mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-15 23:40:29 +02:00
Merge remote-tracking branch 'upstream2/master' into cwcheat
Conflicts: UI/CwCheatScreen.cpp
This commit is contained in:
commit
ddc8ab967f
202 files changed
+5287
-3051
No files matched your search
+3
-3
@@ -148,8 +148,6 @@ if(NOT MSVC)
|
||||
add_definitions(-fno-strict-aliasing)
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -parallel -fopenmp")
|
||||
else()
|
||||
add_definitions(-ffast-math)
|
||||
endif()
|
||||
if(NOT APPLE)
|
||||
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
||||
@@ -163,7 +161,7 @@ if(NOT MSVC)
|
||||
endif()
|
||||
|
||||
if(BLACKBERRY)
|
||||
add_definitions(-D_QNX_SOURCE=1 -D_C99=1 -O3 -mfpu=neon -mtune=cortex-a9)
|
||||
add_definitions(-D_QNX_SOURCE -O3 -mfpu=neon -mtune=cortex-a9)
|
||||
endif()
|
||||
|
||||
if(X86 AND NOT MIPS)
|
||||
@@ -563,6 +561,8 @@ add_library(native STATIC
|
||||
native/gfx/texture_gen.h
|
||||
native/gfx_es2/draw_buffer.cpp
|
||||
native/gfx_es2/draw_buffer.h
|
||||
native/gfx_es2/draw_text.cpp
|
||||
native/gfx_es2/draw_text.h
|
||||
native/gfx_es2/fbo.cpp
|
||||
native/gfx_es2/fbo.h
|
||||
native/gfx_es2/gl_state.cpp
|
||||
|
||||
+19
-1
@@ -15,7 +15,14 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
#include "base/logging.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
||||
@@ -39,6 +46,17 @@
|
||||
#elif !defined(MIPS)
|
||||
void __cpuid(int regs[4], int cpuid_leaf)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
// Use the /dev/cpu/%i/cpuid interface
|
||||
int f = open("/dev/cpu/0/cpuid", O_RDONLY);
|
||||
if (f) {
|
||||
lseek(f, (uint32_t)cpuid_leaf, SEEK_SET);
|
||||
read(f, (void *)regs, 16);
|
||||
close(f);
|
||||
} else {
|
||||
ELOG("CPUID %08x failed!", cpuid_leaf);
|
||||
}
|
||||
#else
|
||||
int eax, ebx, ecx, edx;
|
||||
asm volatile (
|
||||
#if defined(__i386__)
|
||||
@@ -60,11 +78,11 @@ void __cpuid(int regs[4], int cpuid_leaf)
|
||||
"%ebx",
|
||||
#endif
|
||||
"%ecx", "%edx");
|
||||
|
||||
regs[0] = eax;
|
||||
regs[1] = ebx;
|
||||
regs[2] = ecx;
|
||||
regs[3] = edx;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+6
-6
@@ -246,7 +246,7 @@ public:
|
||||
x.clear();
|
||||
while (number > 0)
|
||||
{
|
||||
K first;
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
@@ -283,7 +283,7 @@ public:
|
||||
template<class T>
|
||||
void Do(std::vector<T> &x)
|
||||
{
|
||||
T dv;
|
||||
T dv = T();
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ public:
|
||||
template<class T>
|
||||
void DoPOD(std::vector<T> &x)
|
||||
{
|
||||
T dv;
|
||||
T dv = T();
|
||||
DoVectorPOD(x, dv);
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ public:
|
||||
template<class T>
|
||||
void Do(std::deque<T> &x)
|
||||
{
|
||||
T dv;
|
||||
T dv = T();
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ public:
|
||||
template<class T>
|
||||
void Do(std::list<T> &x)
|
||||
{
|
||||
T dv;
|
||||
T dv = T();
|
||||
DoList(x, dv);
|
||||
}
|
||||
|
||||
@@ -415,7 +415,7 @@ public:
|
||||
x.clear();
|
||||
while (number-- > 0)
|
||||
{
|
||||
T it;
|
||||
T it = T();
|
||||
Do(it);
|
||||
x.insert(it);
|
||||
}
|
||||
|
||||
@@ -27,22 +27,22 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#endif
|
||||
|
||||
#include "thread/threadutil.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "Common.h"
|
||||
#include "LogManager.h" // Common
|
||||
#include "ConsoleListener.h" // Common
|
||||
@@ -71,6 +72,31 @@ ConsoleListener::~ConsoleListener()
|
||||
Close();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Handle console event
|
||||
bool WINAPI ConsoleHandler(DWORD msgType)
|
||||
{
|
||||
if (msgType == CTRL_C_EVENT)
|
||||
{
|
||||
OutputDebugString(L"Ctrl-C!\n");
|
||||
return TRUE;
|
||||
}
|
||||
else if (msgType == CTRL_CLOSE_EVENT)
|
||||
{
|
||||
OutputDebugString(L"Close console window!\n");
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
Other messages:
|
||||
CTRL_BREAK_EVENT Ctrl-Break pressed
|
||||
CTRL_LOGOFF_EVENT User log off
|
||||
CTRL_SHUTDOWN_EVENT System shutdown
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// 100, 100, "Dolphin Log Console"
|
||||
// Open console window - width and height is the size of console window
|
||||
// Name is the window title
|
||||
@@ -84,12 +110,19 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title
|
||||
AllocConsole();
|
||||
HWND hConWnd = GetConsoleWindow();
|
||||
ShowWindow(hConWnd, SW_SHOWDEFAULT);
|
||||
// disable console close button
|
||||
HMENU hMenu=GetSystemMenu(hConWnd,false);
|
||||
EnableMenuItem(hMenu,SC_CLOSE,MF_GRAYED|MF_BYCOMMAND);
|
||||
// Hide
|
||||
if (Hidden) ShowWindow(hConWnd, SW_HIDE);
|
||||
// Save the window handle that AllocConsole() created
|
||||
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
// Set console handler
|
||||
if(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE)){OutputDebugString(L"Console handler is installed!\n");}
|
||||
// Set the console window title
|
||||
SetConsoleTitle(Title);
|
||||
SetConsoleTitle(ConvertUTF8ToWString(Title).c_str());
|
||||
SetConsoleCP(CP_UTF8);
|
||||
|
||||
// Set letter space
|
||||
LetterSpace(Width, LOG_MAX_DISPLAY_LINES);
|
||||
//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
|
||||
@@ -415,6 +448,7 @@ void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Tex
|
||||
*/
|
||||
DWORD cCharsWritten;
|
||||
WORD Color;
|
||||
static wchar_t tempBuf[2048];
|
||||
|
||||
switch (Level)
|
||||
{
|
||||
@@ -441,12 +475,16 @@ void ConsoleListener::WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Tex
|
||||
{
|
||||
// First 10 chars white
|
||||
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL);
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, NULL, NULL);
|
||||
MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, tempBuf, wlen);
|
||||
WriteConsole(hConsole, tempBuf, 10, &cCharsWritten, NULL);
|
||||
Text += 10;
|
||||
Len -= 10;
|
||||
}
|
||||
SetConsoleTextAttribute(hConsole, Color);
|
||||
WriteConsole(hConsole, Text, (DWORD)Len, &cCharsWritten, NULL);
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, NULL, NULL);
|
||||
MultiByteToWideChar(CP_UTF8, 0, Text, (int)Len, tempBuf, wlen);
|
||||
WriteConsole(hConsole, tempBuf, (DWORD)Len, &cCharsWritten, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -476,7 +514,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
|
||||
|
||||
static const int MAX_BYTES = 1024 * 16;
|
||||
|
||||
std::vector<std::array<CHAR, MAX_BYTES>> Str;
|
||||
std::vector<std::array<wchar_t, MAX_BYTES>> Str;
|
||||
std::vector<std::array<WORD, MAX_BYTES>> Attr;
|
||||
|
||||
// ReadConsoleOutputAttribute seems to have a limit at this level
|
||||
|
||||
+11
-21
@@ -17,6 +17,8 @@
|
||||
#include "CommonWindows.h"
|
||||
#include <stdio.h>
|
||||
#include "ExtendedTrace.h"
|
||||
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include <tchar.h>
|
||||
@@ -320,7 +322,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (ULONG)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
etfprint(file, wstring(L" ") + srcInfo + L" : " + symInfo + L"\n");
|
||||
|
||||
for( ULONG index = 0; ; index++ )
|
||||
{
|
||||
@@ -343,7 +345,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
etfprint(file, wstring(L" ") + srcInfo + L" : " + symInfo + L"\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -351,22 +353,6 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
|
||||
ResumeThread( hThread );
|
||||
}
|
||||
|
||||
#ifndef UNICODE
|
||||
|
||||
void StackTrace( HANDLE hThread, wchar_t const*lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
||||
{
|
||||
// TODO: remove when Common builds as unicode
|
||||
size_t origsize = wcslen(lpszMessage) + 1;
|
||||
const size_t newsize = 100;
|
||||
size_t convertedChars = 0;
|
||||
char nstring[newsize];
|
||||
wcstombs_s(&convertedChars, nstring, origsize, lpszMessage, _TRUNCATE);
|
||||
|
||||
StackTrace(hThread, nstring, file, eip, esp, ebp );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
|
||||
{
|
||||
STACKFRAME callStack;
|
||||
@@ -397,7 +383,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
etfprint(file, wstring(L" ") + srcInfo + L" : " + symInfo + L"\n");
|
||||
|
||||
for( ULONG index = 0; ; index++ )
|
||||
{
|
||||
@@ -420,8 +406,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO
|
||||
|
||||
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
|
||||
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
|
||||
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
|
||||
|
||||
etfprint(file, wstring(L" ") + srcInfo + L" : " + symInfo + L"\n");
|
||||
}
|
||||
|
||||
if ( hThread != GetCurrentThread() )
|
||||
@@ -443,4 +428,9 @@ void etfprint(FILE *file, const std::string &text) {
|
||||
fwrite(text.data(), 1, len, file);
|
||||
}
|
||||
|
||||
void etfprint(FILE *file, const std::wstring &text) {
|
||||
size_t len = text.length();
|
||||
fwrite(text.data(), sizeof(wchar_t), len, file);
|
||||
}
|
||||
|
||||
#endif //WIN32
|
||||
@@ -39,6 +39,7 @@ void StackTrace( HANDLE hThread, wchar_t const* lpszMessage, FILE *file, DWORD e
|
||||
// functions by Masken
|
||||
void etfprintf(FILE *file, const char *format, ...);
|
||||
void etfprint(FILE *file, const std::string &text);
|
||||
void etfprint(FILE *file, const std::wstring &text);
|
||||
#define UEFBUFSIZE 2048
|
||||
extern char g_uefbuf[UEFBUFSIZE];
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "FileSearch.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
|
||||
CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, const CFileSearch::XStringVector& _rDirectories)
|
||||
@@ -53,7 +54,8 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
|
||||
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATA findData;
|
||||
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
|
||||
std::wstring searchPathW = ConvertUTF8ToWString(GCMSearchPath);
|
||||
HANDLE FindFirst = FindFirstFile(searchPathW.c_str(), &findData);
|
||||
|
||||
if (FindFirst != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@@ -64,7 +66,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
|
||||
if (findData.cFileName[0] != '.')
|
||||
{
|
||||
std::string strFilename;
|
||||
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
|
||||
BuildCompleteFilename(strFilename, _strPath, ConvertWStringToUTF8(findData.cFileName));
|
||||
m_FileNames.push_back(strFilename);
|
||||
}
|
||||
|
||||
|
||||
+56
-88
@@ -41,6 +41,8 @@
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#endif
|
||||
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -77,6 +79,15 @@ static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **res
|
||||
namespace File
|
||||
{
|
||||
|
||||
FILE *OpenCFile(const std::string &filename, const char *mode)
|
||||
{
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
return _wfopen(ConvertUTF8ToWString(filename).c_str(), ConvertUTF8ToWString(mode).c_str());
|
||||
#else
|
||||
return fopen(filename.c_str(), mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
static void StripTailDirSlashes(std::string &fname)
|
||||
@@ -94,16 +105,39 @@ static void StripTailDirSlashes(std::string &fname)
|
||||
return;
|
||||
}
|
||||
|
||||
// _WIN32 only since std::strings are used everywhere else.
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
static void StripTailDirSlashes(std::wstring &fname)
|
||||
{
|
||||
if (fname.length() > 1)
|
||||
{
|
||||
size_t i = fname.length() - 1;
|
||||
|
||||
if (i == 2 && fname[1] == ':' && fname[2] == '\\')
|
||||
return;
|
||||
|
||||
while (wcschr(_T(DIR_SEP_CHRS), fname[i]))
|
||||
fname[i--] = '\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename)
|
||||
{
|
||||
struct stat64 file_info;
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
std::wstring copy = ConvertUTF8ToWString(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = _wstat64(copy.c_str(), &file_info);
|
||||
#else
|
||||
std::string copy(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = stat64(copy.c_str(), &file_info);
|
||||
|
||||
#endif
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
@@ -117,12 +151,17 @@ bool IsDirectory(const struct stat64 &file_info)
|
||||
bool IsDirectory(const std::string &filename)
|
||||
{
|
||||
struct stat64 file_info;
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
std::wstring copy = ConvertUTF8ToWString(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = _wstat64(copy.c_str(), &file_info);
|
||||
#else
|
||||
std::string copy(filename);
|
||||
StripTailDirSlashes(copy);
|
||||
|
||||
int result = stat64(copy.c_str(), &file_info);
|
||||
|
||||
#endif
|
||||
if (result < 0) {
|
||||
WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
@@ -154,7 +193,7 @@ bool Delete(const std::string &filename)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!DeleteFile(filename.c_str()))
|
||||
if (!DeleteFile(ConvertUTF8ToWString(filename).c_str()))
|
||||
{
|
||||
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
@@ -176,7 +215,7 @@ bool CreateDir(const std::string &path)
|
||||
{
|
||||
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
|
||||
#ifdef _WIN32
|
||||
if (::CreateDirectory(path.c_str(), NULL))
|
||||
if (::CreateDirectory(ConvertUTF8ToWString(path).c_str(), NULL))
|
||||
return true;
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS)
|
||||
@@ -267,7 +306,7 @@ bool DeleteDir(const std::string &filename)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (::RemoveDirectory(filename.c_str()))
|
||||
if (::RemoveDirectory(ConvertUTF8ToWString(filename).c_str()))
|
||||
return true;
|
||||
#else
|
||||
if (rmdir(filename.c_str()) == 0)
|
||||
@@ -296,7 +335,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
INFO_LOG(COMMON, "Copy: %s --> %s",
|
||||
srcFilename.c_str(), destFilename.c_str());
|
||||
#ifdef _WIN32
|
||||
if (CopyFile(srcFilename.c_str(), destFilename.c_str(), FALSE))
|
||||
if (CopyFile(ConvertUTF8ToWString(srcFilename).c_str(), ConvertUTF8ToWString(destFilename).c_str(), FALSE))
|
||||
return true;
|
||||
|
||||
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
|
||||
@@ -397,8 +436,11 @@ tm GetModifTime(const std::string &filename)
|
||||
u64 GetSize(const std::string &filename)
|
||||
{
|
||||
struct stat64 file_info;
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
int result = _wstat64(ConvertUTF8ToWString(filename).c_str(), &file_info);
|
||||
#else
|
||||
int result = stat64(filename.c_str(), &file_info);
|
||||
#endif
|
||||
if (result != 0)
|
||||
{
|
||||
WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str());
|
||||
@@ -451,7 +493,7 @@ bool CreateEmptyFile(const std::string &filename)
|
||||
{
|
||||
INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
|
||||
|
||||
FILE *pFile = fopen(filename.c_str(), "wb");
|
||||
FILE *pFile = OpenCFile(filename, "wb");
|
||||
if (!pFile) {
|
||||
ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
@@ -461,80 +503,6 @@ bool CreateEmptyFile(const std::string &filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Scans the directory tree gets, starting from _Directory and adds the
|
||||
// results into parentEntry. Returns the number of files+directories found
|
||||
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
|
||||
{
|
||||
INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
|
||||
// How many files + directories we found
|
||||
u32 foundEntries = 0;
|
||||
#ifdef _WIN32
|
||||
// Find the first file in the directory.
|
||||
WIN32_FIND_DATA ffd;
|
||||
|
||||
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(hFind);
|
||||
return foundEntries;
|
||||
}
|
||||
// windows loop
|
||||
do
|
||||
{
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(ffd.cFileName);
|
||||
#else
|
||||
struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
|
||||
struct dirent_large diren;
|
||||
struct dirent *result = NULL;
|
||||
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return 0;
|
||||
|
||||
// non windows loop
|
||||
while (!readdir_r(dirp, (dirent*)&diren, &result) && result)
|
||||
{
|
||||
FSTEntry entry;
|
||||
const std::string virtualName(result->d_name);
|
||||
#endif
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
continue;
|
||||
entry.virtualName = virtualName;
|
||||
entry.physicalName = directory;
|
||||
entry.physicalName += DIR_SEP + entry.virtualName;
|
||||
|
||||
if (IsDirectory(entry.physicalName.c_str()))
|
||||
{
|
||||
entry.isDirectory = true;
|
||||
// is a directory, lets go inside
|
||||
entry.size = ScanDirectoryTree(entry.physicalName, entry);
|
||||
foundEntries += (u32)entry.size;
|
||||
}
|
||||
else
|
||||
{ // is a file
|
||||
entry.isDirectory = false;
|
||||
entry.size = GetSize(entry.physicalName.c_str());
|
||||
}
|
||||
++foundEntries;
|
||||
// Push into the tree
|
||||
parentEntry.children.push_back(entry);
|
||||
#ifdef _WIN32
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
FindClose(hFind);
|
||||
#else
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
// Return number of entries found.
|
||||
return foundEntries;
|
||||
}
|
||||
|
||||
|
||||
// Deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string &directory)
|
||||
{
|
||||
@@ -542,7 +510,7 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
#ifdef _WIN32
|
||||
// Find the first file in the directory.
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
|
||||
HANDLE hFind = FindFirstFile(ConvertUTF8ToWString(directory + "\\*").c_str(), &ffd);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@@ -553,7 +521,7 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
// windows loop
|
||||
do
|
||||
{
|
||||
const std::string virtualName = ffd.cFileName;
|
||||
const std::string virtualName = ConvertWStringToUTF8(ffd.cFileName);
|
||||
#else
|
||||
struct dirent dirent, *result = NULL;
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
@@ -751,7 +719,7 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
|
||||
bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, text_file ? "w" : "wb");
|
||||
FILE *f = OpenCFile(filename, text_file ? "w" : "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
size_t len = str.size();
|
||||
@@ -766,7 +734,7 @@ bool WriteStringToFile(bool text_file, const std::string &str, const char *filen
|
||||
|
||||
bool ReadFileToString(bool text_file, const char *filename, std::string &str)
|
||||
{
|
||||
FILE *f = fopen(filename, text_file ? "r" : "rb");
|
||||
FILE *f = OpenCFile(filename, text_file ? "r" : "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
size_t len = (size_t)GetSize(f);
|
||||
@@ -800,8 +768,8 @@ IOFile::~IOFile()
|
||||
bool IOFile::Open(const std::string& filename, const char openmode[])
|
||||
{
|
||||
Close();
|
||||
#ifdef _WIN32
|
||||
fopen_s(&m_file, filename.c_str(), openmode);
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
_wfopen_s(&m_file, ConvertUTF8ToWString(filename).c_str(), ConvertUTF8ToWString(openmode).c_str());
|
||||
#else
|
||||
m_file = fopen(filename.c_str(), openmode);
|
||||
#endif
|
||||
|
||||
+3
-4
@@ -59,6 +59,9 @@ struct FSTEntry
|
||||
std::vector<FSTEntry> children;
|
||||
};
|
||||
|
||||
// Mostly to handle utf-8 filenames better on Windows.
|
||||
FILE *OpenCFile(const std::string &filename, const char *mode);
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename);
|
||||
|
||||
@@ -99,10 +102,6 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename);
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string &filename);
|
||||
|
||||
// Scans the directory tree gets, starting from _Directory and adds the
|
||||
// results into parentEntry. Returns the number of files+directories found
|
||||
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry);
|
||||
|
||||
// deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string &directory);
|
||||
|
||||
|
||||
+3
-3
@@ -245,10 +245,10 @@ void UpdateConfirmCancelKeys() {
|
||||
cancelKeys.push_back(hardcodedCancelKeys[i]);
|
||||
}
|
||||
|
||||
SetConfirmCancelKeys(confirmKeys,cancelKeys);
|
||||
SetConfirmCancelKeys(confirmKeys, cancelKeys);
|
||||
}
|
||||
|
||||
static void SetDefaultKeyMap(int deviceId, const DefMappingStruct *array, int count, bool replace) {
|
||||
static void SetDefaultKeyMap(int deviceId, const DefMappingStruct *array, size_t count, bool replace) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (array[i].direction == 0)
|
||||
SetKeyMapping(array[i].pspKey, KeyDef(deviceId, array[i].key), replace);
|
||||
@@ -679,7 +679,7 @@ void RestoreDefault() {
|
||||
std::string name = System_GetName();
|
||||
if (name == "NVIDIA:SHIELD") {
|
||||
SetDefaultKeyMap(DEFAULT_MAPPING_SHIELD, true);
|
||||
} else if (name == "OUYA:OUYA") { // TODO: check!
|
||||
} else if (name == "OUYA:OUYA Console") { // TODO: check!
|
||||
SetDefaultKeyMap(DEFAULT_MAPPING_OUYA, true);
|
||||
} else if (name == "Sony Ericsson:R800i" || name == "Sony Ericsson:zeus") {
|
||||
SetDefaultKeyMap(DEFAULT_MAPPING_XPERIA_PLAY, true);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "LogManager.h"
|
||||
#include "ConsoleListener.h"
|
||||
#include "Timer.h"
|
||||
@@ -280,6 +280,6 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
{
|
||||
#if _MSC_VER
|
||||
::OutputDebugStringA(msg);
|
||||
OutputDebugStringUTF8(msg);
|
||||
#endif
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ const char* GetLastErrorMsg()
|
||||
#ifdef _WIN32
|
||||
static __declspec(thread) char err_str[buff_size] = {};
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
err_str, buff_size, NULL);
|
||||
#else
|
||||
|
||||
+12
-8
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Common.h" // Local
|
||||
#include "StringUtils.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style);
|
||||
static MsgAlertHandler msg_handler = DefaultMsgHandler;
|
||||
@@ -106,15 +107,18 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
|
||||
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int STYLE = MB_ICONINFORMATION;
|
||||
if (Style == QUESTION) STYLE = MB_ICONQUESTION;
|
||||
if (Style == WARNING) STYLE = MB_ICONWARNING;
|
||||
|
||||
return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK));
|
||||
|
||||
int STYLE = MB_ICONINFORMATION;
|
||||
if (Style == QUESTION) STYLE = MB_ICONQUESTION;
|
||||
if (Style == WARNING) STYLE = MB_ICONWARNING;
|
||||
|
||||
std::wstring wtext = ConvertUTF8ToWString(text);
|
||||
std::wstring wcaption = ConvertUTF8ToWString(caption);
|
||||
|
||||
return IDYES == MessageBox(0, wtext.c_str(), wcaption.c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK));
|
||||
|
||||
#else
|
||||
printf("%s\n", text);
|
||||
return true;
|
||||
printf("%s\n", text);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+36
-13
@@ -48,29 +48,22 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
|
||||
IniFile::Section *general = iniFile.GetOrCreateSection("General");
|
||||
|
||||
bSpeedLimit = false;
|
||||
general->Get("FirstRun", &bFirstRun, true);
|
||||
general->Get("Enable Logging", &bEnableLogging, true);
|
||||
general->Get("AutoLoadLast", &bAutoLoadLast, false);
|
||||
general->Get("AutoRun", &bAutoRun, true);
|
||||
general->Get("Browse", &bBrowse, false);
|
||||
general->Get("ConfirmOnQuit", &bConfirmOnQuit, false);
|
||||
general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true);
|
||||
general->Get("CurrentDirectory", ¤tDirectory, "");
|
||||
general->Get("ShowDebuggerOnLoad", &bShowDebuggerOnLoad, false);
|
||||
general->Get("Language", &languageIni, "en_US");
|
||||
general->Get("NumWorkerThreads", &iNumWorkerThreads, cpu_info.num_cores);
|
||||
general->Get("EnableCheats", &bEnableCheats, false);
|
||||
general->Get("MaxRecent", &iMaxRecent, 30);
|
||||
general->Get("ScreenshotsAsPNG", &bScreenshotsAsPNG, false);
|
||||
general->Get("StateSlot", &iCurrentStateSlot, 0);
|
||||
general->Get("GridView1", &bGridView1, true);
|
||||
general->Get("GridView2", &bGridView2, true);
|
||||
general->Get("GridView3", &bGridView3, true);
|
||||
|
||||
// Fix issue from switching from uint (hex in .ini) to int (dec)
|
||||
if (iMaxRecent == 0)
|
||||
iMaxRecent = 12;
|
||||
|
||||
// "default" means let emulator decide, "" means disable.
|
||||
general->Get("ReportingHost", &sReportHost, "default");
|
||||
@@ -82,8 +75,23 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
|
||||
general->Get("WindowY", &iWindowY, 100);
|
||||
#endif
|
||||
|
||||
if ((int)recentIsos.size() > iMaxRecent)
|
||||
recentIsos.resize(iMaxRecent);
|
||||
IniFile::Section *recent = iniFile.GetOrCreateSection("Recent");
|
||||
recent->Get("MaxRecent", &iMaxRecent, 30);
|
||||
|
||||
// Fix issue from switching from uint (hex in .ini) to int (dec)
|
||||
if (iMaxRecent == 0)
|
||||
iMaxRecent = 30;
|
||||
|
||||
recentIsos.clear();
|
||||
for (int i = 0; i < iMaxRecent; i++)
|
||||
{
|
||||
char keyName[64];
|
||||
std::string fileName;
|
||||
|
||||
sprintf(keyName,"FileName%d",i);
|
||||
if (!recent->Get(keyName,&fileName,"") || fileName.length() == 0) break;
|
||||
recentIsos.push_back(fileName);
|
||||
}
|
||||
|
||||
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
|
||||
#ifdef IOS
|
||||
@@ -231,15 +239,12 @@ void Config::Save() {
|
||||
bFirstRun = false;
|
||||
general->Set("FirstRun", bFirstRun);
|
||||
general->Set("Enable Logging", bEnableLogging);
|
||||
general->Set("AutoLoadLast", bAutoLoadLast);
|
||||
general->Set("AutoRun", bAutoRun);
|
||||
general->Set("Browse", bBrowse);
|
||||
general->Set("ConfirmOnQuit", bConfirmOnQuit);
|
||||
general->Set("IgnoreBadMemAccess", bIgnoreBadMemAccess);
|
||||
general->Set("CurrentDirectory", currentDirectory);
|
||||
general->Set("ShowDebuggerOnLoad", bShowDebuggerOnLoad);
|
||||
general->Set("ReportingHost", sReportHost);
|
||||
general->Set("Recent", recentIsos);
|
||||
general->Set("AutoSaveSymbolMap", bAutoSaveSymbolMap);
|
||||
#ifdef _WIN32
|
||||
general->Set("TopMost", bTopMost);
|
||||
@@ -248,13 +253,23 @@ void Config::Save() {
|
||||
#endif
|
||||
general->Set("Language", languageIni);
|
||||
general->Set("NumWorkerThreads", iNumWorkerThreads);
|
||||
general->Set("MaxRecent", iMaxRecent);
|
||||
general->Set("EnableCheats", bEnableCheats);
|
||||
general->Set("ScreenshotsAsPNG", bScreenshotsAsPNG);
|
||||
general->Set("StateSlot", iCurrentStateSlot);
|
||||
general->Set("GridView1", bGridView1);
|
||||
general->Set("GridView2", bGridView2);
|
||||
general->Set("GridView3", bGridView3);
|
||||
|
||||
IniFile::Section *recent = iniFile.GetOrCreateSection("Recent");
|
||||
recent->Set("MaxRecent", iMaxRecent);
|
||||
|
||||
for (int i = 0; i < (int)recentIsos.size(); i++)
|
||||
{
|
||||
char keyName[64];
|
||||
|
||||
sprintf(keyName,"FileName%d",i);
|
||||
recent->Set(keyName,recentIsos[i]);
|
||||
}
|
||||
|
||||
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
|
||||
cpu->Set("Jit", bJit);
|
||||
@@ -378,3 +393,11 @@ void Config::CleanRecent() {
|
||||
}
|
||||
recentIsos = cleanedRecent;
|
||||
}
|
||||
|
||||
void Config::RestoreDefaults() {
|
||||
if(File::Exists("ppsspp.ini"))
|
||||
File::Delete("ppsspp.ini");
|
||||
recentIsos.clear();
|
||||
currentDirectory = "";
|
||||
Load();
|
||||
}
|
||||
+7
-9
@@ -34,21 +34,18 @@ public:
|
||||
bool bSaveSettings;
|
||||
bool bFirstRun;
|
||||
|
||||
// These are broken
|
||||
bool bAutoLoadLast;
|
||||
bool bSpeedLimit;
|
||||
bool bConfirmOnQuit;
|
||||
bool bAutoRun; // start immediately
|
||||
bool bBrowse;
|
||||
#ifdef _WIN32
|
||||
bool bTopMost;
|
||||
#endif
|
||||
bool bBrowse; // when opening the emulator, immediately show a file browser
|
||||
|
||||
|
||||
// General
|
||||
int iNumWorkerThreads;
|
||||
bool bScreenshotsAsPNG;
|
||||
bool bEnableLogging;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool bTopMost;
|
||||
std::string sFont;
|
||||
#endif
|
||||
// Core
|
||||
bool bIgnoreBadMemAccess;
|
||||
bool bFastMemory;
|
||||
@@ -169,6 +166,7 @@ public:
|
||||
|
||||
void Load(const char *iniFileName = "ppsspp.ini", const char *controllerIniFilename = "controls.ini");
|
||||
void Save();
|
||||
void RestoreDefaults();
|
||||
|
||||
// Utility functions for "recent" management
|
||||
void AddRecent(const std::string &file);
|
||||
|
||||
+64
-4
@@ -26,24 +26,24 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -323,6 +323,54 @@
|
||||
<ClCompile Include="MIPS\MIPSIntVFPU.cpp" />
|
||||
<ClCompile Include="Mips\MIPSTables.cpp" />
|
||||
<ClCompile Include="MIPS\MIPSVFPUUtils.cpp" />
|
||||
<ClCompile Include="MIPS\PPC\PpcAsm.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompAlu.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompBranch.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompFpu.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompLoadStore.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompVFPU.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcJit.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcRegCache.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\x86\Asm.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompALU.cpp" />
|
||||
<ClCompile Include="MIPS\x86\CompBranch.cpp" />
|
||||
@@ -481,6 +529,18 @@
|
||||
<ClInclude Include="MIPS\MIPSIntVFPU.h" />
|
||||
<ClInclude Include="Mips\MIPSTables.h" />
|
||||
<ClInclude Include="MIPS\MIPSVFPUUtils.h" />
|
||||
<ClInclude Include="MIPS\PPC\PpcJit.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MIPS\PPC\PpcRegCache.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MIPS\x86\Asm.h" />
|
||||
<ClInclude Include="MIPS\x86\RegCacheFPU.h" />
|
||||
<ClInclude Include="MIPS\x86\Jit.h" />
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
<Filter Include="Font">
|
||||
<UniqueIdentifier>{1c79e88d-1c48-450b-8af6-f22ce7d40c66}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="MIPS\PPC">
|
||||
<UniqueIdentifier>{ac0e396a-6e16-4796-a0a0-b8ebf46ea74c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ELF\ElfReader.cpp">
|
||||
@@ -460,6 +463,30 @@
|
||||
<ClCompile Include="..\ext\xxhash.c">
|
||||
<Filter>Ext</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompLoadStore.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompVFPU.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcJit.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcRegCache.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompAlu.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompBranch.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcCompFpu.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\PPC\PpcAsm.cpp">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@@ -858,6 +885,12 @@
|
||||
<ClInclude Include="..\ext\xxhash.h">
|
||||
<Filter>Ext</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MIPS\PPC\PpcJit.h">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MIPS\PPC\PpcRegCache.h">
|
||||
<Filter>MIPS\PPC</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
||||
@@ -298,8 +298,9 @@ void CBreakPoints::Update(u32 addr)
|
||||
{
|
||||
if (MIPSComp::jit && Core_IsInactive())
|
||||
{
|
||||
// In case this is a delay slot, clear the previous instruction too.
|
||||
if (addr != 0)
|
||||
MIPSComp::jit->ClearCacheAt(addr);
|
||||
MIPSComp::jit->ClearCacheAt(addr - 4, 8);
|
||||
else
|
||||
MIPSComp::jit->ClearCache();
|
||||
}
|
||||
|
||||
@@ -21,13 +21,17 @@
|
||||
#include "DebugInterface.h"
|
||||
#include <vector>
|
||||
|
||||
// TODO: Replace with expression or something.
|
||||
struct BreakPointCond
|
||||
{
|
||||
DebugInterface* debug;
|
||||
DebugInterface *debug;
|
||||
PostfixExpression expression;
|
||||
char expressionString[128];
|
||||
|
||||
BreakPointCond() : debug(NULL)
|
||||
{
|
||||
expressionString[0] = '\0';
|
||||
}
|
||||
|
||||
u32 Evaluate()
|
||||
{
|
||||
u32 result;
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
virtual const char *getDescription(unsigned int address) {return "";}
|
||||
virtual const char *findSymbolForAddress(unsigned int address) { return NULL; };
|
||||
virtual bool getSymbolValue(char* symbol, u32& dest) { return false; };
|
||||
virtual bool initExpression(char* exp, PostfixExpression& dest) { return false; };
|
||||
virtual bool initExpression(const char* exp, PostfixExpression& dest) { return false; };
|
||||
virtual bool parseExpression(PostfixExpression& exp, u32& dest) { return false; };
|
||||
|
||||
|
||||
|
||||
+27
-26
@@ -23,13 +23,13 @@
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "../../Core/MemMap.h"
|
||||
#include "SymbolMap.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Globals.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
|
||||
SymbolMap symbolMap;
|
||||
|
||||
//need improvement
|
||||
@@ -46,7 +46,7 @@ static u32 ComputeHash(u32 start, u32 size)
|
||||
{
|
||||
u32 hash=0;
|
||||
for (unsigned int i=start; i<start+size; i+=4)
|
||||
hash = hasher(hash, Memory::Read_Instruction(i));
|
||||
hash = hasher(hash, Memory::Read_Instruction(i).encoding);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ bool SymbolMap::LoadSymbolMap(const char *filename)
|
||||
{
|
||||
lock_guard guard(lock_);
|
||||
SymbolMap::ResetSymbolMap();
|
||||
FILE *f = fopen(filename,"r");
|
||||
FILE *f = File::OpenCFile(filename, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
//char temp[256];
|
||||
@@ -212,7 +212,7 @@ bool SymbolMap::LoadSymbolMap(const char *filename)
|
||||
void SymbolMap::SaveSymbolMap(const char *filename) const
|
||||
{
|
||||
lock_guard guard(lock_);
|
||||
FILE *f = fopen(filename,"w");
|
||||
FILE *f = File::OpenCFile(filename, "w");
|
||||
if (!f)
|
||||
return;
|
||||
fprintf(f,".text\n");
|
||||
@@ -227,7 +227,7 @@ void SymbolMap::SaveSymbolMap(const char *filename) const
|
||||
bool SymbolMap::LoadNocashSym(const char *filename)
|
||||
{
|
||||
lock_guard guard(lock_);
|
||||
FILE *f = fopen(filename,"r");
|
||||
FILE *f = File::OpenCFile(filename, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
@@ -336,7 +336,7 @@ bool SymbolMap::getSymbolValue(char* symbol, u32& dest)
|
||||
{
|
||||
const MapEntry &entry = *it;
|
||||
#ifdef _WIN32
|
||||
if (stricmp(entry.name,symbol) == 0)
|
||||
if (_stricmp(entry.name,symbol) == 0)
|
||||
#else
|
||||
if (strcasecmp(entry.name,symbol) == 0)
|
||||
#endif
|
||||
@@ -388,8 +388,8 @@ void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symmask) const
|
||||
{
|
||||
for (int i = 0; i < defaultSymbolsAmount; i++)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp,"0x%08X (%s)",defaultSymbolsAddresses[i],defaultSymbolsNames[i]);
|
||||
wchar_t temp[256];
|
||||
wsprintf(temp, L"0x%08X (%S)", defaultSymbolsAddresses[i], defaultSymbolsNames[i]);
|
||||
int index = ListBox_AddString(listbox,temp);
|
||||
ListBox_SetItemData(listbox,index,defaultSymbolsAddresses[i]);
|
||||
}
|
||||
@@ -404,12 +404,12 @@ void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symmask) const
|
||||
const MapEntry &entry = *it;
|
||||
if (entry.type & symmask)
|
||||
{
|
||||
char temp[256];
|
||||
wchar_t temp[256];
|
||||
if (entry.type & ST_FUNCTION || !(entry.type & ST_DATA))
|
||||
{
|
||||
sprintf(temp,"%s",entry.name);
|
||||
wsprintf(temp, L"%S", entry.name);
|
||||
} else {
|
||||
sprintf(temp,"0x%08X (%s)",entry.vaddress,entry.name);
|
||||
wsprintf(temp, L"0x%08X (%S)", entry.vaddress, entry.name);
|
||||
}
|
||||
|
||||
int index = ListBox_AddString(listbox,temp);
|
||||
@@ -429,23 +429,23 @@ void SymbolMap::FillSymbolComboBox(HWND listbox,SymbolType symmask) const
|
||||
|
||||
//int style = GetWindowLong(listbox,GWL_STYLE);
|
||||
|
||||
ComboBox_AddString(listbox,"(0x02000000)");
|
||||
ComboBox_SetItemData(listbox,0,0x02000000);
|
||||
ComboBox_AddString(listbox, L"(0x02000000)");
|
||||
ComboBox_SetItemData(listbox, 0, 0x02000000);
|
||||
|
||||
//ListBox_AddString(listbox,"(0x80002000)");
|
||||
//ListBox_SetItemData(listbox,1,0x80002000);
|
||||
//ListBox_AddString(listbox, L"(0x80002000)");
|
||||
//ListBox_SetItemData(listbox, 1, 0x80002000);
|
||||
|
||||
lock_guard guard(lock_);
|
||||
|
||||
SendMessage(listbox, WM_SETREDRAW, FALSE, 0);
|
||||
SendMessage(listbox, CB_INITSTORAGE, (WPARAM)entries.size(), (LPARAM)entries.size() * 30);
|
||||
SendMessage(listbox, CB_INITSTORAGE, (WPARAM)entries.size(), (LPARAM)entries.size() * 30 * sizeof(wchar_t));
|
||||
for (size_t i = 0, end = entries.size(); i < end; ++i)
|
||||
{
|
||||
const MapEntry &entry = entries[i];
|
||||
if (entry.type & symmask)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp,"%s (%d)",entry.name,entry.size);
|
||||
wchar_t temp[256];
|
||||
wsprintf(temp, L"%S (%d)", entry.name, entry.size);
|
||||
int index = ComboBox_AddString(listbox,temp);
|
||||
ComboBox_SetItemData(listbox,index,entry.vaddress);
|
||||
}
|
||||
@@ -469,6 +469,7 @@ void SymbolMap::FillListBoxBLinks(HWND listbox, int num) const
|
||||
for (int i=0; i<e.backwardLinks.size(); i++)
|
||||
{
|
||||
u32 addr = e.backwardLinks[i];
|
||||
// TODO: wchar_t
|
||||
int index = ListBox_AddString(listbox,SymbolMap::GetSymbolName(SymbolMap::GetSymbolNum(addr)));
|
||||
ListBox_SetItemData(listbox,index,addr);
|
||||
}
|
||||
@@ -537,7 +538,7 @@ unsigned int SymbolMap::GetRunCount(int num) const
|
||||
void SymbolMap::CompileFuncSignaturesFile(const char *filename) const
|
||||
{
|
||||
// Store name,length,first instruction,hash into file
|
||||
FILE *f = fopen(filename, "w");
|
||||
FILE *f = File::OpenCFile(filename, "w");
|
||||
fprintf(f,"00000000\n");
|
||||
int count=0;
|
||||
for (auto it = entries.begin(), end = entries.end(); it != end; ++it)
|
||||
@@ -546,7 +547,7 @@ void SymbolMap::CompileFuncSignaturesFile(const char *filename) const
|
||||
int size = entry.size;
|
||||
if (size >= 16 && entry.type == ST_FUNCTION)
|
||||
{
|
||||
u32 inst = Memory::Read_Instruction(entry.vaddress); //try to make a bigger number of different vals sometime
|
||||
u32 inst = Memory::Read_Instruction(entry.vaddress).encoding; //try to make a bigger number of different vals sometime
|
||||
if (inst != 0)
|
||||
{
|
||||
char temp[64];
|
||||
@@ -588,7 +589,7 @@ void SymbolMap::UseFuncSignaturesFile(const char *filename, u32 maxAddress)
|
||||
sigs.clear();
|
||||
//SymbolMap::ResetSymbolMap();
|
||||
//#1: Read the signature file and put them in a fast data structure
|
||||
FILE *f = fopen(filename, "r");
|
||||
FILE *f = File::OpenCFile(filename, "r");
|
||||
int count;
|
||||
if (fscanf(f, "%08x\n", &count) != 1)
|
||||
count = 0;
|
||||
@@ -633,7 +634,7 @@ void SymbolMap::UseFuncSignaturesFile(const char *filename, u32 maxAddress)
|
||||
sprintf(temp,"Scanning: %08x",addr);
|
||||
lastAddr=addr;
|
||||
}
|
||||
u32 inst = Memory::Read_Instruction(addr);
|
||||
u32 inst = Memory::Read_Instruction(addr).encoding;
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -160,6 +160,32 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer<u16_
|
||||
_string = stringBuffer;
|
||||
}
|
||||
|
||||
void GetWideStringFromPSPPointer(std::wstring& _string, const PSPPointer<u16_le> em_address)
|
||||
{
|
||||
if (!em_address.IsValid())
|
||||
{
|
||||
_string = L"";
|
||||
return;
|
||||
}
|
||||
const size_t maxLength = 2048;
|
||||
|
||||
wchar_t stringBuffer[maxLength];
|
||||
wchar_t *string = stringBuffer;
|
||||
|
||||
auto input = em_address;
|
||||
int c;
|
||||
u32 count = 0;
|
||||
while ((c = *input++) != 0)
|
||||
{
|
||||
if ( !(++count >= maxLength) )
|
||||
*string++ = c;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*string++ = '\0';
|
||||
_string = stringBuffer;
|
||||
}
|
||||
|
||||
void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const wchar_t *input)
|
||||
{
|
||||
char stringBuffer[2048];
|
||||
@@ -600,7 +626,7 @@ void PSPOskDialog::RemoveKorean()
|
||||
else
|
||||
{
|
||||
i_level = 1;
|
||||
inputChars += kor_cons[i_value[0]];;
|
||||
inputChars += kor_cons[i_value[0]];
|
||||
}
|
||||
}
|
||||
else if(i_level == 3)
|
||||
@@ -739,10 +765,9 @@ void PSPOskDialog::RenderKeyboard()
|
||||
#ifdef _WIN32
|
||||
// TODO: Why does this have a 2 button press lag/delay when
|
||||
// re-opening the dialog box? I don't get it.
|
||||
// TODO: Use a wstring to allow Japanese/Russian/etc.. on _WIN32(others?)
|
||||
int PSPOskDialog::NativeKeyboard()
|
||||
{
|
||||
char *input = new char[FieldMaxLength()];
|
||||
wchar_t *input = new wchar_t[FieldMaxLength()];
|
||||
memset(input, 0, sizeof(input));
|
||||
|
||||
if (status == SCE_UTILITY_STATUS_INITIALIZE)
|
||||
@@ -752,37 +777,35 @@ int PSPOskDialog::NativeKeyboard()
|
||||
|
||||
else if (status == SCE_UTILITY_STATUS_RUNNING)
|
||||
{
|
||||
|
||||
std::string initial_text;
|
||||
ConvertUCS2ToUTF8(initial_text, oskParams->fields[0].intext);
|
||||
std::wstring titleText;
|
||||
GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc);
|
||||
|
||||
const size_t defaultText_len = 512;
|
||||
char defaultText[defaultText_len];
|
||||
std::wstring defaultText;
|
||||
GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext);
|
||||
|
||||
memset(defaultText, 0, sizeof(defaultText));
|
||||
if(defaultText.length() <= 0)
|
||||
defaultText.assign(L"VALUE");
|
||||
|
||||
if(initial_text.length() < defaultText_len)
|
||||
strncat(defaultText, initial_text.c_str(), strlen(initial_text.c_str()));
|
||||
else {
|
||||
ERROR_LOG(HLE, "NativeKeyboard: initial text length is too long");
|
||||
strncat(defaultText, "VALUE", strlen("VALUE"));
|
||||
std::wstring inputWide;
|
||||
|
||||
if(!host->InputBoxGetWString(titleText.c_str(), defaultText, inputWide))
|
||||
{
|
||||
wcsncat(input, L"", wcslen(L""));
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t maxInputLength = FieldMaxLength();
|
||||
|
||||
char windowTitle[defaultText_len];
|
||||
memset(windowTitle, 0, sizeof(windowTitle));
|
||||
|
||||
std::string description_text;
|
||||
ConvertUCS2ToUTF8(description_text, oskParams->fields[0].desc);
|
||||
|
||||
if(description_text.length() < defaultText_len)
|
||||
strncat(windowTitle, description_text.c_str(), strlen(description_text.c_str()));
|
||||
|
||||
size_t maxInputLength = FieldMaxLength();
|
||||
|
||||
if(host->InputBoxGetString(windowTitle, defaultText, input, maxInputLength)) {
|
||||
strncat(input, "", strlen(""));
|
||||
if(inputWide.length() < maxInputLength)
|
||||
{
|
||||
wcsncat(input, inputWide.c_str(), inputWide.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxInputLength);
|
||||
wcsncat(input, inputWide.c_str(), maxInputLength);
|
||||
}
|
||||
}
|
||||
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
}
|
||||
else if (status == SCE_UTILITY_STATUS_FINISHED)
|
||||
|
||||
@@ -68,7 +68,7 @@ void ElfReader::LoadRelocations(Elf32_Rel *rels, int numRelocs)
|
||||
|
||||
addr += segmentVAddr[readwrite];
|
||||
|
||||
u32 op = Memory::ReadUnchecked_U32(addr);
|
||||
u32 op = Memory::Read_Instruction(addr).encoding;
|
||||
|
||||
const bool log = false;
|
||||
//log=true;
|
||||
@@ -145,7 +145,7 @@ void ElfReader::LoadRelocations(Elf32_Rel *rels, int numRelocs)
|
||||
case R_MIPS_16:
|
||||
{
|
||||
char temp[256];
|
||||
MIPSDisAsm(op, 0, temp);
|
||||
MIPSDisAsm(MIPSOpcode(op), 0, temp);
|
||||
ERROR_LOG_REPORT(LOADER, "WARNING: Unsupported R_MIPS_16 reloc @ %08x : %s", addr, temp);
|
||||
}
|
||||
break;
|
||||
@@ -157,7 +157,7 @@ void ElfReader::LoadRelocations(Elf32_Rel *rels, int numRelocs)
|
||||
default:
|
||||
{
|
||||
char temp[256];
|
||||
MIPSDisAsm(op, 0, temp);
|
||||
MIPSDisAsm(MIPSOpcode(op), 0, temp);
|
||||
ERROR_LOG_REPORT(LOADER,"ARGH IT'S AN UNKNOWN RELOCATION!!!!!!!! %08x, type=%d : %s", addr, type, temp);
|
||||
}
|
||||
break;
|
||||
@@ -253,7 +253,7 @@ void ElfReader::LoadRelocations2(int rel_seg)
|
||||
buf += 2;
|
||||
rel_base += rel_offset;
|
||||
}else if((flag&0x06)==0x04){
|
||||
rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);;
|
||||
rel_base = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
|
||||
buf += 4;
|
||||
}else{
|
||||
ERROR_LOG_REPORT(LOADER, "Rel2: invalid relocat size flag! %x", flag);
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/ELF/PBPReader.h"
|
||||
|
||||
PBPReader::PBPReader(const char *filename) : header_() {
|
||||
file_ = fopen(filename, "rb");
|
||||
file_ = File::OpenCFile(filename, "rb");
|
||||
if (!file_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
#include "BlockDevices.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/FileSystems/BlockDevices.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
@@ -29,7 +30,7 @@ extern "C"
|
||||
|
||||
BlockDevice *constructBlockDevice(const char *filename) {
|
||||
// Check for CISO
|
||||
FILE *f = fopen(filename, "rb");
|
||||
FILE *f = File::OpenCFile(filename, "rb");
|
||||
if (!f)
|
||||
return 0;
|
||||
char buffer[4];
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "ISOFileSystem.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "file/zip_read.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/CommonWindows.h"
|
||||
@@ -184,7 +185,7 @@ bool DirectoryFileHandle::Open(std::string& basePath, std::string& fileName, Fil
|
||||
openmode = OPEN_EXISTING;
|
||||
}
|
||||
//Let's do it!
|
||||
hFile = CreateFile(fullName.c_str(), desired, sharemode, 0, openmode, 0, 0);
|
||||
hFile = CreateFile(ConvertUTF8ToWString(fullName).c_str(), desired, sharemode, 0, openmode, 0, 0);
|
||||
bool success = hFile != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
// Convert flags in access parameter to fopen access mode
|
||||
@@ -392,7 +393,7 @@ int DirectoryFileSystem::RenameFile(const std::string &from, const std::string &
|
||||
const char * fullToC = fullTo.c_str();
|
||||
|
||||
#ifdef _WIN32
|
||||
bool retValue = (MoveFile(fullFrom.c_str(), fullToC) == TRUE);
|
||||
bool retValue = (MoveFile(ConvertUTF8ToWString(fullFrom).c_str(), ConvertUTF8ToWString(fullToC).c_str()) == TRUE);
|
||||
#else
|
||||
bool retValue = (0 == rename(fullFrom.c_str(), fullToC));
|
||||
#endif
|
||||
@@ -586,7 +587,7 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
||||
|
||||
std::string w32path = GetLocalPath(path) + "\\*.*";
|
||||
|
||||
hFind = FindFirstFile(w32path.c_str(), &findData);
|
||||
hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
return myVector; //the empty list
|
||||
@@ -603,11 +604,11 @@ std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
||||
entry.access = entry.type == FILETYPE_NORMAL ? 0666 : 0777;
|
||||
// TODO: is this just for .. or all subdirectories? Need to add a directory to the test
|
||||
// to find out. Also why so different than the old test results?
|
||||
if (!strcmp(findData.cFileName, "..") )
|
||||
if (!wcscmp(findData.cFileName, L"..") )
|
||||
entry.size = 4096;
|
||||
else
|
||||
entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
|
||||
entry.name = findData.cFileName;
|
||||
entry.name = ConvertWStringToUTF8(findData.cFileName);
|
||||
tmFromFiletime(entry.atime, findData.ftLastAccessTime);
|
||||
tmFromFiletime(entry.ctime, findData.ftCreationTime);
|
||||
tmFromFiletime(entry.mtime, findData.ftLastWriteTime);
|
||||
|
||||
@@ -662,7 +662,7 @@ void ISOFileSystem::DoState(PointerWrap &p)
|
||||
entries.clear();
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
u32 fd;
|
||||
u32 fd = 0;
|
||||
OpenFileEntry of;
|
||||
|
||||
p.Do(fd);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Core/FileSystems/ISOFileSystem.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "file/zip_read.h"
|
||||
#include "util/text/utf8.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Common/CommonWindows.h"
|
||||
@@ -168,7 +169,7 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p)
|
||||
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
u32 fd;
|
||||
u32 fd = 0;
|
||||
OpenFileEntry of;
|
||||
|
||||
p.Do(fd);
|
||||
@@ -599,14 +600,14 @@ std::vector<PSPFileInfo> VirtualDiscFileSystem::GetDirListing(std::string path)
|
||||
|
||||
std::string w32path = GetLocalPath(path) + "\\*.*";
|
||||
|
||||
hFind = FindFirstFile(w32path.c_str(), &findData);
|
||||
hFind = FindFirstFile(ConvertUTF8ToWString(w32path).c_str(), &findData);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
return myVector; //the empty list
|
||||
}
|
||||
|
||||
for (BOOL retval = 1; retval; retval = FindNextFile(hFind, &findData)) {
|
||||
if (!strcmp(findData.cFileName, "..") || !strcmp(findData.cFileName, ".")) {
|
||||
if (!wcscmp(findData.cFileName, L"..") || !wcscmp(findData.cFileName, L".")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -619,7 +620,7 @@ std::vector<PSPFileInfo> VirtualDiscFileSystem::GetDirListing(std::string path)
|
||||
|
||||
entry.access = FILEACCESS_READ;
|
||||
entry.size = findData.nFileSizeLow | ((u64)findData.nFileSizeHigh<<32);
|
||||
entry.name = findData.cFileName;
|
||||
entry.name = ConvertWStringToUTF8(findData.cFileName);
|
||||
tmFromFiletime(entry.atime, findData.ftLastAccessTime);
|
||||
tmFromFiletime(entry.ctime, findData.ftCreationTime);
|
||||
tmFromFiletime(entry.mtime, findData.ftLastWriteTime);
|
||||
@@ -728,7 +729,7 @@ void VirtualDiscFileSystem::HandlerLogger(void *arg, HandlerHandle handle, LogTy
|
||||
|
||||
VirtualDiscFileSystem::Handler::Handler(const char *filename, VirtualDiscFileSystem *const sys) {
|
||||
#ifdef _WIN32
|
||||
#define dlopen(name, ignore) (void *)LoadLibrary(name)
|
||||
#define dlopen(name, ignore) (void *)LoadLibrary(ConvertUTF8ToWString(name).c_str())
|
||||
#define dlsym(mod, name) GetProcAddress((HMODULE)mod, name)
|
||||
#define dlclose(mod) FreeLibrary((HMODULE)mod)
|
||||
#endif
|
||||
|
||||
+38
-87
@@ -58,8 +58,6 @@ typedef std::vector<Syscall> SyscallVector;
|
||||
typedef std::map<std::string, SyscallVector> SyscallVectorByModule;
|
||||
|
||||
static std::vector<HLEModule> moduleDB;
|
||||
static SyscallVectorByModule unresolvedSyscalls;
|
||||
static SyscallVectorByModule exportedCalls;
|
||||
static int delayedResultEvent = -1;
|
||||
static int hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
static const char *hleAfterSyscallReschedReason;
|
||||
@@ -87,8 +85,6 @@ void HLEInit()
|
||||
|
||||
void HLEDoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(unresolvedSyscalls);
|
||||
p.Do(exportedCalls);
|
||||
p.Do(delayedResultEvent);
|
||||
CoreTiming::RestoreRegisterEvent(delayedResultEvent, "HLEDelayedResult", hleDelayResultFinish);
|
||||
p.DoMarker("HLE");
|
||||
@@ -98,8 +94,6 @@ void HLEShutdown()
|
||||
{
|
||||
hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
moduleDB.clear();
|
||||
unresolvedSyscalls.clear();
|
||||
exportedCalls.clear();
|
||||
}
|
||||
|
||||
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable)
|
||||
@@ -159,33 +153,19 @@ const char *GetFuncName(const char *moduleName, u32 nib)
|
||||
if (func)
|
||||
return func->name;
|
||||
|
||||
SyscallModuleName searchModuleName = {0};
|
||||
strncpy(searchModuleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
searchModuleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
// Was this function exported previously?
|
||||
static char temp[256];
|
||||
const auto exported = exportedCalls.find(searchModuleName);
|
||||
if (exported != exportedCalls.end())
|
||||
{
|
||||
const SyscallVector &syscalls = exported->second;
|
||||
for (auto it = syscalls.begin(), end = syscalls.end(); it != end; ++it)
|
||||
{
|
||||
if (it->nid == nib)
|
||||
{
|
||||
sprintf(temp, "[EXP: 0x%08x]", nib);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No good, we can't find it.
|
||||
sprintf(temp,"[UNK: 0x%08x]", nib);
|
||||
return temp;
|
||||
}
|
||||
|
||||
u32 GetSyscallOp(const char *moduleName, u32 nib)
|
||||
{
|
||||
// Special case to hook up bad imports.
|
||||
if (moduleName == NULL)
|
||||
{
|
||||
return (0x03FFFFCC); // invalid syscall
|
||||
}
|
||||
|
||||
int modindex = GetModuleIndex(moduleName);
|
||||
if (modindex != -1)
|
||||
{
|
||||
@@ -197,7 +177,6 @@ u32 GetSyscallOp(const char *moduleName, u32 nib)
|
||||
else
|
||||
{
|
||||
INFO_LOG(HLE, "Syscall (%s, %08x) unknown", moduleName, nib);
|
||||
Reporting::ReportMessage("Unknown syscall in known module: %s 0x%08x", moduleName, nib);
|
||||
return (0x0003FFCC | (modindex<<18)); // invalid syscall
|
||||
}
|
||||
}
|
||||
@@ -208,77 +187,47 @@ u32 GetSyscallOp(const char *moduleName, u32 nib)
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
bool FuncImportIsSyscall(const char *module, u32 nib)
|
||||
{
|
||||
return GetFunc(module, nib) != NULL;
|
||||
}
|
||||
|
||||
void WriteFuncStub(u32 stubAddr, u32 symAddr)
|
||||
{
|
||||
// Note that this should be J not JAL, as otherwise control will return to the stub..
|
||||
Memory::Write_U32(MIPS_MAKE_J(symAddr), stubAddr);
|
||||
// Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently
|
||||
// Perhaps a syscall here (and verify support in jit), marking the module by uid (debugIdentifier)?
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), stubAddr + 4);
|
||||
}
|
||||
|
||||
void WriteFuncMissingStub(u32 stubAddr, u32 nid)
|
||||
{
|
||||
// Write a trap so we notice this func if it's called before resolving.
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), stubAddr); // jr ra
|
||||
Memory::Write_U32(GetSyscallOp(NULL, nid), stubAddr + 4);
|
||||
}
|
||||
|
||||
bool WriteSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
{
|
||||
if (nib == 0)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "Wrote patched out nid=0 syscall (%s)", moduleName);
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); //patched out?
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out?
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
int modindex = GetModuleIndex(moduleName);
|
||||
if (modindex != -1)
|
||||
{
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra
|
||||
Memory::Write_U32(GetSyscallOp(moduleName, nib), address + 4);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Syscall sysc = {"", address, nib};
|
||||
strncpy(sysc.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
sysc.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
// Did another module export this already?
|
||||
const auto exported = exportedCalls.find(sysc.moduleName);
|
||||
if (exported != exportedCalls.end())
|
||||
{
|
||||
const SyscallVector &syscalls = exported->second;
|
||||
for (auto it = syscalls.begin(), end = syscalls.end(); it != end; ++it)
|
||||
{
|
||||
if (it->nid == nib)
|
||||
{
|
||||
Memory::Write_U32(MIPS_MAKE_J(it->symAddr), address); // j symAddr
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), address + 4); // nop (delay slot)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Module inexistent.. for now; let's store the syscall for it to be resolved later
|
||||
INFO_LOG(HLE,"Syscall (%s,%08x) unresolved, storing for later resolving", moduleName, nib);
|
||||
unresolvedSyscalls[sysc.moduleName].push_back(sysc);
|
||||
|
||||
// Write a trap so we notice this func if it's called before resolving.
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra
|
||||
Memory::Write_U32(GetSyscallOp("(invalid syscall)", nib), address + 4);
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name.");
|
||||
|
||||
Syscall ex = {"", address, nib};
|
||||
strncpy(ex.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
ex.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
exportedCalls[ex.moduleName].push_back(ex);
|
||||
|
||||
const auto unresolved = unresolvedSyscalls.find(ex.moduleName);
|
||||
if (unresolved != unresolvedSyscalls.end())
|
||||
{
|
||||
const SyscallVector &syscalls = unresolved->second;
|
||||
for (size_t i = 0; i < syscalls.size(); i++)
|
||||
{
|
||||
const Syscall *sysc = &syscalls[i];
|
||||
if (sysc->nid == nib)
|
||||
{
|
||||
INFO_LOG(HLE,"Resolving %s/%08x",moduleName,nib);
|
||||
// Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently
|
||||
// Note that this should be J not JAL, as otherwise control will return to the stub..
|
||||
Memory::Write_U32(MIPS_MAKE_J(address), sysc->symAddr);
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), sysc->symAddr + 4);
|
||||
}
|
||||
}
|
||||
ERROR_LOG_REPORT(HLE, "Unable to write unknown syscall: %s/%08x", moduleName, nib);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +405,7 @@ inline void updateSyscallStats(int modulenum, int funcnum, double total)
|
||||
}
|
||||
}
|
||||
|
||||
void CallSyscall(u32 op)
|
||||
void CallSyscall(MIPSOpcode op)
|
||||
{
|
||||
double start = 0.0; // need to initialize to fix the race condition where g_Config.bShowDebugStats is enabled in the middle of this func.
|
||||
if (g_Config.bShowDebugStats)
|
||||
@@ -477,10 +426,12 @@ void CallSyscall(u32 op)
|
||||
{
|
||||
// TODO: Move to jit/interp.
|
||||
u32 flags = moduleDB[modulenum].funcTable[funcnum].flags;
|
||||
if (flags & HLE_NOT_DISPATCH_SUSPENDED)
|
||||
if (flags != 0)
|
||||
{
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled())
|
||||
RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT);
|
||||
else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt())
|
||||
RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT);
|
||||
else
|
||||
func();
|
||||
}
|
||||
|
||||
+5
-4
@@ -113,7 +113,8 @@ void HLEDoState(PointerWrap &p);
|
||||
void HLEShutdown();
|
||||
u32 GetNibByName(const char *module, const char *function);
|
||||
u32 GetSyscallOp(const char *module, u32 nib);
|
||||
void WriteSyscall(const char *module, u32 nib, u32 address);
|
||||
void CallSyscall(u32 op);
|
||||
void ResolveSyscall(const char *moduleName, u32 nib, u32 address);
|
||||
|
||||
bool FuncImportIsSyscall(const char *module, u32 nib);
|
||||
bool WriteSyscall(const char *module, u32 nib, u32 address);
|
||||
void CallSyscall(MIPSOpcode op);
|
||||
void WriteFuncStub(u32 stubAddr, u32 symAddr);
|
||||
void WriteFuncMissingStub(u32 stubAddr, u32 nid);
|
||||
@@ -256,12 +256,14 @@ static const int numModules = sizeof(moduleList)/sizeof(HLEModule);
|
||||
void RegisterAllModules() {
|
||||
Register_Kernel_Library();
|
||||
Register_ThreadManForUser();
|
||||
Register_ThreadManForKernel();
|
||||
Register_LoadExecForUser();
|
||||
Register_UtilsForKernel();
|
||||
Register_SysMemUserForUser();
|
||||
Register_InterruptManager();
|
||||
Register_IoFileMgrForUser();
|
||||
Register_ModuleMgrForUser();
|
||||
Register_ModuleMgrForKernel();
|
||||
Register_StdioForUser();
|
||||
|
||||
Register_sceHprm();
|
||||
|
||||
+11
-6
@@ -85,7 +85,7 @@ void __AudioInit() {
|
||||
|
||||
if (g_Config.bLowLatencyAudio) {
|
||||
chanQueueMaxSizeFactor = 1;
|
||||
chanQueueMinSizeFactor = 0;
|
||||
chanQueueMinSizeFactor = 1;
|
||||
hwBlockSize = 16;
|
||||
hostAttemptBlockSize = 256;
|
||||
} else {
|
||||
@@ -160,10 +160,15 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking) {
|
||||
// TODO: Regular multichannel audio seems to block for 64 samples less? Or enqueue the first 64 sync?
|
||||
int blockSamples = (int)chan.sampleQueue.size() / 2 / chanQueueMinSizeFactor;
|
||||
|
||||
AudioChannelWaitInfo waitInfo = {__KernelGetCurThread(), blockSamples};
|
||||
chan.waitingThreads.push_back(waitInfo);
|
||||
// Also remember the value to return in the waitValue.
|
||||
__KernelWaitCurThread(WAITTYPE_AUDIOCHANNEL, (SceUID)chanNum + 1, ret, 0, false, "blocking audio waited");
|
||||
if (__KernelIsDispatchEnabled()) {
|
||||
AudioChannelWaitInfo waitInfo = {__KernelGetCurThread(), blockSamples};
|
||||
chan.waitingThreads.push_back(waitInfo);
|
||||
// Also remember the value to return in the waitValue.
|
||||
__KernelWaitCurThread(WAITTYPE_AUDIOCHANNEL, (SceUID)chanNum + 1, ret, 0, false, "blocking audio");
|
||||
} else {
|
||||
// TODO: Maybe we shouldn't take this audio after all?
|
||||
ret = SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
|
||||
// Fall through to the sample queueing, don't want to lose the samples even though
|
||||
// we're getting full. The PSP would enqueue after blocking.
|
||||
@@ -311,7 +316,7 @@ void __AudioUpdate() {
|
||||
}
|
||||
|
||||
if (firstChannel) {
|
||||
memset(mixBuffer, 0, sizeof(mixBuffer));
|
||||
memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32));
|
||||
}
|
||||
|
||||
if (g_Config.bEnableSound) {
|
||||
|
||||
@@ -65,6 +65,8 @@ const u32 ATRAC3PLUS_MAX_SAMPLES = 0x800;
|
||||
|
||||
static const int atracDecodeDelay = 2300;
|
||||
|
||||
static const int MAX_CONFIG_VOLUME = 8;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
|
||||
// Urgh! Why is this needed?
|
||||
@@ -625,7 +627,6 @@ u32 _AtracDecodeData(int atracID, u8* outbuf, u32 *SamplesNum, u32* finish, int
|
||||
atrac->sampleQueue.push(buf, decodebytes);
|
||||
}
|
||||
}
|
||||
const int MAX_CONFIG_VOLUME = 8;
|
||||
s16* out = (s16*)outbuf;
|
||||
memset(out, 0, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels);
|
||||
int gotsize = atrac->sampleQueue.pop_front(buf, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels);
|
||||
@@ -1696,7 +1697,6 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA
|
||||
Atrac3plus_Decoder::Decode(atrac->decoder_context, Memory::GetPointer(sourceAddr), sourcebytes, &decodebytes, buf);
|
||||
atrac->sampleQueue.push(buf, decodebytes);
|
||||
}
|
||||
const int MAX_CONFIG_VOLUME = 5;
|
||||
s16* out = (s16*)Memory::GetPointer(samplesAddr);
|
||||
memset(out, 0, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracOutputChannels);
|
||||
int gotsize = atrac->sampleQueue.pop_front(buf, ATRAC3PLUS_MAX_SAMPLES * sizeof(s16) * atrac->atracChannels);
|
||||
|
||||
@@ -79,7 +79,7 @@ u32 sceAudioOutputBlocking(u32 chan, int vol, u32 samplePtr) {
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputBlocking() - channel not reserved");
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceAudioOutputBlocking(%08x, %08x, %08x)", chan, vol, samplePtr);
|
||||
if (vol >= 0) {
|
||||
@@ -100,7 +100,7 @@ u32 sceAudioOutputPannedBlocking(u32 chan, int leftvol, int rightvol, u32 sample
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputPannedBlocking() - channel not reserved");
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceAudioOutputPannedBlocking(%08x, %08x, %08x, %08x)", chan, leftvol, rightvol, samplePtr);
|
||||
if (leftvol >= 0) {
|
||||
@@ -123,7 +123,7 @@ u32 sceAudioOutput(u32 chan, int vol, u32 samplePtr) {
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutput(%08x, %08x, %08x) - channel not reserved", chan, vol, samplePtr);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceAudioOutputPanned(%08x, %08x, %08x)", chan, vol, samplePtr);
|
||||
if (vol >= 0) {
|
||||
@@ -144,7 +144,7 @@ u32 sceAudioOutputPanned(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
|
||||
return SCE_ERROR_AUDIO_INVALID_CHANNEL;
|
||||
} else if (!chans[chan].reserved) {
|
||||
ERROR_LOG(HLE,"sceAudioOutputPanned(%08x, %08x, %08x, %08x) - channel not reserved", chan, leftvol, rightvol, samplePtr);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_INIT;
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"sceAudioOutputPanned(%08x, %08x, %08x, %08x)", chan, leftvol, rightvol, samplePtr);
|
||||
if (leftvol >= 0) {
|
||||
|
||||
+15
-9
@@ -16,15 +16,16 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <math.h>
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "StdMutex.h"
|
||||
#include "sceCtrl.h"
|
||||
#include "sceDisplay.h"
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/StdMutex.h"
|
||||
#include "Core/HLE/sceCtrl.h"
|
||||
#include "Core/HLE/sceDisplay.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
|
||||
/* Index for the two analog directions */
|
||||
#define CTRL_ANALOG_X 0
|
||||
@@ -216,6 +217,11 @@ int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek)
|
||||
if (nBufs > NUM_CTRL_BUFFERS)
|
||||
return SCE_KERNEL_ERROR_INVALID_SIZE;
|
||||
|
||||
if (!peek && !__KernelIsDispatchEnabled())
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
if (!peek && __IsInInterrupt())
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
|
||||
u32 resetRead = ctrlBufRead;
|
||||
|
||||
u32 availBufs;
|
||||
|
||||
+49
-13
@@ -115,6 +115,8 @@ static int actualFlips = 0; // taking frameskip into account
|
||||
static int lastActualFlips = 0;
|
||||
static float actualFps = 0;
|
||||
static u64 lastFlipCycles = 0;
|
||||
// For the "max 60 fps" setting.
|
||||
static int lastFlipsTooFrequent = 0;
|
||||
|
||||
void hleEnterVblank(u64 userdata, int cyclesLate);
|
||||
void hleLeaveVblank(u64 userdata, int cyclesLate);
|
||||
@@ -135,6 +137,7 @@ void __DisplayInit() {
|
||||
framebuf.pspFramebufFormat = GE_FORMAT_8888;
|
||||
framebuf.pspFramebufLinesize = 480; // ??
|
||||
lastFlipCycles = 0;
|
||||
lastFlipsTooFrequent = 0;
|
||||
|
||||
enterVblankEvent = CoreTiming::RegisterEvent("EnterVBlank", &hleEnterVblank);
|
||||
leaveVblankEvent = CoreTiming::RegisterEvent("LeaveVBlank", &hleLeaveVblank);
|
||||
@@ -272,6 +275,8 @@ void __DisplayGetDebugStats(char stats[2048]) {
|
||||
"Most active syscall: %s : %0.2f ms\n"
|
||||
"Draw calls: %i, flushes %i\n"
|
||||
"Cached Draw calls: %i\n"
|
||||
"Alpha Tested draws: %i\n"
|
||||
"Non Alpha Tested draws: %i\n"
|
||||
"Num Tracked Vertex Arrays: %i\n"
|
||||
"Cycles executed: %d (%f per vertex)\n"
|
||||
"Commands per call level: %i %i %i %i\n"
|
||||
@@ -294,6 +299,8 @@ void __DisplayGetDebugStats(char stats[2048]) {
|
||||
gpuStats.numDrawCalls,
|
||||
gpuStats.numFlushes,
|
||||
gpuStats.numCachedDrawCalls,
|
||||
gpuStats.numAlphaTestedDraws,
|
||||
gpuStats.numNonAlphaTestedDraws,
|
||||
gpuStats.numTrackedVertexArrays,
|
||||
gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles,
|
||||
vertexAverageCycles,
|
||||
@@ -519,15 +526,28 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync)
|
||||
fbstate.pspFramebufLinesize = linesize;
|
||||
}
|
||||
|
||||
if (topaddr != framebuf.topaddr) {
|
||||
if (g_Config.iForceMaxEmulatedFPS) {
|
||||
u64 now = CoreTiming::GetTicks();
|
||||
u64 expected = msToCycles(1000) / g_Config.iForceMaxEmulatedFPS;
|
||||
u64 actual = now - lastFlipCycles;
|
||||
if (actual < expected)
|
||||
hleEatCycles((int)(expected - actual));
|
||||
lastFlipCycles = CoreTiming::GetTicks();
|
||||
s64 delayCycles = 0;
|
||||
if (topaddr != framebuf.topaddr && g_Config.iForceMaxEmulatedFPS > 0) {
|
||||
// Sometimes we get a small number, there's probably no need to delay the thread for this.
|
||||
// sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack.
|
||||
const int FLIP_DELAY_CYCLES_MIN = 10;
|
||||
// Some games (like Final Fantasy 4) only call this too much in spurts.
|
||||
// The goal is to fix games where this would result in a consistent overhead.
|
||||
const int FLIP_DELAY_MIN_FLIPS = 30;
|
||||
|
||||
u64 now = CoreTiming::GetTicks();
|
||||
u64 expected = msToCycles(1000) / g_Config.iForceMaxEmulatedFPS;
|
||||
u64 actual = now - lastFlipCycles;
|
||||
if (actual < expected - FLIP_DELAY_CYCLES_MIN) {
|
||||
if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS) {
|
||||
delayCycles = expected - actual;
|
||||
} else {
|
||||
++lastFlipsTooFrequent;
|
||||
}
|
||||
} else {
|
||||
--lastFlipsTooFrequent;
|
||||
}
|
||||
lastFlipCycles = CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) {
|
||||
@@ -543,7 +563,15 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync)
|
||||
latchedFramebuf = fbstate;
|
||||
framebufIsLatched = true;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (delayCycles > 0) {
|
||||
// Okay, the game is going at too high a frame rate. God of War and Fat Princess both do this.
|
||||
// Simply eating the cycles works and is fast, but breaks other games (like Jeanne d'Arc.)
|
||||
// So, instead, we delay this HLE thread only (a small deviation from correct behavior.)
|
||||
return hleDelayResult(0, "set framebuf", cyclesToUs(delayCycles));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int latchedMode) {
|
||||
@@ -598,6 +626,10 @@ u32 sceDisplayWaitVblankStartMulti(int vblanks) {
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
}
|
||||
VERBOSE_LOG(HLE, "sceDisplayWaitVblankStartMulti(%d)", vblanks);
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
if (__IsInInterrupt())
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks));
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false, "vblank start multi waited");
|
||||
return 0;
|
||||
@@ -629,6 +661,10 @@ u32 sceDisplayWaitVblankStartMultiCB(int vblanks) {
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
}
|
||||
VERBOSE_LOG(HLE,"sceDisplayWaitVblankStartMultiCB(%d)", vblanks);
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
if (__IsInInterrupt())
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks));
|
||||
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true, "vblank start multi waited");
|
||||
return 0;
|
||||
@@ -719,11 +755,11 @@ const HLEFunction sceDisplay[] = {
|
||||
{0x0E20F177,WrapU_III<sceDisplaySetMode>, "sceDisplaySetMode"},
|
||||
{0x289D82FE,WrapU_UIII<sceDisplaySetFramebuf>, "sceDisplaySetFrameBuf"},
|
||||
{0xEEDA2E54,WrapU_UUUI<sceDisplayGetFramebuf>,"sceDisplayGetFrameBuf"},
|
||||
{0x36CDFADE,WrapU_V<sceDisplayWaitVblank>, "sceDisplayWaitVblank"},
|
||||
{0x984C27E7,WrapU_V<sceDisplayWaitVblankStart>, "sceDisplayWaitVblankStart"},
|
||||
{0x36CDFADE,WrapU_V<sceDisplayWaitVblank>, "sceDisplayWaitVblank", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x984C27E7,WrapU_V<sceDisplayWaitVblankStart>, "sceDisplayWaitVblankStart", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x40f1469c,WrapU_I<sceDisplayWaitVblankStartMulti>, "sceDisplayWaitVblankStartMulti"},
|
||||
{0x8EB9EC49,WrapU_V<sceDisplayWaitVblankCB>, "sceDisplayWaitVblankCB"},
|
||||
{0x46F186C3,WrapU_V<sceDisplayWaitVblankStartCB>, "sceDisplayWaitVblankStartCB"},
|
||||
{0x8EB9EC49,WrapU_V<sceDisplayWaitVblankCB>, "sceDisplayWaitVblankCB", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x46F186C3,WrapU_V<sceDisplayWaitVblankStartCB>, "sceDisplayWaitVblankStartCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x77ed8b3a,WrapU_I<sceDisplayWaitVblankStartMultiCB>,"sceDisplayWaitVblankStartMultiCB"},
|
||||
{0xdba6c4c4,WrapF_V<sceDisplayGetFramePerSec>,"sceDisplayGetFramePerSec"},
|
||||
{0x773dd3a3,WrapU_V<sceDisplayGetCurrentHcount>,"sceDisplayGetCurrentHcount"},
|
||||
|
||||
@@ -55,6 +55,11 @@ public:
|
||||
{
|
||||
GeInterruptData intrdata = ge_pending_cb.front();
|
||||
DisplayList* dl = gpu->getList(intrdata.listid);
|
||||
if (!dl->interruptsEnabled)
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "Unable to run GE interrupt: list has interrupts disabled, should not happen");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dl == NULL)
|
||||
{
|
||||
@@ -120,6 +125,11 @@ public:
|
||||
ge_pending_cb.pop_front();
|
||||
|
||||
DisplayList* dl = gpu->getList(intrdata.listid);
|
||||
if (!dl->interruptsEnabled)
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "Unable to finish GE interrupt: list has interrupts disabled, should not happen");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dl->signal)
|
||||
{
|
||||
|
||||
+58
-17
@@ -43,6 +43,7 @@ extern "C" {
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
|
||||
// For headless screenshots.
|
||||
#include "Core/HLE/sceDisplay.h"
|
||||
@@ -644,9 +645,17 @@ bool __IoRead(int &result, int id, u32 data_addr, int size) {
|
||||
}
|
||||
|
||||
u32 sceIoRead(int id, u32 data_addr, int size) {
|
||||
// TODO: Check id is valid first?
|
||||
if (!__KernelIsDispatchEnabled() && id > 2) {
|
||||
return -1;
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
if (id > 2 && f != NULL) {
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "sceIoRead(%d, %08x, %x): dispatch disabled", id, data_addr, size);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "sceIoRead(%d, %08x, %x): inside interrupt", id, data_addr, size);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Timing is probably not very accurate, low estimate.
|
||||
@@ -660,8 +669,6 @@ u32 sceIoRead(int id, u32 data_addr, int size) {
|
||||
if (!complete) {
|
||||
DEBUG_LOG(HLE, "sceIoRead(%d, %08x, %x): deferring result", id, data_addr, size);
|
||||
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
__IoSchedSync(f, id, us);
|
||||
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io read");
|
||||
return 0;
|
||||
@@ -734,9 +741,18 @@ bool __IoWrite(int &result, int id, void *data_ptr, int size) {
|
||||
}
|
||||
|
||||
u32 sceIoWrite(int id, u32 data_addr, int size) {
|
||||
// TODO: Check id is valid first?
|
||||
if (!__KernelIsDispatchEnabled() && id > 2)
|
||||
return -1;
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
if (id > 2 && f != NULL) {
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "sceIoWrite(%d, %08x, %x): dispatch disabled", id, data_addr, size);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "sceIoWrite(%d, %08x, %x): inside interrupt", id, data_addr, size);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Timing is probably not very accurate, low estimate.
|
||||
int us = size / 100;
|
||||
@@ -749,8 +765,6 @@ u32 sceIoWrite(int id, u32 data_addr, int size) {
|
||||
if (!complete) {
|
||||
DEBUG_LOG(HLE, "sceIoWrite(%d, %08x, %x): deferring result", id, data_addr, size);
|
||||
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
__IoSchedSync(f, id, us);
|
||||
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io write");
|
||||
return 0;
|
||||
@@ -1485,24 +1499,33 @@ u32 sceIoOpenAsync(const char *filename, int flags, int mode)
|
||||
return fd;
|
||||
}
|
||||
|
||||
u32 sceIoGetAsyncStat(int id, u32 poll, u32 address)
|
||||
{
|
||||
u32 sceIoGetAsyncStat(int id, u32 poll, u32 address) {
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
if (f)
|
||||
{
|
||||
if (f) {
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x): illegal context", f->asyncResult, id, poll, address);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
if (f->pendingAsyncResult) {
|
||||
if (poll) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x): not ready", f->asyncResult, id, poll, address);
|
||||
return 1;
|
||||
} else {
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x): waiting", f->asyncResult, id, poll, address);
|
||||
__KernelWaitCurThread(WAITTYPE_IO, id, address, 0, false, "io waited");
|
||||
}
|
||||
} else if (f->hasAsyncResult) {
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x): dispatch disabled", f->asyncResult, id, poll, address);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "%lli = sceIoGetAsyncStat(%i, %i, %08x)", f->asyncResult, id, poll, address);
|
||||
Memory::Write_U64((u64) f->asyncResult, address);
|
||||
f->hasAsyncResult = false;
|
||||
@@ -1527,10 +1550,22 @@ int sceIoWaitAsync(int id, u32 address) {
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
if (f) {
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsync(%i, %08x): illegal context", f->asyncResult, id, address);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
if (f->pendingAsyncResult) {
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsync(%i, %08x): dispatch disabled", f->asyncResult, id, address);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsync(%i, %08x): waiting", f->asyncResult, id, address);
|
||||
__KernelWaitCurThread(WAITTYPE_IO, id, address, 0, false, "io waited");
|
||||
} else if (f->hasAsyncResult) {
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsync(%i, %08x): dispatch disabled", f->asyncResult, id, address);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsync(%i, %08x)", f->asyncResult, id, address);
|
||||
Memory::Write_U64((u64) f->asyncResult, address);
|
||||
f->hasAsyncResult = false;
|
||||
@@ -1554,9 +1589,15 @@ int sceIoWaitAsyncCB(int id, u32 address) {
|
||||
u32 error;
|
||||
FileNode *f = __IoGetFd(id, error);
|
||||
if (f) {
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsyncCB(%i, %08x): illegal context", f->asyncResult, id, address);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
|
||||
hleCheckCurrentCallbacks();
|
||||
if (f->pendingAsyncResult) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsyncCB(%i, %08x): waiting", f->asyncResult, id, address);
|
||||
// TODO: This seems to re-enable dispatch or something?
|
||||
__KernelWaitCurThread(WAITTYPE_IO, id, address, 0, false, "io waited");
|
||||
} else if (f->hasAsyncResult) {
|
||||
DEBUG_LOG(HLE, "%lli = sceIoWaitAsyncCB(%i, %08x)", f->asyncResult, id, address);
|
||||
@@ -1923,8 +1964,8 @@ const HLEFunction IoFileMgrForUser[] = {
|
||||
{ 0x6d08a871, &WrapU_C<sceIoUnassign>, "sceIoUnassign" },
|
||||
{ 0x42EC03AC, &WrapU_IUI<sceIoWrite>, "sceIoWrite" }, //(int fd, void *data, int size);
|
||||
{ 0x0facab19, &WrapU_IUI<sceIoWriteAsync>, "sceIoWriteAsync" },
|
||||
{ 0x35dbd746, &WrapI_IU<sceIoWaitAsyncCB>, "sceIoWaitAsyncCB", HLE_NOT_DISPATCH_SUSPENDED },
|
||||
{ 0xe23eec33, &WrapI_IU<sceIoWaitAsync>, "sceIoWaitAsync", HLE_NOT_DISPATCH_SUSPENDED },
|
||||
{ 0x35dbd746, &WrapI_IU<sceIoWaitAsyncCB>, "sceIoWaitAsyncCB" },
|
||||
{ 0xe23eec33, &WrapI_IU<sceIoWaitAsync>, "sceIoWaitAsync" },
|
||||
{ 0x5C2BE2CC, &WrapU_UIU<sceIoGetFdList>, "sceIoGetFdList"},
|
||||
};
|
||||
|
||||
|
||||
+92
-63
@@ -636,14 +636,32 @@ int sceKernelReferGlobalProfiler(u32 statusPtr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadManForKernel_446d8de6(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
return sceKernelCreateThread(threadName, entry, prio, stacksize, attr, optionAddr);
|
||||
}
|
||||
|
||||
int ThreadManForKernel_f475845d(SceUID threadToStartID, int argSize, u32 argBlockPtr)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
return sceKernelStartThread(threadToStartID,argSize,argBlockPtr);
|
||||
}
|
||||
|
||||
int ThreadManForKernel_ceadeb47(u32 usec)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
return sceKernelDelayThread(usec);
|
||||
}
|
||||
|
||||
const HLEFunction ThreadManForUser[] =
|
||||
{
|
||||
{0x55C20A00,&WrapI_CUUU<sceKernelCreateEventFlag>, "sceKernelCreateEventFlag"},
|
||||
{0x812346E4,&WrapU_IU<sceKernelClearEventFlag>, "sceKernelClearEventFlag"},
|
||||
{0xEF9E4C70,&WrapU_I<sceKernelDeleteEventFlag>, "sceKernelDeleteEventFlag"},
|
||||
{0x1fb15a32,&WrapU_IU<sceKernelSetEventFlag>, "sceKernelSetEventFlag"},
|
||||
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
|
||||
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
|
||||
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag", HLE_NOT_IN_INTERRUPT},
|
||||
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB", HLE_NOT_IN_INTERRUPT},
|
||||
{0x30FD48F0,&WrapI_IUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
|
||||
{0xCD203292,&WrapU_IUU<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
|
||||
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
|
||||
@@ -654,8 +672,8 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x58b1f937,&WrapI_II<sceKernelPollSema>, "sceKernelPollSema"},
|
||||
{0xBC6FEBC5,&WrapI_IU<sceKernelReferSemaStatus>, "sceKernelReferSemaStatus"},
|
||||
{0x3F53E640,&WrapI_II<sceKernelSignalSema>, "sceKernelSignalSema"},
|
||||
{0x4E3A1105,&WrapI_IIU<sceKernelWaitSema>, "sceKernelWaitSema", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x6d212bac,&WrapI_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x4E3A1105,&WrapI_IIU<sceKernelWaitSema>, "sceKernelWaitSema", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x6d212bac,&WrapI_IIU<sceKernelWaitSemaCB>, "sceKernelWaitSemaCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
|
||||
{0x60107536,&WrapI_U<sceKernelDeleteLwMutex>, "sceKernelDeleteLwMutex"},
|
||||
{0x19CFF145,&WrapI_UCUIU<sceKernelCreateLwMutex>, "sceKernelCreateLwMutex"},
|
||||
@@ -667,14 +685,14 @@ const HLEFunction ThreadManForUser[] =
|
||||
//{0x31327F19,0, "_sceKernelLockLwMutexCB"},
|
||||
//{0xBEED3A47,0, "_sceKernelUnlockLwMutex"},
|
||||
|
||||
{0xf8170fbe,&WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
|
||||
{0xB011B11F,&WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x5bf4dd27,&WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x6b30100f,&WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
|
||||
{0xb7d098c6,&WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
|
||||
{0x0DDCD2C9,&WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
|
||||
{0xA9C2CB9A,&WrapI_IU<sceKernelReferMutexStatus>, "sceKernelReferMutexStatus"},
|
||||
{0x87D9223C,0, "sceKernelCancelMutex"},
|
||||
{0xf8170fbe,WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
|
||||
{0xB011B11F,WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x5bf4dd27,WrapI_IIU<sceKernelLockMutexCB>, "sceKernelLockMutexCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x6b30100f,WrapI_II<sceKernelUnlockMutex>, "sceKernelUnlockMutex"},
|
||||
{0xb7d098c6,WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
|
||||
{0x0DDCD2C9,WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
|
||||
{0xA9C2CB9A,WrapI_IU<sceKernelReferMutexStatus>, "sceKernelReferMutexStatus"},
|
||||
{0x87D9223C,WrapI_IIU<sceKernelCancelMutex>, "sceKernelCancelMutex"},
|
||||
|
||||
{0xFCCFAD26,WrapI_I<sceKernelCancelWakeupThread>,"sceKernelCancelWakeupThread"},
|
||||
{0x1AF94D03,0,"sceKernelDonateWakeupThread"},
|
||||
@@ -682,10 +700,10 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x71bc9871,WrapI_II<sceKernelChangeThreadPriority>,"sceKernelChangeThreadPriority"},
|
||||
{0x446D8DE6,WrapI_CUUIUU<sceKernelCreateThread>,"sceKernelCreateThread"},
|
||||
{0x9fa03cd3,WrapI_I<sceKernelDeleteThread>,"sceKernelDeleteThread"},
|
||||
{0xBD123D9E,sceKernelDelaySysClockThread,"sceKernelDelaySysClockThread"},
|
||||
{0x1181E963,sceKernelDelaySysClockThreadCB,"sceKernelDelaySysClockThreadCB"},
|
||||
{0xceadeb47,WrapI_U<sceKernelDelayThread>,"sceKernelDelayThread"},
|
||||
{0x68da9e36,WrapI_U<sceKernelDelayThreadCB>,"sceKernelDelayThreadCB"},
|
||||
{0xBD123D9E,WrapI_U<sceKernelDelaySysClockThread>, "sceKernelDelaySysClockThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x1181E963,WrapI_U<sceKernelDelaySysClockThreadCB>, "sceKernelDelaySysClockThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xceadeb47,WrapI_U<sceKernelDelayThread>, "sceKernelDelayThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x68da9e36,WrapI_U<sceKernelDelayThreadCB>, "sceKernelDelayThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xaa73c935,WrapV_I<sceKernelExitThread>,"sceKernelExitThread"},
|
||||
{0x809ce29b,WrapV_I<sceKernelExitDeleteThread>,"sceKernelExitDeleteThread"},
|
||||
{0x94aa61ee,sceKernelGetThreadCurrentPriority,"sceKernelGetThreadCurrentPriority"},
|
||||
@@ -696,11 +714,11 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x17c1684e,WrapU_UU<sceKernelReferThreadStatus>,"sceKernelReferThreadStatus"},
|
||||
{0x2C34E053,WrapI_I<sceKernelReleaseWaitThread>,"sceKernelReleaseWaitThread"},
|
||||
{0x75156e8f,WrapI_I<sceKernelResumeThread>,"sceKernelResumeThread"},
|
||||
{0x3ad58b8c,&WrapU_V<sceKernelSuspendDispatchThread>,"sceKernelSuspendDispatchThread"},
|
||||
{0x27e22ec2,&WrapU_U<sceKernelResumeDispatchThread>,"sceKernelResumeDispatchThread"},
|
||||
{0x3ad58b8c,&WrapU_V<sceKernelSuspendDispatchThread>, "sceKernelSuspendDispatchThread", HLE_NOT_IN_INTERRUPT},
|
||||
{0x27e22ec2,&WrapU_U<sceKernelResumeDispatchThread>, "sceKernelResumeDispatchThread", HLE_NOT_IN_INTERRUPT},
|
||||
{0x912354a7,&WrapI_I<sceKernelRotateThreadReadyQueue>,"sceKernelRotateThreadReadyQueue"},
|
||||
{0x9ACE131E,WrapI_V<sceKernelSleepThread>,"sceKernelSleepThread"},
|
||||
{0x82826f70,WrapI_V<sceKernelSleepThreadCB>,"sceKernelSleepThreadCB"},
|
||||
{0x9ACE131E,WrapI_V<sceKernelSleepThread>, "sceKernelSleepThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x82826f70,WrapI_V<sceKernelSleepThreadCB>, "sceKernelSleepThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xF475845D,&WrapI_IIU<sceKernelStartThread>,"sceKernelStartThread"},
|
||||
{0x9944f31f,WrapI_I<sceKernelSuspendThread>,"sceKernelSuspendThread"},
|
||||
{0x616403ba,WrapI_I<sceKernelTerminateThread>,"sceKernelTerminateThread"},
|
||||
@@ -740,51 +758,51 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x72F3C145,0,"sceKernelReleaseThreadEventHandler"},
|
||||
{0x369EEB6B,0,"sceKernelReferThreadEventHandlerStatus"},
|
||||
|
||||
{0x349d6d6c,sceKernelCheckCallback, "sceKernelCheckCallback"},
|
||||
{0xE81CAF8F,WrapI_CUU<sceKernelCreateCallback>, "sceKernelCreateCallback"},
|
||||
{0xEDBA5844,WrapI_I<sceKernelDeleteCallback>, "sceKernelDeleteCallback"},
|
||||
{0xC11BA8C4,WrapI_II<sceKernelNotifyCallback>, "sceKernelNotifyCallback"},
|
||||
{0xBA4051D6,WrapI_I<sceKernelCancelCallback>, "sceKernelCancelCallback"},
|
||||
{0x2A3D44FF,WrapI_I<sceKernelGetCallbackCount>, "sceKernelGetCallbackCount"},
|
||||
{0x730ED8BC,WrapI_IU<sceKernelReferCallbackStatus>, "sceKernelReferCallbackStatus"},
|
||||
{0x349d6d6c,sceKernelCheckCallback, "sceKernelCheckCallback"},
|
||||
{0xE81CAF8F,WrapI_CUU<sceKernelCreateCallback>, "sceKernelCreateCallback"},
|
||||
{0xEDBA5844,WrapI_I<sceKernelDeleteCallback>, "sceKernelDeleteCallback"},
|
||||
{0xC11BA8C4,WrapI_II<sceKernelNotifyCallback>, "sceKernelNotifyCallback"},
|
||||
{0xBA4051D6,WrapI_I<sceKernelCancelCallback>, "sceKernelCancelCallback"},
|
||||
{0x2A3D44FF,WrapI_I<sceKernelGetCallbackCount>, "sceKernelGetCallbackCount"},
|
||||
{0x730ED8BC,WrapI_IU<sceKernelReferCallbackStatus>, "sceKernelReferCallbackStatus"},
|
||||
|
||||
{0x8125221D,WrapI_CUU<sceKernelCreateMbx>, "sceKernelCreateMbx"},
|
||||
{0x86255ADA,WrapI_I<sceKernelDeleteMbx>, "sceKernelDeleteMbx"},
|
||||
{0xE9B3061E,WrapI_IU<sceKernelSendMbx>, "sceKernelSendMbx"},
|
||||
{0x18260574,WrapI_IUU<sceKernelReceiveMbx>, "sceKernelReceiveMbx"},
|
||||
{0xF3986382,WrapI_IUU<sceKernelReceiveMbxCB>, "sceKernelReceiveMbxCB"},
|
||||
{0x0D81716A,WrapI_IU<sceKernelPollMbx>, "sceKernelPollMbx"},
|
||||
{0x87D4DD36,WrapI_IU<sceKernelCancelReceiveMbx>, "sceKernelCancelReceiveMbx"},
|
||||
{0xA8E8C846,WrapI_IU<sceKernelReferMbxStatus>, "sceKernelReferMbxStatus"},
|
||||
{0x8125221D,WrapI_CUU<sceKernelCreateMbx>, "sceKernelCreateMbx"},
|
||||
{0x86255ADA,WrapI_I<sceKernelDeleteMbx>, "sceKernelDeleteMbx"},
|
||||
{0xE9B3061E,WrapI_IU<sceKernelSendMbx>, "sceKernelSendMbx"},
|
||||
{0x18260574,WrapI_IUU<sceKernelReceiveMbx>, "sceKernelReceiveMbx", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xF3986382,WrapI_IUU<sceKernelReceiveMbxCB>, "sceKernelReceiveMbxCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x0D81716A,WrapI_IU<sceKernelPollMbx>, "sceKernelPollMbx"},
|
||||
{0x87D4DD36,WrapI_IU<sceKernelCancelReceiveMbx>, "sceKernelCancelReceiveMbx"},
|
||||
{0xA8E8C846,WrapI_IU<sceKernelReferMbxStatus>, "sceKernelReferMbxStatus"},
|
||||
|
||||
{0x7C0DC2A0,WrapI_CIUUU<sceKernelCreateMsgPipe>, "sceKernelCreateMsgPipe"},
|
||||
{0xF0B7DA1C,WrapI_I<sceKernelDeleteMsgPipe>, "sceKernelDeleteMsgPipe"},
|
||||
{0x876DBFAD,WrapI_IUUUUU<sceKernelSendMsgPipe>, "sceKernelSendMsgPipe"},
|
||||
{0x7C41F2C2,WrapI_IUUUUU<sceKernelSendMsgPipeCB>, "sceKernelSendMsgPipeCB"},
|
||||
{0x884C9F90,WrapI_IUUUU<sceKernelTrySendMsgPipe>, "sceKernelTrySendMsgPipe"},
|
||||
{0x74829B76,WrapI_IUUUUU<sceKernelReceiveMsgPipe>, "sceKernelReceiveMsgPipe"},
|
||||
{0xFBFA697D,WrapI_IUUUUU<sceKernelReceiveMsgPipeCB>, "sceKernelReceiveMsgPipeCB"},
|
||||
{0xDF52098F,WrapI_IUUUU<sceKernelTryReceiveMsgPipe>, "sceKernelTryReceiveMsgPipe"},
|
||||
{0x349B864D,WrapI_IUU<sceKernelCancelMsgPipe>, "sceKernelCancelMsgPipe"},
|
||||
{0x33BE4024,WrapI_IU<sceKernelReferMsgPipeStatus>, "sceKernelReferMsgPipeStatus"},
|
||||
{0x7C0DC2A0,WrapI_CIUUU<sceKernelCreateMsgPipe>, "sceKernelCreateMsgPipe"},
|
||||
{0xF0B7DA1C,WrapI_I<sceKernelDeleteMsgPipe>, "sceKernelDeleteMsgPipe"},
|
||||
{0x876DBFAD,WrapI_IUUUUU<sceKernelSendMsgPipe>, "sceKernelSendMsgPipe"},
|
||||
{0x7C41F2C2,WrapI_IUUUUU<sceKernelSendMsgPipeCB>, "sceKernelSendMsgPipeCB"},
|
||||
{0x884C9F90,WrapI_IUUUU<sceKernelTrySendMsgPipe>, "sceKernelTrySendMsgPipe"},
|
||||
{0x74829B76,WrapI_IUUUUU<sceKernelReceiveMsgPipe>, "sceKernelReceiveMsgPipe"},
|
||||
{0xFBFA697D,WrapI_IUUUUU<sceKernelReceiveMsgPipeCB>, "sceKernelReceiveMsgPipeCB"},
|
||||
{0xDF52098F,WrapI_IUUUU<sceKernelTryReceiveMsgPipe>, "sceKernelTryReceiveMsgPipe"},
|
||||
{0x349B864D,WrapI_IUU<sceKernelCancelMsgPipe>, "sceKernelCancelMsgPipe"},
|
||||
{0x33BE4024,WrapI_IU<sceKernelReferMsgPipeStatus>, "sceKernelReferMsgPipeStatus"},
|
||||
|
||||
{0x56C039B5,WrapI_CIUUU<sceKernelCreateVpl>,"sceKernelCreateVpl"},
|
||||
{0x89B3D48C,WrapI_I<sceKernelDeleteVpl>,"sceKernelDeleteVpl"},
|
||||
{0xBED27435,WrapI_IUUU<sceKernelAllocateVpl>,"sceKernelAllocateVpl"},
|
||||
{0xEC0A693F,WrapI_IUUU<sceKernelAllocateVplCB>,"sceKernelAllocateVplCB"},
|
||||
{0xAF36D708,WrapI_IUU<sceKernelTryAllocateVpl>,"sceKernelTryAllocateVpl"},
|
||||
{0xB736E9FF,WrapI_IU<sceKernelFreeVpl>,"sceKernelFreeVpl"},
|
||||
{0x1D371B8A,WrapI_IU<sceKernelCancelVpl>,"sceKernelCancelVpl"},
|
||||
{0x39810265,WrapI_IU<sceKernelReferVplStatus>,"sceKernelReferVplStatus"},
|
||||
{0x56C039B5,WrapI_CIUUU<sceKernelCreateVpl>, "sceKernelCreateVpl"},
|
||||
{0x89B3D48C,WrapI_I<sceKernelDeleteVpl>, "sceKernelDeleteVpl"},
|
||||
{0xBED27435,WrapI_IUUU<sceKernelAllocateVpl>, "sceKernelAllocateVpl", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xEC0A693F,WrapI_IUUU<sceKernelAllocateVplCB>, "sceKernelAllocateVplCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xAF36D708,WrapI_IUU<sceKernelTryAllocateVpl>, "sceKernelTryAllocateVpl"},
|
||||
{0xB736E9FF,WrapI_IU<sceKernelFreeVpl>, "sceKernelFreeVpl"},
|
||||
{0x1D371B8A,WrapI_IU<sceKernelCancelVpl>, "sceKernelCancelVpl"},
|
||||
{0x39810265,WrapI_IU<sceKernelReferVplStatus>, "sceKernelReferVplStatus"},
|
||||
|
||||
{0xC07BB470,sceKernelCreateFpl,"sceKernelCreateFpl"},
|
||||
{0xED1410E0,sceKernelDeleteFpl,"sceKernelDeleteFpl"},
|
||||
{0xD979E9BF,sceKernelAllocateFpl,"sceKernelAllocateFpl"},
|
||||
{0xE7282CB6,sceKernelAllocateFplCB,"sceKernelAllocateFplCB"},
|
||||
{0x623AE665,sceKernelTryAllocateFpl,"sceKernelTryAllocateFpl"},
|
||||
{0xF6414A71,sceKernelFreeFpl,"sceKernelFreeFpl"},
|
||||
{0xA8AA591F,sceKernelCancelFpl,"sceKernelCancelFpl"},
|
||||
{0xD8199E4C,sceKernelReferFplStatus,"sceKernelReferFplStatus"},
|
||||
{0xC07BB470,WrapI_CUUUUU<sceKernelCreateFpl>, "sceKernelCreateFpl"},
|
||||
{0xED1410E0,WrapI_I<sceKernelDeleteFpl>, "sceKernelDeleteFpl"},
|
||||
{0xD979E9BF,WrapI_IUU<sceKernelAllocateFpl>, "sceKernelAllocateFpl", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xE7282CB6,WrapI_IUU<sceKernelAllocateFplCB>, "sceKernelAllocateFplCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x623AE665,WrapI_IU<sceKernelTryAllocateFpl>, "sceKernelTryAllocateFpl"},
|
||||
{0xF6414A71,WrapI_IU<sceKernelFreeFpl>, "sceKernelFreeFpl"},
|
||||
{0xA8AA591F,WrapI_IU<sceKernelCancelFpl>, "sceKernelCancelFpl"},
|
||||
{0xD8199E4C,WrapI_IU<sceKernelReferFplStatus>, "sceKernelReferFplStatus"},
|
||||
|
||||
{0x20fff560,WrapU_CU<sceKernelCreateVTimer>,"sceKernelCreateVTimer"},
|
||||
{0x328F9E52,WrapU_U<sceKernelDeleteVTimer>,"sceKernelDeleteVTimer"},
|
||||
@@ -820,6 +838,13 @@ const HLEFunction ThreadManForUser[] =
|
||||
// {0x6E9EA350, _sceKernelReturnFromCallback,"_sceKernelReturnFromCallback"},
|
||||
};
|
||||
|
||||
const HLEFunction ThreadManForKernel[] =
|
||||
{
|
||||
{0xceadeb47, WrapI_U<ThreadManForKernel_ceadeb47>, "ThreadManForKernel_ceadeb47"},
|
||||
{0x446d8de6, WrapI_CUUIUU<ThreadManForKernel_446d8de6>, "ThreadManForKernel_446d8de6"},//Not sure right
|
||||
{0xf475845d, &WrapI_IIU<ThreadManForKernel_f475845d>, "ThreadManForKernel_f475845d"},//Not sure right
|
||||
};
|
||||
|
||||
void Register_ThreadManForUser()
|
||||
{
|
||||
RegisterModule("ThreadManForUser", ARRAY_SIZE(ThreadManForUser), ThreadManForUser);
|
||||
@@ -841,8 +866,6 @@ void Register_LoadExecForUser()
|
||||
RegisterModule("LoadExecForUser", ARRAY_SIZE(LoadExecForUser), LoadExecForUser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const HLEFunction ExceptionManagerForKernel[] =
|
||||
{
|
||||
{0x3FB264FC, 0, "sceKernelRegisterExceptionHandler"},
|
||||
@@ -888,3 +911,9 @@ void Register_UtilsForKernel()
|
||||
{
|
||||
RegisterModule("UtilsForKernel", ARRAY_SIZE(UtilsForKernel), UtilsForKernel);
|
||||
}
|
||||
|
||||
void Register_ThreadManForKernel()
|
||||
{
|
||||
RegisterModule("ThreadManForKernel", ARRAY_SIZE(ThreadManForKernel), ThreadManForKernel);
|
||||
|
||||
}
|
||||
@@ -557,5 +557,6 @@ extern KernelStats kernelStats;
|
||||
extern u32 registeredExitCbId;
|
||||
|
||||
void Register_ThreadManForUser();
|
||||
void Register_ThreadManForKernel();
|
||||
void Register_LoadExecForUser();
|
||||
void Register_UtilsForKernel();
|
||||
@@ -324,7 +324,11 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateEventFlag(\"%s\", %08x, %08x, %08x)", id, e->nef.name, e->nef.attr, e->nef.currentPattern, optPtr);
|
||||
|
||||
if (optPtr != 0)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateEventFlag(%s) unsupported options parameter: %08x", name, optPtr);
|
||||
{
|
||||
u32 size = Memory::Read_U32(optPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size);
|
||||
}
|
||||
if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr);
|
||||
|
||||
@@ -654,7 +658,7 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr)
|
||||
// Can't wait on 0, it never matches.
|
||||
if (bits == 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x): bad pattern", id, bits, wait, outBitsPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x): bad pattern", id, bits, wait, outBitsPtr);
|
||||
return SCE_KERNEL_ERROR_EVF_ILPAT;
|
||||
}
|
||||
|
||||
@@ -669,23 +673,23 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr)
|
||||
|
||||
if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr);
|
||||
return SCE_KERNEL_ERROR_EVF_MULTI;
|
||||
}
|
||||
|
||||
// No match - return that, this is polling, not waiting.
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_COND=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_COND=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr);
|
||||
return SCE_KERNEL_ERROR_EVF_COND;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "0=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
|
||||
DEBUG_LOG(HLE, "0=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x): invalid event flag", id, bits, wait, outBitsPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x): invalid event flag", id, bits, wait, outBitsPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ void sceKernelCpuResumeIntr(u32 enable)
|
||||
{
|
||||
__EnableInterrupts();
|
||||
hleRunInterrupts();
|
||||
hleReSchedule("interrupts resumed");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -165,7 +166,7 @@ void IntrHandler::enable(int subIntrNum)
|
||||
}
|
||||
void IntrHandler::disable(int subIntrNum)
|
||||
{
|
||||
subIntrHandlers[subIntrNum].enabled = true;
|
||||
subIntrHandlers[subIntrNum].enabled = false;
|
||||
}
|
||||
SubIntrHandler* IntrHandler::get(int subIntrNum)
|
||||
{
|
||||
@@ -407,9 +408,9 @@ void __KernelReturnFromInterrupt()
|
||||
{
|
||||
// Otherwise, we reschedule when dispatch was enabled, or switch back otherwise.
|
||||
if (__KernelIsDispatchEnabled())
|
||||
__KernelReSchedule("return from interrupt");
|
||||
__KernelReSchedule("left interrupt");
|
||||
else
|
||||
__KernelSwitchToThread(threadBeforeInterrupt, "return from interrupt");
|
||||
__KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,8 +575,8 @@ const HLEFunction Kernel_Library[] =
|
||||
{0xa089eca4,WrapU_UUU<sceKernelMemset>, "sceKernelMemset"},
|
||||
{0xDC692EE3,WrapI_UI<sceKernelTryLockLwMutex>, "sceKernelTryLockLwMutex"},
|
||||
{0x37431849,WrapI_UI<sceKernelTryLockLwMutex_600>, "sceKernelTryLockLwMutex_600"},
|
||||
{0xbea46419,WrapI_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x1FC64E09,WrapI_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB", HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xbea46419,WrapI_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x1FC64E09,WrapI_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x15b6446b,WrapI_UI<sceKernelUnlockLwMutex>, "sceKernelUnlockLwMutex"},
|
||||
{0xc1734599,WrapI_UU<sceKernelReferLwMutexStatus>, "sceKernelReferLwMutexStatus"},
|
||||
{0x293b45b8,WrapI_V<sceKernelGetThreadId>, "sceKernelGetThreadId"},
|
||||
|
||||
@@ -316,7 +316,11 @@ SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr)
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateMbx(%s, %08x, %08x)", id, name, attr, optAddr);
|
||||
|
||||
if (optAddr != 0)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateMbx(%s) unsupported options parameter: %08x", name, optAddr);
|
||||
{
|
||||
u32 size = Memory::Read_U32(optAddr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateMbx(%s) unsupported options parameter, size = %d", name, size);
|
||||
}
|
||||
if ((attr & ~SCE_KERNEL_MBA_ATTR_KNOWN) != 0)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateMbx(%s) unsupported attr parameter: %08x", name, attr);
|
||||
|
||||
|
||||
+379
-111
@@ -17,16 +17,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include "HLE.h"
|
||||
#include "../System.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../MemMap.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelMemory.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
|
||||
const int TLS_NUM_INDEXES = 16;
|
||||
|
||||
@@ -36,6 +37,7 @@ BlockAllocator userMemory(256);
|
||||
BlockAllocator kernelMemory(256);
|
||||
|
||||
static int vplWaitTimer = -1;
|
||||
static int fplWaitTimer = -1;
|
||||
static bool tlsUsedIndexes[TLS_NUM_INDEXES];
|
||||
// STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -47,11 +49,16 @@ int flags_ = 0;
|
||||
int sdkVersion_;
|
||||
int compilerVersion_;
|
||||
|
||||
struct FplWaitingThread
|
||||
{
|
||||
SceUID threadID;
|
||||
u32 addrPtr;
|
||||
};
|
||||
|
||||
struct NativeFPL
|
||||
{
|
||||
u32_le size;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
SceUID_le mpid;
|
||||
u32_le attr;
|
||||
|
||||
s32_le blocksize;
|
||||
@@ -63,7 +70,7 @@ struct NativeFPL
|
||||
//FPL - Fixed Length Dynamic Memory Pool - every item has the same length
|
||||
struct FPL : public KernelObject
|
||||
{
|
||||
FPL() : blocks(NULL) {}
|
||||
FPL() : blocks(NULL), nextBlock(0) {}
|
||||
~FPL() {
|
||||
if (blocks != NULL) {
|
||||
delete [] blocks;
|
||||
@@ -77,8 +84,10 @@ struct FPL : public KernelObject
|
||||
|
||||
int findFreeBlock() {
|
||||
for (int i = 0; i < nf.numBlocks; i++) {
|
||||
if (!blocks[i])
|
||||
return i;
|
||||
int b = nextBlock++ % nf.numBlocks;
|
||||
if (!blocks[b]) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -105,12 +114,19 @@ struct FPL : public KernelObject
|
||||
blocks = new bool[nf.numBlocks];
|
||||
p.DoArray(blocks, nf.numBlocks);
|
||||
p.Do(address);
|
||||
p.Do(alignedSize);
|
||||
p.Do(nextBlock);
|
||||
FplWaitingThread dv = {0};
|
||||
p.Do(waitingThreads, dv);
|
||||
p.DoMarker("FPL");
|
||||
}
|
||||
|
||||
NativeFPL nf;
|
||||
bool *blocks;
|
||||
u32 address;
|
||||
int alignedSize;
|
||||
int nextBlock;
|
||||
std::vector<FplWaitingThread> waitingThreads;
|
||||
};
|
||||
|
||||
struct VplWaitingThread
|
||||
@@ -156,6 +172,7 @@ struct VPL : public KernelObject
|
||||
};
|
||||
|
||||
void __KernelVplTimeout(u64 userdata, int cyclesLate);
|
||||
void __KernelFplTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
void __KernelMemoryInit()
|
||||
{
|
||||
@@ -164,6 +181,7 @@ void __KernelMemoryInit()
|
||||
INFO_LOG(HLE, "Kernel and user memory pools initialized");
|
||||
|
||||
vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout);
|
||||
fplWaitTimer = CoreTiming::RegisterEvent("FplTimeout", __KernelFplTimeout);
|
||||
|
||||
flags_ = 0;
|
||||
sdkVersion_ = 0;
|
||||
@@ -178,6 +196,8 @@ void __KernelMemoryDoState(PointerWrap &p)
|
||||
|
||||
p.Do(vplWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout);
|
||||
p.Do(fplWaitTimer);
|
||||
CoreTiming::RestoreRegisterEvent(fplWaitTimer, "FplTimeout", __KernelFplTimeout);
|
||||
p.Do(flags_);
|
||||
p.Do(sdkVersion_);
|
||||
p.Do(compilerVersion_);
|
||||
@@ -195,209 +215,428 @@ void __KernelMemoryShutdown()
|
||||
kernelMemory.Shutdown();
|
||||
}
|
||||
|
||||
//sceKernelCreateFpl(const char *name, SceUID mpid, SceUint attr, SceSize blocksize, int numBlocks, optparam)
|
||||
void sceKernelCreateFpl()
|
||||
enum SceKernelFplAttr
|
||||
{
|
||||
const char *name = Memory::GetCharPointer(PARAM(0));
|
||||
PSP_FPL_ATTR_FIFO = 0x0000,
|
||||
PSP_FPL_ATTR_PRIORITY = 0x0100,
|
||||
PSP_FPL_ATTR_HIGHMEM = 0x4000,
|
||||
PSP_FPL_ATTR_KNOWN = PSP_FPL_ATTR_FIFO | PSP_FPL_ATTR_PRIORITY | PSP_FPL_ATTR_HIGHMEM,
|
||||
};
|
||||
|
||||
u32 mpid = PARAM(1);
|
||||
u32 attr = PARAM(2);
|
||||
u32 blockSize = PARAM(3);
|
||||
u32 numBlocks = PARAM(4);
|
||||
bool __KernelUnlockFplForThread(FPL *fpl, FplWaitingThread &threadInfo, u32 &error, int result, bool &wokeThreads)
|
||||
{
|
||||
const SceUID threadID = threadInfo.threadID;
|
||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_FPL, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
|
||||
u32 totalSize = blockSize * numBlocks;
|
||||
// The waitID may be different after a timeout.
|
||||
if (waitID != fpl->GetUID())
|
||||
return true;
|
||||
|
||||
bool atEnd = false; // attr can change this I think
|
||||
// If result is an error code, we're just letting it go.
|
||||
if (result == 0)
|
||||
{
|
||||
int blockNum = fpl->allocateBlock();
|
||||
if (blockNum >= 0)
|
||||
{
|
||||
u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
|
||||
Memory::Write_U32(blockPtr, threadInfo.addrPtr);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timeoutPtr != 0 && fplWaitTimer != -1)
|
||||
{
|
||||
// Remove any event for this thread.
|
||||
s64 cyclesLeft = CoreTiming::UnscheduleEvent(fplWaitTimer, threadID);
|
||||
Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
wokeThreads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void __KernelFplRemoveThread(FPL *fpl, SceUID threadID)
|
||||
{
|
||||
for (size_t i = 0; i < fpl->waitingThreads.size(); i++)
|
||||
{
|
||||
FplWaitingThread *t = &fpl->waitingThreads[i];
|
||||
if (t->threadID == threadID)
|
||||
{
|
||||
fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2)
|
||||
{
|
||||
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
|
||||
}
|
||||
|
||||
bool __KernelClearFplThreads(FPL *fpl, int reason)
|
||||
{
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (auto iter = fpl->waitingThreads.begin(), end = fpl->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockFplForThread(fpl, *iter, error, reason, wokeThreads);
|
||||
fpl->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
void __KernelSortFplThreads(FPL *fpl)
|
||||
{
|
||||
// Remove any that are no longer waiting.
|
||||
u32 error;
|
||||
SceUID uid = fpl->GetUID();
|
||||
for (size_t i = 0; i < fpl->waitingThreads.size(); i++)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(fpl->waitingThreads[i].threadID, WAITTYPE_FPL, error);
|
||||
if (waitID != uid)
|
||||
{
|
||||
fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((fpl->nf.attr & PSP_FPL_ATTR_PRIORITY) != 0)
|
||||
std::stable_sort(fpl->waitingThreads.begin(), fpl->waitingThreads.end(), __FplThreadSortPriority);
|
||||
}
|
||||
|
||||
int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 numBlocks, u32 optPtr)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid name", SCE_KERNEL_ERROR_NO_MEMORY);
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (mpid < 1 || mpid > 9 || mpid == 7)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, mpid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
// We only support user right now.
|
||||
if (mpid != 2 && mpid != 6)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_PERM, mpid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_PERM;
|
||||
}
|
||||
if (((attr & ~PSP_FPL_ATTR_KNOWN) & ~0xFF) != 0)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
|
||||
}
|
||||
// There's probably a simpler way to get this same basic formula...
|
||||
// This is based on results from a PSP.
|
||||
bool illegalMemSize = blockSize == 0 || numBlocks == 0;
|
||||
if (!illegalMemSize && (u64) blockSize > ((0x100000000ULL / (u64) numBlocks) - 4ULL))
|
||||
illegalMemSize = true;
|
||||
if (!illegalMemSize && (u64) numBlocks >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL))
|
||||
illegalMemSize = true;
|
||||
if (illegalMemSize)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid blockSize/count", SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
|
||||
}
|
||||
|
||||
int alignment = 4;
|
||||
if (optPtr != 0)
|
||||
{
|
||||
u32 size = Memory::Read_U32(optPtr);
|
||||
if (size > 8)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateFpl(): unsupported extra options, size = %d", size);
|
||||
if (size >= 4)
|
||||
alignment = Memory::Read_U32(optPtr + 4);
|
||||
// Must be a power of 2 to be valid.
|
||||
if ((alignment & (alignment - 1)) != 0)
|
||||
{
|
||||
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateFpl(): invalid alignment %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, alignment);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (alignment < 4)
|
||||
alignment = 4;
|
||||
|
||||
int alignedSize = ((int)blockSize + alignment - 1) & ~(alignment - 1);
|
||||
u32 totalSize = alignedSize * numBlocks;
|
||||
bool atEnd = (attr & PSP_FPL_ATTR_HIGHMEM) != 0;
|
||||
u32 address = userMemory.Alloc(totalSize, atEnd, "FPL");
|
||||
if (address == (u32)-1)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelCreateFpl(\"%s\", partition=%i, attr=%i, bsize=%i, nb=%i) FAILED - out of ram",
|
||||
DEBUG_LOG(HLE, "sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i) FAILED - out of ram",
|
||||
name, mpid, attr, blockSize, numBlocks);
|
||||
RETURN(SCE_KERNEL_ERROR_NO_MEMORY);
|
||||
return;
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
FPL *fpl = new FPL;
|
||||
SceUID id = kernelObjects.Create(fpl);
|
||||
strncpy(fpl->nf.name, name, 32);
|
||||
|
||||
fpl->nf.size = sizeof(fpl->nf);
|
||||
fpl->nf.mpid = mpid; // partition
|
||||
strncpy(fpl->nf.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
fpl->nf.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
fpl->nf.attr = attr;
|
||||
fpl->nf.size = sizeof(fpl->nf);
|
||||
fpl->nf.blocksize = blockSize;
|
||||
fpl->nf.numBlocks = numBlocks;
|
||||
fpl->nf.numFreeBlocks = numBlocks;
|
||||
fpl->nf.numWaitThreads = 0;
|
||||
|
||||
fpl->blocks = new bool[fpl->nf.numBlocks];
|
||||
memset(fpl->blocks, 0, fpl->nf.numBlocks * sizeof(bool));
|
||||
fpl->address = address;
|
||||
fpl->alignedSize = alignedSize;
|
||||
|
||||
DEBUG_LOG(HLE,"%i=sceKernelCreateFpl(\"%s\", partition=%i, attr=%i, bsize=%i, nb=%i)",
|
||||
DEBUG_LOG(HLE, "%i=sceKernelCreateFpl(\"%s\", partition=%i, attr=%08x, bsize=%i, nb=%i)",
|
||||
id, name, mpid, attr, blockSize, numBlocks);
|
||||
|
||||
RETURN(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
void sceKernelDeleteFpl()
|
||||
int sceKernelDeleteFpl(SceUID uid)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteFpl(%i)", uid);
|
||||
|
||||
bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("fpl deleted");
|
||||
|
||||
userMemory.Free(fpl->address);
|
||||
DEBUG_LOG(HLE,"sceKernelDeleteFpl(%i)", id);
|
||||
RETURN(kernelObjects.Destroy<FPL>(id));
|
||||
return kernelObjects.Destroy<FPL>(uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteFpl(%i): invalid fpl", uid);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelAllocateFpl()
|
||||
void __KernelFplTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
SceUID threadID = (SceUID) userdata;
|
||||
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (timeoutPtr != 0)
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_FPL, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
u32 blockPtrAddr = PARAM(1);
|
||||
int timeOut = PARAM(2);
|
||||
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
|
||||
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
|
||||
// actually running, it will get a DELETE result instead of a TIMEOUT.
|
||||
// So, we need to remember it or we won't be able to mark it DELETE instead later.
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelSetFplTimeout(u32 timeoutPtr)
|
||||
{
|
||||
if (timeoutPtr == 0 || fplWaitTimer == -1)
|
||||
return;
|
||||
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// TODO: test for fpls.
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 5)
|
||||
micro = 10;
|
||||
// Yes, this 7 is reproducible. 6 is (a lot) longer than 7.
|
||||
else if (micro == 7)
|
||||
micro = 15;
|
||||
else if (micro <= 215)
|
||||
micro = 250;
|
||||
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), fplWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelAllocateFpl(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr);
|
||||
|
||||
int blockNum = fpl->allocateBlock();
|
||||
if (blockNum >= 0) {
|
||||
u32 blockPtr = fpl->address + fpl->nf.blocksize * blockNum;
|
||||
u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
|
||||
Memory::Write_U32(blockPtr, blockPtrAddr);
|
||||
RETURN(0);
|
||||
} else {
|
||||
// TODO: Should block!
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelAllocateFpl: should block");
|
||||
RETURN(0);
|
||||
SceUID threadID = __KernelGetCurThread();
|
||||
__KernelFplRemoveThread(fpl, threadID);
|
||||
FplWaitingThread waiting = {threadID, blockPtrAddr};
|
||||
fpl->waitingThreads.push_back(waiting);
|
||||
|
||||
__KernelSetFplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, false, "fpl waited");
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateFpl(%i, %08x, %i)", id, blockPtrAddr, timeOut);
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"ERROR: sceKernelAllocateFpl(%i)", id);
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelAllocateFpl(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelAllocateFplCB()
|
||||
int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
u32 blockPtrAddr = PARAM(1);
|
||||
int timeOut = PARAM(2);
|
||||
DEBUG_LOG(HLE, "sceKernelAllocateFplCB(%i, %08x, %08x)", uid, blockPtrAddr, timeoutPtr);
|
||||
|
||||
int blockNum = fpl->allocateBlock();
|
||||
if (blockNum >= 0) {
|
||||
u32 blockPtr = fpl->address + fpl->nf.blocksize * blockNum;
|
||||
u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
|
||||
Memory::Write_U32(blockPtr, blockPtrAddr);
|
||||
RETURN(0);
|
||||
} else {
|
||||
// TODO: Should block and process callbacks!
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelAllocateFplCB: should block");
|
||||
__KernelCheckCallbacks();
|
||||
SceUID threadID = __KernelGetCurThread();
|
||||
__KernelFplRemoveThread(fpl, threadID);
|
||||
FplWaitingThread waiting = {threadID, blockPtrAddr};
|
||||
fpl->waitingThreads.push_back(waiting);
|
||||
|
||||
__KernelSetFplTimeout(timeoutPtr);
|
||||
__KernelWaitCurThread(WAITTYPE_FPL, uid, 0, timeoutPtr, true, "fpl waited");
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"sceKernelAllocateFpl(%i, %08x, %i)", id, PARAM(1), timeOut);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"ERROR: sceKernelAllocateFplCB(%i)", id);
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelAllocateFplCB(%i, %08x, %08x): invalid fpl", uid, blockPtrAddr, timeoutPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelTryAllocateFpl()
|
||||
int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
u32 blockPtrAddr = PARAM(1);
|
||||
DEBUG_LOG(HLE,"sceKernelTryAllocateFpl(%i, %08x)", id, PARAM(1));
|
||||
DEBUG_LOG(HLE, "sceKernelTryAllocateFpl(%i, %08x)", uid, blockPtrAddr);
|
||||
|
||||
int blockNum = fpl->allocateBlock();
|
||||
if (blockNum >= 0) {
|
||||
u32 blockPtr = fpl->address + fpl->nf.blocksize * blockNum;
|
||||
u32 blockPtr = fpl->address + fpl->alignedSize * blockNum;
|
||||
Memory::Write_U32(blockPtr, blockPtrAddr);
|
||||
RETURN(0);
|
||||
return 0;
|
||||
} else {
|
||||
RETURN(SCE_KERNEL_ERROR_NO_MEMORY);
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelTryAllocateFpl(%i) - bad UID", id);
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelTryAllocateFpl(%i, %08x): invalid fpl", uid, blockPtrAddr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelFreeFpl()
|
||||
int sceKernelFreeFpl(SceUID uid, u32 blockPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
u32 blockAddr = PARAM(1);
|
||||
if (blockPtr > PSP_GetUserMemoryEnd()) {
|
||||
WARN_LOG(HLE, "%08x=sceKernelFreeFpl(%i, %08x): invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, blockPtr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE,"sceKernelFreeFpl(%i, %08x)", id, blockAddr);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl) {
|
||||
int blockNum = (blockAddr - fpl->address) / fpl->nf.blocksize;
|
||||
int blockNum = (blockPtr - fpl->address) / fpl->alignedSize;
|
||||
if (blockNum < 0 || blockNum >= fpl->nf.numBlocks) {
|
||||
RETURN(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK);
|
||||
DEBUG_LOG(HLE, "sceKernelFreeFpl(%i, %08x): bad block ptr", uid, blockPtr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK;
|
||||
} else {
|
||||
if (fpl->freeBlock(blockNum)) {
|
||||
// TODO: If there are waiting threads, wake them up
|
||||
DEBUG_LOG(HLE, "sceKernelFreeFpl(%i, %08x)", uid, blockPtr);
|
||||
__KernelSortFplThreads(fpl);
|
||||
|
||||
bool wokeThreads = false;
|
||||
retry:
|
||||
for (auto iter = fpl->waitingThreads.begin(), end = fpl->waitingThreads.end(); iter != end; ++iter)
|
||||
{
|
||||
if (__KernelUnlockFplForThread(fpl, *iter, error, 0, wokeThreads))
|
||||
{
|
||||
fpl->waitingThreads.erase(iter);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("fpl freed");
|
||||
return 0;
|
||||
} else {
|
||||
DEBUG_LOG(HLE, "sceKernelFreeFpl(%i, %08x): already free", uid, blockPtr);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK;
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelFreeFpl(%i, %08x): invalid fpl", uid, blockPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelCancelFpl()
|
||||
int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
DEBUG_LOG(HLE,"UNIMPL: sceKernelCancelFpl(%i)", id);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
RETURN(0);
|
||||
DEBUG_LOG(HLE, "sceKernelCancelFpl(%i, %08x)", uid, numWaitThreadsPtr);
|
||||
fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size();
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr);
|
||||
|
||||
bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_CANCEL);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("fpl canceled");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelCancelFpl(%i, %08x): invalid fpl", uid, numWaitThreadsPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
void sceKernelReferFplStatus()
|
||||
int sceKernelReferFplStatus(SceUID uid, u32 statusPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
u32 statusAddr = PARAM(1);
|
||||
DEBUG_LOG(HLE,"sceKernelReferFplStatus(%i, %08x)", id, statusAddr);
|
||||
u32 error;
|
||||
FPL *fpl = kernelObjects.Get<FPL>(id, error);
|
||||
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
|
||||
if (fpl)
|
||||
{
|
||||
Memory::WriteStruct(statusAddr, &fpl->nf);
|
||||
RETURN(0);
|
||||
DEBUG_LOG(HLE, "sceKernelReferFplStatus(%i, %08x)", uid, statusPtr);
|
||||
// Refresh waiting threads and free block count.
|
||||
__KernelSortFplThreads(fpl);
|
||||
fpl->nf.numWaitThreads = (int) fpl->waitingThreads.size();
|
||||
fpl->nf.numFreeBlocks = 0;
|
||||
for (int i = 0; i < (int)fpl->nf.numBlocks; ++i)
|
||||
{
|
||||
if (!fpl->blocks[i])
|
||||
++fpl->nf.numFreeBlocks;
|
||||
}
|
||||
if (Memory::Read_U32(statusPtr) != 0)
|
||||
Memory::WriteStruct(statusPtr, &fpl->nf);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN(error);
|
||||
DEBUG_LOG(HLE, "sceKernelReferFplStatus(%i, %08x): invalid fpl", uid, statusPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,6 +1176,25 @@ bool __KernelClearVplThreads(VPL *vpl, int reason)
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
void __KernelSortFplThreads(VPL *vpl)
|
||||
{
|
||||
// Remove any that are no longer waiting.
|
||||
u32 error;
|
||||
SceUID uid = vpl->GetUID();
|
||||
for (size_t i = 0; i < vpl->waitingThreads.size(); i++)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(vpl->waitingThreads[i].threadID, WAITTYPE_VPL, error);
|
||||
if (waitID != uid)
|
||||
{
|
||||
vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0)
|
||||
std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority);
|
||||
}
|
||||
|
||||
SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr)
|
||||
{
|
||||
if (!name)
|
||||
@@ -982,7 +1240,7 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize
|
||||
u32 memBlockPtr = userMemory.Alloc(allocSize, (attr & PSP_VPL_ATTR_HIGHMEM) != 0, "VPL");
|
||||
if (memBlockPtr == (u32)-1)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelCreateVpl: Failed to allocate %i bytes of pool data", vplSize);
|
||||
ERROR_LOG(HLE, "sceKernelCreateVpl(): Failed to allocate %i bytes of pool data", vplSize);
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
@@ -1004,6 +1262,15 @@ SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize
|
||||
DEBUG_LOG(HLE, "%x=sceKernelCreateVpl(\"%s\", block=%i, attr=%i, size=%i)",
|
||||
id, name, partition, vpl->nv.attr, vpl->nv.poolSize);
|
||||
|
||||
if (optPtr != 0)
|
||||
{
|
||||
u32 size = Memory::Read_U32(optPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateVpl(): unsupported options parameter, size = %d", size);
|
||||
}
|
||||
if (attr & PSP_VPL_ATTR_SMALLEST)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateVpl(): unsupported SMALLEST wake priority attr");
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -1133,8 +1400,6 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
|
||||
{
|
||||
if (vpl)
|
||||
{
|
||||
vpl->nv.numWaitThreads++;
|
||||
|
||||
SceUID threadID = __KernelGetCurThread();
|
||||
__KernelVplRemoveThread(vpl, threadID);
|
||||
VplWaitingThread waiting = {threadID, addrPtr};
|
||||
@@ -1170,8 +1435,7 @@ int sceKernelFreeVpl(SceUID uid, u32 addr)
|
||||
{
|
||||
if (vpl->alloc.FreeExact(addr))
|
||||
{
|
||||
if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0)
|
||||
std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority);
|
||||
__KernelSortFplThreads(vpl);
|
||||
|
||||
bool wokeThreads = false;
|
||||
retry:
|
||||
@@ -1201,11 +1465,11 @@ retry:
|
||||
|
||||
int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelVpl(%i, %08x)", uid, numWaitThreadsPtr);
|
||||
u32 error;
|
||||
VPL *vpl = kernelObjects.Get<VPL>(uid, error);
|
||||
if (vpl)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelVpl(%i, %08x)", uid, numWaitThreadsPtr);
|
||||
vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size();
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr);
|
||||
@@ -1217,7 +1481,10 @@ int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelVpl(%i, %08x): invalid vpl", uid, numWaitThreadsPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelReferVplStatus(SceUID uid, u32 infoPtr)
|
||||
@@ -1228,14 +1495,7 @@ int sceKernelReferVplStatus(SceUID uid, u32 infoPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReferVplStatus(%i, %08x)", uid, infoPtr);
|
||||
|
||||
for (auto iter = vpl->waitingThreads.begin(); iter != vpl->waitingThreads.end(); ++iter)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(iter->threadID, WAITTYPE_VPL, error);
|
||||
// The thread is no longer waiting for this, clean it up.
|
||||
if (waitID != uid)
|
||||
vpl->waitingThreads.erase(iter--);
|
||||
}
|
||||
|
||||
__KernelSortFplThreads(vpl);
|
||||
vpl->nv.numWaitThreads = (int) vpl->waitingThreads.size();
|
||||
vpl->nv.freeSize = vpl->alloc.GetTotalFreeBytes();
|
||||
if (Memory::IsValidAddress(infoPtr) && Memory::Read_U32(infoPtr))
|
||||
@@ -1441,9 +1701,13 @@ SceUID sceKernelCreateTls(const char *name, u32 partition, u32 attr, u32 blockSi
|
||||
|
||||
// TODO: just alignment?
|
||||
if (optionsPtr != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateTls(%s) unsupported options parameter: %08x", name, optionsPtr);
|
||||
{
|
||||
u32 size = Memory::Read_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateTls(%s) unsupported options parameter, size = %d", name, size);
|
||||
}
|
||||
if ((attr & PSP_TLS_ATTR_PRIORITY) != 0)
|
||||
WARN_LOG(HLE, "sceKernelCreateTls(%s) unsupported attr parameter: %08x", name, attr);
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateTls(%s) unsupported attr parameter: %08x", name, attr);
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -1468,6 +1732,10 @@ int sceKernelAllocateTls(SceUID uid)
|
||||
{
|
||||
// TODO: Allocate downward if PSP_TLS_ATTR_HIGHMEM?
|
||||
DEBUG_LOG(HLE, "sceKernelAllocateTls(%08x)", uid);
|
||||
|
||||
if (!__KernelIsDispatchEnabled() || __IsInInterrupt())
|
||||
return 0;
|
||||
|
||||
u32 error;
|
||||
TLS *tls = kernelObjects.Get<TLS>(uid, error);
|
||||
if (tls)
|
||||
|
||||
@@ -46,14 +46,14 @@ int sceKernelFreeVpl(SceUID uid, u32 addr);
|
||||
int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr);
|
||||
int sceKernelReferVplStatus(SceUID uid, u32 infoPtr);
|
||||
|
||||
void sceKernelCreateFpl();
|
||||
void sceKernelDeleteFpl();
|
||||
void sceKernelAllocateFpl();
|
||||
void sceKernelAllocateFplCB();
|
||||
void sceKernelTryAllocateFpl();
|
||||
void sceKernelFreeFpl();
|
||||
void sceKernelCancelFpl();
|
||||
void sceKernelReferFplStatus();
|
||||
int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blocksize, u32 numBlocks, u32 optPtr);
|
||||
int sceKernelDeleteFpl(SceUID uid);
|
||||
int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr);
|
||||
int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr);
|
||||
int sceKernelTryAllocateFpl(SceUID uid, u32 blockPtrAddr);
|
||||
int sceKernelFreeFpl(SceUID uid, u32 blockPtr);
|
||||
int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr);
|
||||
int sceKernelReferFplStatus(SceUID uid, u32 statusPtr);
|
||||
|
||||
int sceKernelGetCompiledSdkVersion();
|
||||
|
||||
|
||||
+383
-92
@@ -17,33 +17,34 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
#include "native/base/stringutil.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/HLETables.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "../Host.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/ELF/ElfReader.h"
|
||||
#include "Core/ELF/PBPReader.h"
|
||||
#include "Core/ELF/PrxDecrypter.h"
|
||||
#include "../Debugger/SymbolMap.h"
|
||||
#include "../FileSystems/FileSystem.h"
|
||||
#include "../FileSystems/MetaFileSystem.h"
|
||||
#include "../Util/BlockAllocator.h"
|
||||
#include "Core/FileSystems/FileSystem.h"
|
||||
#include "Core/FileSystems/MetaFileSystem.h"
|
||||
#include "Core/Util/BlockAllocator.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/PSPLoaders.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
|
||||
#include "sceKernel.h"
|
||||
#include "sceKernelModule.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "sceKernelMemory.h"
|
||||
#include "sceIo.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelModule.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceIo.h"
|
||||
|
||||
enum {
|
||||
PSP_THREAD_ATTR_USER = 0x80000000
|
||||
@@ -69,6 +70,7 @@ enum {
|
||||
static const char *lieAboutSuccessModules[] = {
|
||||
"flash0:/kd/audiocodec.prx",
|
||||
"flash0:/kd/libatrac3plus.prx",
|
||||
"disc0:/PSP_GAME/SYSDIR/UPDATE/EBOOT.BIN",
|
||||
};
|
||||
|
||||
static const char *blacklistedModules[] = {
|
||||
@@ -89,13 +91,47 @@ static const char *blacklistedModules[] = {
|
||||
"sceSsl_Module",
|
||||
};
|
||||
|
||||
struct VarSymbol {
|
||||
char moduleName[32];
|
||||
u32 symAddr;
|
||||
struct VarSymbolImport {
|
||||
char moduleName[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
u32 nid;
|
||||
u32 stubAddr;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
struct VarSymbolExport {
|
||||
bool Matches(const VarSymbolImport &other) const {
|
||||
return !strncmp(moduleName, other.moduleName, KERNELOBJECT_MAX_NAME_LENGTH) && nid == other.nid;
|
||||
}
|
||||
|
||||
char moduleName[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
u32 nid;
|
||||
u32 symAddr;
|
||||
};
|
||||
|
||||
struct FuncSymbolImport {
|
||||
char moduleName[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
u32 stubAddr;
|
||||
u32 nid;
|
||||
};
|
||||
|
||||
struct FuncSymbolExport {
|
||||
bool Matches(const FuncSymbolImport &other) const {
|
||||
return !strncmp(moduleName, other.moduleName, KERNELOBJECT_MAX_NAME_LENGTH) && nid == other.nid;
|
||||
}
|
||||
|
||||
char moduleName[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
u32 symAddr;
|
||||
u32 nid;
|
||||
};
|
||||
|
||||
void ImportVarSymbol(const VarSymbolImport &var);
|
||||
void ExportVarSymbol(const VarSymbolExport &var);
|
||||
void UnexportVarSymbol(const VarSymbolExport &var);
|
||||
|
||||
void ImportFuncSymbol(const FuncSymbolImport &func);
|
||||
void ExportFuncSymbol(const FuncSymbolExport &func);
|
||||
void UnexportFuncSymbol(const FuncSymbolExport &func);
|
||||
|
||||
struct NativeModule {
|
||||
u32_le next;
|
||||
u16_le attribute;
|
||||
@@ -191,12 +227,87 @@ public:
|
||||
p.Do(isStarted);
|
||||
ModuleWaitingThread mwt = {0};
|
||||
p.Do(waitingThreads, mwt);
|
||||
FuncSymbolExport fsx = {0};
|
||||
p.Do(exportedFuncs, fsx);
|
||||
FuncSymbolImport fsi = {0};
|
||||
p.Do(importedFuncs, fsi);
|
||||
VarSymbolExport vsx = {0};
|
||||
p.Do(exportedVars, vsx);
|
||||
VarSymbolImport vsi = {0};
|
||||
p.Do(importedVars, vsi);
|
||||
RebuildImpExpModuleNames();
|
||||
p.DoMarker("Module");
|
||||
}
|
||||
|
||||
// We don't do this in the destructor to avoid annoying messages on game shutdown.
|
||||
void Cleanup();
|
||||
|
||||
void ImportFunc(const FuncSymbolImport &func) {
|
||||
if (!Memory::IsValidAddress(func.stubAddr)) {
|
||||
WARN_LOG_REPORT(LOADER, "Invalid address for syscall stub %s %08x", func.moduleName, func.nid);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOADER, "Importing %s : %08x", GetFuncName(func.moduleName, func.nid), func.stubAddr);
|
||||
|
||||
// Add the symbol to the symbol map for debugging.
|
||||
char temp[256];
|
||||
sprintf(temp,"zz_%s", GetFuncName(func.moduleName, func.nid));
|
||||
symbolMap.AddSymbol(temp, func.stubAddr, 8, ST_FUNCTION);
|
||||
|
||||
// Keep track and actually hook it up if possible.
|
||||
importedFuncs.push_back(func);
|
||||
impExpModuleNames.insert(func.moduleName);
|
||||
ImportFuncSymbol(func);
|
||||
}
|
||||
|
||||
void ImportVar(const VarSymbolImport &var) {
|
||||
// Keep track and actually hook it up if possible.
|
||||
importedVars.push_back(var);
|
||||
impExpModuleNames.insert(var.moduleName);
|
||||
ImportVarSymbol(var);
|
||||
}
|
||||
|
||||
void ExportFunc(const FuncSymbolExport &func) {
|
||||
exportedFuncs.push_back(func);
|
||||
impExpModuleNames.insert(func.moduleName);
|
||||
ExportFuncSymbol(func);
|
||||
}
|
||||
|
||||
void ExportVar(const VarSymbolExport &var) {
|
||||
exportedVars.push_back(var);
|
||||
impExpModuleNames.insert(var.moduleName);
|
||||
ExportVarSymbol(var);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RebuildImpExpList(const std::vector<T> &list) {
|
||||
for (size_t i = 0; i < list.size(); ++i) {
|
||||
impExpModuleNames.insert(list[i].moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
void RebuildImpExpModuleNames() {
|
||||
impExpModuleNames.clear();
|
||||
RebuildImpExpList(exportedFuncs);
|
||||
RebuildImpExpList(importedFuncs);
|
||||
RebuildImpExpList(exportedVars);
|
||||
RebuildImpExpList(importedVars);
|
||||
}
|
||||
|
||||
bool ImportsOrExportsModuleName(const std::string &moduleName) {
|
||||
return impExpModuleNames.find(moduleName) != impExpModuleNames.end();
|
||||
}
|
||||
|
||||
NativeModule nm;
|
||||
std::vector<ModuleWaitingThread> waitingThreads;
|
||||
|
||||
std::vector<FuncSymbolExport> exportedFuncs;
|
||||
std::vector<FuncSymbolImport> importedFuncs;
|
||||
std::vector<VarSymbolExport> exportedVars;
|
||||
std::vector<VarSymbolImport> importedVars;
|
||||
std::set<std::string> impExpModuleNames;
|
||||
|
||||
u32 memoryBlockAddr;
|
||||
u32 memoryBlockSize;
|
||||
bool isFake;
|
||||
@@ -263,8 +374,7 @@ struct SceKernelSMOption {
|
||||
// STATE BEGIN
|
||||
static int actionAfterModule;
|
||||
|
||||
static std::vector<VarSymbol> unresolvedVars;
|
||||
static std::vector<VarSymbol> exportedVars;
|
||||
static std::set<SceUID> loadedModules;
|
||||
// STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -277,16 +387,12 @@ void __KernelModuleDoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(actionAfterModule);
|
||||
__KernelRestoreActionType(actionAfterModule, AfterModuleEntryCall::Create);
|
||||
VarSymbol vs = {""};
|
||||
p.Do(unresolvedVars, vs);
|
||||
p.Do(exportedVars, vs);
|
||||
p.DoMarker("sceKernelModule");
|
||||
}
|
||||
|
||||
void __KernelModuleShutdown()
|
||||
{
|
||||
unresolvedVars.clear();
|
||||
exportedVars.clear();
|
||||
loadedModules.clear();
|
||||
MIPSAnalyst::Shutdown();
|
||||
}
|
||||
|
||||
@@ -298,14 +404,14 @@ struct HI16RelocInfo
|
||||
u32 addr;
|
||||
u32 data;
|
||||
};
|
||||
void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type)
|
||||
void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool reverse = false)
|
||||
{
|
||||
// We have to post-process the HI16 part, since it might be +1 or not depending on the LO16 value.
|
||||
static u32 lastHI16ExportAddress = 0;
|
||||
static std::vector<HI16RelocInfo> lastHI16Relocs;
|
||||
static bool lastHI16Processed = true;
|
||||
|
||||
u32 relocData = Memory::Read_Instruction(relocAddress);
|
||||
u32 relocData = Memory::Read_Instruction(relocAddress).encoding;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -314,24 +420,33 @@ void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type)
|
||||
break;
|
||||
|
||||
case R_MIPS_32:
|
||||
relocData += exportAddress;
|
||||
if (!reverse) {
|
||||
relocData += exportAddress;
|
||||
} else {
|
||||
relocData -= exportAddress;
|
||||
}
|
||||
break;
|
||||
|
||||
// Not really tested, but should work...
|
||||
/*
|
||||
case R_MIPS_26:
|
||||
if (exportAddress % 4 || (exportAddress >> 28) != ((relocAddress + 4) >> 28))
|
||||
if (exportAddress % 4 || (exportAddress >> 28) != ((relocAddress + 4) >> 28)) {
|
||||
WARN_LOG_REPORT(LOADER, "Bad var relocation addresses for type 26 - %08x => %08x", exportAddress, relocAddress)
|
||||
else
|
||||
relocData = (relocData & ~0x03ffffff) | ((relocData + (exportAddress >> 2)) & 0x03ffffff);
|
||||
} else {
|
||||
if (!reverse) {
|
||||
relocData = (relocData & ~0x03ffffff) | ((relocData + (exportAddress >> 2)) & 0x03ffffff);
|
||||
} else {
|
||||
relocData = (relocData & ~0x03ffffff) | ((relocData - (exportAddress >> 2)) & 0x03ffffff);
|
||||
}
|
||||
}
|
||||
break;
|
||||
*/
|
||||
|
||||
case R_MIPS_HI16:
|
||||
if (lastHI16ExportAddress != exportAddress)
|
||||
{
|
||||
if (!lastHI16Processed && lastHI16Relocs.size() >= 1)
|
||||
if (lastHI16ExportAddress != exportAddress) {
|
||||
if (!lastHI16Processed && lastHI16Relocs.size() >= 1) {
|
||||
WARN_LOG_REPORT(LOADER, "Unsafe unpaired HI16 variable relocation @ %08x / %08x", lastHI16Relocs[lastHI16Relocs.size() - 1].addr, relocAddress);
|
||||
}
|
||||
|
||||
lastHI16ExportAddress = exportAddress;
|
||||
lastHI16Relocs.clear();
|
||||
@@ -341,7 +456,7 @@ void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type)
|
||||
// The R_MIPS_LO16 and R_MIPS_HI16 will often be *different* relocAddress values.
|
||||
HI16RelocInfo reloc;
|
||||
reloc.addr = relocAddress;
|
||||
reloc.data = Memory::Read_Instruction(relocAddress);
|
||||
reloc.data = Memory::Read_Instruction(relocAddress).encoding;
|
||||
lastHI16Relocs.push_back(reloc);
|
||||
lastHI16Processed = false;
|
||||
break;
|
||||
@@ -353,17 +468,20 @@ void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type)
|
||||
u32 full = exportOffsetLo;
|
||||
|
||||
// The ABI requires that these come in pairs, at least.
|
||||
if (lastHI16Relocs.empty())
|
||||
if (lastHI16Relocs.empty()) {
|
||||
ERROR_LOG_REPORT(LOADER, "LO16 without any HI16 variable import at %08x for %08x", relocAddress, exportAddress)
|
||||
// Try to process at least the low relocation...
|
||||
else if (lastHI16ExportAddress != exportAddress)
|
||||
} else if (lastHI16ExportAddress != exportAddress) {
|
||||
ERROR_LOG_REPORT(LOADER, "HI16 and LO16 imports do not match at %08x for %08x (should be %08x)", relocAddress, lastHI16ExportAddress, exportAddress)
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Process each of the HI16. Usually there's only one.
|
||||
for (auto it = lastHI16Relocs.begin(), end = lastHI16Relocs.end(); it != end; ++it)
|
||||
{
|
||||
full = (it->data << 16) + exportOffsetLo;
|
||||
if (!reverse) {
|
||||
full = (it->data << 16) + exportOffsetLo;
|
||||
} else {
|
||||
full = (it->data << 16) - exportOffsetLo;
|
||||
}
|
||||
// The low instruction will be a signed add, which means (full & 0x8000) will subtract.
|
||||
// We add 1 in that case so that it ends up the right value.
|
||||
u16 high = (full >> 16) + ((full & 0x8000) ? 1 : 0);
|
||||
@@ -382,64 +500,177 @@ void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type)
|
||||
}
|
||||
|
||||
Memory::Write_U32(relocData, relocAddress);
|
||||
currentMIPS->InvalidateICache(relocAddress, 4);
|
||||
}
|
||||
|
||||
void ImportVarSymbol(const char *moduleName, u32 nid, u32 address, u8 type)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name.");
|
||||
|
||||
if (nid == 0)
|
||||
{
|
||||
void ImportVarSymbol(const VarSymbolImport &var) {
|
||||
if (var.nid == 0) {
|
||||
// TODO: What's the right thing for this?
|
||||
ERROR_LOG_REPORT(LOADER, "Var import with nid = 0, type = %d", type);
|
||||
ERROR_LOG_REPORT(LOADER, "Var import with nid = 0, type = %d", var.type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Memory::IsValidAddress(address))
|
||||
{
|
||||
ERROR_LOG_REPORT(LOADER, "Invalid address for var import nid = %08x, type = %d, addr = %08x", nid, type, address);
|
||||
if (!Memory::IsValidAddress(var.stubAddr)) {
|
||||
ERROR_LOG_REPORT(LOADER, "Invalid address for var import nid = %08x, type = %d, addr = %08x", var.nid, var.type, var.stubAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = exportedVars.begin(), end = exportedVars.end(); it != end; ++it)
|
||||
{
|
||||
if (!strncmp(it->moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH) && it->nid == nid)
|
||||
{
|
||||
WriteVarSymbol(it->symAddr, address, type);
|
||||
return;
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for exports currently loaded modules already have. Maybe it's available?
|
||||
for (auto it = module->exportedVars.begin(), end = module->exportedVars.end(); it != end; ++it) {
|
||||
if (it->Matches(var)) {
|
||||
WriteVarSymbol(it->symAddr, var.stubAddr, var.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It hasn't been exported yet, but hopefully it will later.
|
||||
INFO_LOG(LOADER, "Variable (%s,%08x) unresolved, storing for later resolving", moduleName, nid);
|
||||
VarSymbol vs = {"", address, nid, type};
|
||||
strncpy(vs.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
vs.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
unresolvedVars.push_back(vs);
|
||||
INFO_LOG(LOADER, "Variable (%s,%08x) unresolved, storing for later resolving", var.moduleName, var.nid);
|
||||
}
|
||||
|
||||
void ExportVarSymbol(const char *moduleName, u32 nid, u32 address)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name.");
|
||||
|
||||
VarSymbol ex = {"", address, nid};
|
||||
strncpy(ex.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
ex.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
exportedVars.push_back(ex);
|
||||
|
||||
for (auto it = unresolvedVars.begin(), end = unresolvedVars.end(); it != end; ++it)
|
||||
{
|
||||
if (strncmp(it->moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH) == 0 && it->nid == nid)
|
||||
{
|
||||
INFO_LOG(HLE,"Resolving var %s/%08x", moduleName, nid);
|
||||
WriteVarSymbol(address, it->symAddr, it->type);
|
||||
void ExportVarSymbol(const VarSymbolExport &var) {
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for imports currently loaded modules already have, hook it up right away.
|
||||
for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) {
|
||||
if (var.Matches(*it)) {
|
||||
INFO_LOG(LOADER, "Resolving var %s/%08x", var.moduleName, var.nid);
|
||||
WriteVarSymbol(var.symAddr, it->stubAddr, it->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnexportVarSymbol(const VarSymbolExport &var) {
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for imports modules that are *still* loaded have, and reverse them.
|
||||
for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) {
|
||||
if (var.Matches(*it)) {
|
||||
INFO_LOG(LOADER, "Unresolving var %s/%08x", var.moduleName, var.nid);
|
||||
WriteVarSymbol(var.symAddr, it->stubAddr, it->type, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImportFuncSymbol(const FuncSymbolImport &func) {
|
||||
// Prioritize HLE implementations.
|
||||
// TODO: Or not?
|
||||
if (FuncImportIsSyscall(func.moduleName, func.nid)) {
|
||||
WriteSyscall(func.moduleName, func.nid, func.stubAddr);
|
||||
currentMIPS->InvalidateICache(func.stubAddr, 8);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for exports currently loaded modules already have. Maybe it's available?
|
||||
for (auto it = module->exportedFuncs.begin(), end = module->exportedFuncs.end(); it != end; ++it) {
|
||||
if (it->Matches(func)) {
|
||||
WriteFuncStub(func.stubAddr, it->symAddr);
|
||||
currentMIPS->InvalidateICache(func.stubAddr, 8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It hasn't been exported yet, but hopefully it will later.
|
||||
if (GetModuleIndex(func.moduleName) != -1) {
|
||||
WARN_LOG_REPORT(LOADER, "Unknown syscall in known module: %s 0x%08x", func.moduleName, func.nid);
|
||||
} else {
|
||||
INFO_LOG(LOADER, "Function (%s,%08x) unresolved, storing for later resolving", func.moduleName, func.nid);
|
||||
}
|
||||
WriteFuncMissingStub(func.stubAddr, func.nid);
|
||||
currentMIPS->InvalidateICache(func.stubAddr, 8);
|
||||
}
|
||||
|
||||
void ExportFuncSymbol(const FuncSymbolExport &func) {
|
||||
if (FuncImportIsSyscall(func.moduleName, func.nid)) {
|
||||
// Oops, HLE covers this.
|
||||
WARN_LOG_REPORT(LOADER, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for imports currently loaded modules already have, hook it up right away.
|
||||
for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) {
|
||||
if (func.Matches(*it)) {
|
||||
INFO_LOG(LOADER, "Resolving function %s/%08x", func.moduleName, func.nid);
|
||||
WriteFuncStub(it->stubAddr, func.symAddr);
|
||||
currentMIPS->InvalidateICache(it->stubAddr, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnexportFuncSymbol(const FuncSymbolExport &func) {
|
||||
if (FuncImportIsSyscall(func.moduleName, func.nid)) {
|
||||
// Oops, HLE covers this.
|
||||
return;
|
||||
}
|
||||
|
||||
u32 error;
|
||||
for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) {
|
||||
Module *module = kernelObjects.Get<Module>(*mod, error);
|
||||
if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for imports modules that are *still* loaded have, and write back stubs.
|
||||
for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) {
|
||||
if (func.Matches(*it)) {
|
||||
INFO_LOG(LOADER, "Unresolving function %s/%08x", func.moduleName, func.nid);
|
||||
WriteFuncMissingStub(it->stubAddr, it->nid);
|
||||
currentMIPS->InvalidateICache(it->stubAddr, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Module::Cleanup() {
|
||||
loadedModules.erase(GetUID());
|
||||
|
||||
for (auto it = exportedVars.begin(), end = exportedVars.end(); it != end; ++it) {
|
||||
UnexportVarSymbol(*it);
|
||||
}
|
||||
for (auto it = exportedFuncs.begin(), end = exportedFuncs.end(); it != end; ++it) {
|
||||
UnexportFuncSymbol(*it);
|
||||
}
|
||||
}
|
||||
|
||||
Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string, u32 *magic) {
|
||||
Module *module = new Module;
|
||||
kernelObjects.Create(module);
|
||||
loadedModules.insert(module->GetUID());
|
||||
memset(&module->nm, 0, sizeof(module->nm));
|
||||
|
||||
u8 *newptr = 0;
|
||||
@@ -488,6 +719,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
*error_string = "File corrupt";
|
||||
if (newptr)
|
||||
delete [] newptr;
|
||||
module->Cleanup();
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
return 0;
|
||||
}
|
||||
@@ -498,6 +730,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
ERROR_LOG(HLE, "LoadInto failed");
|
||||
if (newptr)
|
||||
delete [] newptr;
|
||||
module->Cleanup();
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
return 0;
|
||||
}
|
||||
@@ -622,20 +855,17 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
continue;
|
||||
}
|
||||
|
||||
FuncSymbolImport func;
|
||||
strncpy(func.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
u32_le *nidDataPtr = (u32_le *)Memory::GetPointer(entry->nidData);
|
||||
for (int i = 0; i < entry->numFuncs; ++i) {
|
||||
u32 addrToWriteSyscall = entry->firstSymAddr + i * 8;
|
||||
DEBUG_LOG(LOADER, "%s : %08x", GetFuncName(modulename, nidDataPtr[i]), addrToWriteSyscall);
|
||||
//write a syscall here
|
||||
if (Memory::IsValidAddress(addrToWriteSyscall)) {
|
||||
WriteSyscall(modulename, nidDataPtr[i], addrToWriteSyscall);
|
||||
} else {
|
||||
WARN_LOG_REPORT(LOADER, "Invalid address for syscall stub %s %08x", modulename, nidDataPtr[i]);
|
||||
}
|
||||
|
||||
char temp[256];
|
||||
sprintf(temp,"zz_%s", GetFuncName(modulename, nidDataPtr[i]));
|
||||
symbolMap.AddSymbol(temp, addrToWriteSyscall, 8, ST_FUNCTION);
|
||||
// This is the id of the import.
|
||||
func.nid = nidDataPtr[i];
|
||||
// This is the address to write the j abnd delay slot to.
|
||||
func.stubAddr = entry->firstSymAddr + i * 8;
|
||||
module->ImportFunc(func);
|
||||
}
|
||||
} else if (entry->numFuncs > 0) {
|
||||
WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs);
|
||||
@@ -649,6 +879,10 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
continue;
|
||||
}
|
||||
|
||||
VarSymbolImport var;
|
||||
strncpy(var.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
for (int i = 0; i < entry->numVars; ++i) {
|
||||
u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8);
|
||||
u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4);
|
||||
@@ -659,7 +893,10 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
|
||||
u32_le *varRef = (u32_le *)Memory::GetPointer(varRefsPtr);
|
||||
for (; *varRef != 0; ++varRef) {
|
||||
ImportVarSymbol(modulename, nid, (*varRef & 0x03FFFFFF) << 2, *varRef >> 26);
|
||||
var.nid = nid;
|
||||
var.stubAddr = (*varRef & 0x03FFFFFF) << 2;
|
||||
var.type = *varRef >> 26;
|
||||
module->ImportVar(var);
|
||||
}
|
||||
}
|
||||
} else if (entry->numVars > 0) {
|
||||
@@ -733,7 +970,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
INFO_LOG(HLE, "Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident);
|
||||
|
||||
if (!Memory::IsValidAddress(ent->resident)) {
|
||||
if (ent->fcount + ent->vcount > 0) {
|
||||
if (ent->fcount + variableCount > 0) {
|
||||
WARN_LOG_REPORT(LOADER, "Invalid export resident address %08x", ent->resident);
|
||||
}
|
||||
continue;
|
||||
@@ -746,6 +983,10 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
WARN_LOG_REPORT(LOADER, "Unexpected export module entry size %d, vcountNew=%08x, unknown1=%08x, unknown2=%08x", ent->size, ent->vcountNew, ent->unknown1, ent->unknown2);
|
||||
}
|
||||
|
||||
FuncSymbolExport func;
|
||||
strncpy(func.moduleName, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
for (u32 j = 0; j < ent->fcount; j++) {
|
||||
u32 nid = residentPtr[j];
|
||||
u32 exportAddr = exportPtr[j];
|
||||
@@ -767,10 +1008,16 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
module->nm.module_bootstart_func = exportAddr;
|
||||
break;
|
||||
default:
|
||||
ResolveSyscall(name, nid, exportAddr);
|
||||
func.nid = nid;
|
||||
func.symAddr = exportAddr;
|
||||
module->ExportFunc(func);
|
||||
}
|
||||
}
|
||||
|
||||
VarSymbolExport var;
|
||||
strncpy(var.moduleName, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
|
||||
for (u32 j = 0; j < variableCount; j++) {
|
||||
u32 nid = residentPtr[ent->fcount + j];
|
||||
u32 exportAddr = exportPtr[ent->fcount + j];
|
||||
@@ -813,7 +1060,9 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
DEBUG_LOG(LOADER, "Module SDK: %08x", Memory::Read_U32(exportAddr));
|
||||
break;
|
||||
default:
|
||||
ExportVarSymbol(name, nid, exportAddr);
|
||||
var.nid = nid;
|
||||
var.symAddr = exportAddr;
|
||||
module->ExportVar(var);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -971,8 +1220,10 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
|
||||
Module *module = __KernelLoadModule(temp, 0, error_string);
|
||||
|
||||
if (!module || module->isFake) {
|
||||
if (module)
|
||||
if (module) {
|
||||
module->Cleanup();
|
||||
kernelObjects.Destroy<Module>(module->GetUID());
|
||||
}
|
||||
ERROR_LOG(LOADER, "Failed to load module %s", filename);
|
||||
*error_string = "Failed to load executable: " + *error_string;
|
||||
delete [] temp;
|
||||
@@ -1068,6 +1319,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr)
|
||||
|
||||
Module *module = new Module;
|
||||
kernelObjects.Create(module);
|
||||
loadedModules.insert(module->GetUID());
|
||||
memset(&module->nm, 0, sizeof(module->nm));
|
||||
module->isFake = true;
|
||||
return module->GetUID();
|
||||
@@ -1143,7 +1395,7 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu
|
||||
u32 stacksize = 0x40000;
|
||||
u32 attr = 0;
|
||||
int stackPartition = 0;
|
||||
SceKernelSMOption smoption;
|
||||
SceKernelSMOption smoption = {0};
|
||||
if (optionAddr) {
|
||||
Memory::ReadStruct(optionAddr, &smoption);
|
||||
}
|
||||
@@ -1320,6 +1572,7 @@ u32 sceKernelUnloadModule(u32 moduleId)
|
||||
if (!module)
|
||||
return error;
|
||||
|
||||
module->Cleanup();
|
||||
kernelObjects.Destroy<Module>(moduleId);
|
||||
return moduleId;
|
||||
}
|
||||
@@ -1409,6 +1662,12 @@ u32 sceKernelGetModuleId()
|
||||
u32 sceKernelFindModuleByName(const char *name)
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceKernelFindModuleByName(%s)", name);
|
||||
|
||||
int index = GetModuleIndex(name);
|
||||
|
||||
if (index == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1496,13 +1755,32 @@ u32 sceKernelQueryModuleInfo(u32 uid, u32 infoAddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 ModuleMgrForKernel_977de386(const char *name, u32 flags, u32 optionAddr)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
return sceKernelLoadModule(name, flags, optionAddr);
|
||||
}
|
||||
|
||||
void ModuleMgrForKernel_50f0c1ec(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
sceKernelStartModule(moduleId, argsize, argAddr, returnValueAddr, optionAddr);
|
||||
}
|
||||
|
||||
//fix for tiger x dragon
|
||||
u32 ModuleMgrForKernel_a1a78c58(const char *name, u32 flags, u32 optionAddr)
|
||||
{
|
||||
WARN_LOG(HLE,"Not support this patcher");
|
||||
return sceKernelLoadModule(name, flags, optionAddr);
|
||||
}
|
||||
|
||||
const HLEFunction ModuleMgrForUser[] =
|
||||
{
|
||||
{0x977DE386,&WrapU_CUU<sceKernelLoadModule>,"sceKernelLoadModule"},
|
||||
{0xb7f46618,&WrapU_UUU<sceKernelLoadModuleByID>,"sceKernelLoadModuleByID"},
|
||||
{0x50F0C1EC,&WrapV_UUUUU<sceKernelStartModule>,"sceKernelStartModule"},
|
||||
{0x50F0C1EC,&WrapV_UUUUU<sceKernelStartModule>,"sceKernelStartModule", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xD675EBB8,&sceKernelExitGame,"sceKernelSelfStopUnloadModule"}, //HACK
|
||||
{0xd1ff982a,&WrapU_UUUUU<sceKernelStopModule>,"sceKernelStopModule"},
|
||||
{0xd1ff982a,&WrapU_UUUUU<sceKernelStopModule>,"sceKernelStopModule", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0x2e0911aa,WrapU_U<sceKernelUnloadModule>,"sceKernelUnloadModule"},
|
||||
{0x710F61B5,0,"sceKernelLoadModuleMs"},
|
||||
{0xF9275D98,0,"sceKernelLoadModuleBufferUsbWlan"}, ///???
|
||||
@@ -1519,7 +1797,20 @@ const HLEFunction ModuleMgrForUser[] =
|
||||
};
|
||||
|
||||
|
||||
const HLEFunction ModuleMgrForKernel[] =
|
||||
{
|
||||
{0x50f0c1ec,&WrapV_UUUUU<ModuleMgrForKernel_50f0c1ec>, "ModuleMgrForKernel_50f0c1ec"},//Not sure right
|
||||
{0x977de386, &WrapU_CUU<ModuleMgrForKernel_977de386>, "ModuleMgrForKernel_977de386"},//Not sure right
|
||||
{0xa1a78c58, &WrapU_CUU<ModuleMgrForKernel_a1a78c58>, "ModuleMgrForKernel_a1a78c58"}, //fix for tiger x dragon
|
||||
};
|
||||
|
||||
void Register_ModuleMgrForUser()
|
||||
{
|
||||
RegisterModule("ModuleMgrForUser", ARRAY_SIZE(ModuleMgrForUser), ModuleMgrForUser);
|
||||
}
|
||||
|
||||
void Register_ModuleMgrForKernel()
|
||||
{
|
||||
RegisterModule("ModuleMgrForKernel", ARRAY_SIZE(ModuleMgrForKernel), ModuleMgrForKernel);
|
||||
|
||||
};
|
||||
@@ -29,3 +29,4 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
|
||||
void __KernelReturnFromModuleFunc();
|
||||
|
||||
void Register_ModuleMgrForUser();
|
||||
void Register_ModuleMgrForKernel();
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/sceKernelMsgPipe.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
|
||||
@@ -140,7 +141,7 @@ struct MsgPipe : public KernelObject
|
||||
|
||||
void AddWaitingThread(std::vector<MsgPipeWaitingThread> &list, SceUID id, u32 addr, u32 size, int waitMode, u32 transferredBytesAddr)
|
||||
{
|
||||
MsgPipeWaitingThread thread = { id, addr, size, size, waitMode, transferredBytesAddr };
|
||||
MsgPipeWaitingThread thread = { id, addr, size, size, waitMode, { transferredBytesAddr } };
|
||||
// Start out with 0 transferred bytes while waiting.
|
||||
// TODO: for receive, it might be a different (partial) number.
|
||||
if (thread.transferredBytes.IsValid())
|
||||
@@ -399,7 +400,11 @@ int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size,
|
||||
DEBUG_LOG(HLE, "%d=sceKernelCreateMsgPipe(%s, part=%d, attr=%08x, size=%d, opt=%08x)", id, name, partition, attr, size, optionsPtr);
|
||||
|
||||
if (optionsPtr != 0)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateMsgPipe(%s) unsupported options parameter: %08x", name, optionsPtr);
|
||||
{
|
||||
u32 size = Memory::Read_U32(optionsPtr);
|
||||
if (size > 4)
|
||||
WARN_LOG_REPORT(HLE, "sceKernelCreateMsgPipe(%s) unsupported options parameter, size = %d", name, size);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -423,11 +428,8 @@ int sceKernelDeleteMsgPipe(SceUID uid)
|
||||
return kernelObjects.Destroy<MsgPipe>(uid);
|
||||
}
|
||||
|
||||
int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll)
|
||||
int __KernelValidateSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, int waitMode, u32 resultAddr, bool tryMode = false)
|
||||
{
|
||||
u32 curSendAddr = sendBufAddr;
|
||||
SceUID uid = m->GetUID();
|
||||
|
||||
if (sendSize & 0x80000000)
|
||||
{
|
||||
ERROR_LOG(HLE, "__KernelSendMsgPipe(%d): illegal size %d", uid, sendSize);
|
||||
@@ -442,10 +444,32 @@ int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode,
|
||||
|
||||
if (waitMode != SCE_KERNEL_MPW_ASAP && waitMode != SCE_KERNEL_MPW_FULL)
|
||||
{
|
||||
ERROR_LOG(HLE, "__KernelSendMsgPipe(%d): invalid wait mode", uid, waitMode);
|
||||
ERROR_LOG(HLE, "__KernelSendMsgPipe(%d): invalid wait mode %d", uid, waitMode);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
|
||||
if (!tryMode)
|
||||
{
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
{
|
||||
WARN_LOG(HLE, "__KernelSendMsgPipe(%d): dispatch disabled", uid);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt())
|
||||
{
|
||||
WARN_LOG(HLE, "__KernelSendMsgPipe(%d): in interrupt", uid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll)
|
||||
{
|
||||
u32 curSendAddr = sendBufAddr;
|
||||
SceUID uid = m->GetUID();
|
||||
|
||||
// If the buffer size is 0, nothing is buffered and all operations wait.
|
||||
if (m->nmp.bufSize == 0)
|
||||
{
|
||||
@@ -547,7 +571,10 @@ int __KernelSendMsgPipe(MsgPipe *m, u32 sendBufAddr, u32 sendSize, int waitMode,
|
||||
|
||||
int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateSendMsgPipe(uid, sendBufAddr, sendSize, waitMode, resultAddr);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
@@ -560,7 +587,10 @@ int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode
|
||||
|
||||
int sceKernelSendMsgPipeCB(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateSendMsgPipe(uid, sendBufAddr, sendSize, waitMode, resultAddr);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelSendMsgPipeCB(%i) - ERROR %08x", uid, error);
|
||||
@@ -575,7 +605,10 @@ int sceKernelSendMsgPipeCB(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMo
|
||||
|
||||
int sceKernelTrySendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateSendMsgPipe(uid, sendBufAddr, sendSize, waitMode, resultAddr, true);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelTrySendMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
@@ -586,11 +619,8 @@ int sceKernelTrySendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitM
|
||||
return __KernelSendMsgPipe(m, sendBufAddr, sendSize, waitMode, resultAddr, 0, false, true);
|
||||
}
|
||||
|
||||
int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll)
|
||||
int __KernelValidateReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, int waitMode, u32 resultAddr, bool tryMode = false)
|
||||
{
|
||||
u32 curReceiveAddr = receiveBufAddr;
|
||||
SceUID uid = m->GetUID();
|
||||
|
||||
if (receiveSize & 0x80000000)
|
||||
{
|
||||
ERROR_LOG(HLE, "__KernelReceiveMsgPipe(%d): illegal size %d", uid, receiveSize);
|
||||
@@ -605,10 +635,32 @@ int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSize, int
|
||||
|
||||
if (waitMode != SCE_KERNEL_MPW_ASAP && waitMode != SCE_KERNEL_MPW_FULL)
|
||||
{
|
||||
ERROR_LOG(HLE, "__KernelReceiveMsgPipe(%d): invalid wait mode", uid, waitMode);
|
||||
ERROR_LOG(HLE, "__KernelReceiveMsgPipe(%d): invalid wait mode %d", uid, waitMode);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
|
||||
if (!tryMode)
|
||||
{
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
{
|
||||
WARN_LOG(HLE, "__KernelReceiveMsgPipe(%d): dispatch disabled", uid);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt())
|
||||
{
|
||||
WARN_LOG(HLE, "__KernelReceiveMsgPipe(%d): in interrupt", uid);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSize, int waitMode, u32 resultAddr, u32 timeoutPtr, bool cbEnabled, bool poll)
|
||||
{
|
||||
u32 curReceiveAddr = receiveBufAddr;
|
||||
SceUID uid = m->GetUID();
|
||||
|
||||
// MsgPipe buffer size is 0, receiving directly from waiting send threads
|
||||
if (m->nmp.bufSize == 0)
|
||||
{
|
||||
@@ -708,7 +760,10 @@ int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSize, int
|
||||
|
||||
int sceKernelReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateReceiveMsgPipe(uid, receiveBufAddr, receiveSize, waitMode, resultAddr);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelReceiveMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
@@ -721,7 +776,10 @@ int sceKernelReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32
|
||||
|
||||
int sceKernelReceiveMsgPipeCB(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateReceiveMsgPipe(uid, receiveBufAddr, receiveSize, waitMode, resultAddr);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelReceiveMsgPipeCB(%i) - ERROR %08x", uid, error);
|
||||
@@ -736,7 +794,10 @@ int sceKernelReceiveMsgPipeCB(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u
|
||||
|
||||
int sceKernelTryReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr)
|
||||
{
|
||||
u32 error;
|
||||
u32 error = __KernelValidateReceiveMsgPipe(uid, receiveBufAddr, receiveSize, waitMode, resultAddr, true);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
|
||||
if (!m) {
|
||||
ERROR_LOG(HLE, "sceKernelTryReceiveMsgPipe(%i) - ERROR %08x", uid, error);
|
||||
|
||||
@@ -405,11 +405,11 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio
|
||||
|
||||
int sceKernelDeleteMutex(SceUID id)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelDeleteMutex(%i)", id);
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(id, error);
|
||||
if (mutex)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteMutex(%i)", id);
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter, end;
|
||||
for (iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
|
||||
@@ -425,7 +425,10 @@ int sceKernelDeleteMutex(SceUID id)
|
||||
return kernelObjects.Destroy<Mutex>(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteMutex(%i): invalid mutex", id);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
bool __KernelLockMutexCheck(Mutex *mutex, int count, u32 &error)
|
||||
@@ -567,6 +570,65 @@ void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr)
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
|
||||
{
|
||||
u32 error;
|
||||
Mutex *mutex = kernelObjects.Get<Mutex>(uid, error);
|
||||
if (mutex)
|
||||
{
|
||||
bool lockable = count <= 0 || __KernelLockMutexCheck(mutex, count, error);
|
||||
if (!lockable)
|
||||
{
|
||||
// May still be okay. As long as the count/etc. are valid.
|
||||
if (error != 0 && error != PSP_MUTEX_ERROR_LOCK_OVERFLOW && error != PSP_MUTEX_ERROR_ALREADY_LOCKED)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x): invalid count", uid, count, numWaitThreadsPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr);
|
||||
|
||||
// Remove threads no longer waiting on this first (so the numWaitThreads value is correct.)
|
||||
for (auto iter = mutex->waitingThreads.begin(); iter != mutex->waitingThreads.end(); ++iter)
|
||||
{
|
||||
SceUID waitID = __KernelGetWaitID(*iter, WAITTYPE_MUTEX, error);
|
||||
// The thread is no longer waiting for this, clean it up.
|
||||
if (waitID != uid)
|
||||
mutex->waitingThreads.erase(iter--);
|
||||
}
|
||||
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr);
|
||||
|
||||
bool wokeThreads = false;
|
||||
for (auto iter = mutex->waitingThreads.begin(), end = mutex->waitingThreads.end(); iter != end; ++iter)
|
||||
wokeThreads |= __KernelUnlockMutexForThread(mutex, *iter, error, SCE_KERNEL_ERROR_WAIT_CANCEL);
|
||||
|
||||
if (mutex->nm.lockThread != -1)
|
||||
__KernelMutexEraseLock(mutex);
|
||||
mutex->waitingThreads.clear();
|
||||
|
||||
if (count <= 0)
|
||||
{
|
||||
mutex->nm.lockLevel = 0;
|
||||
mutex->nm.lockThread = -1;
|
||||
}
|
||||
else
|
||||
__KernelMutexAcquireLock(mutex, count);
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("mutex canceled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// int sceKernelLockMutex(SceUID id, int count, int *timeout)
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr);
|
||||
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr);
|
||||
int sceKernelDeleteMutex(SceUID id);
|
||||
int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr);
|
||||
|
||||
@@ -477,7 +477,7 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCal
|
||||
int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
|
||||
{
|
||||
int result = __KernelWaitSema(id, wantedCount, timeoutPtr, false);
|
||||
if (result == SCE_KERNEL_ERROR_ILLEGAL_COUNT)
|
||||
if (result == (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT)
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr)
|
||||
else if (result == 0)
|
||||
DEBUG_LOG(HLE, "0=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr)
|
||||
@@ -489,7 +489,7 @@ int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
|
||||
int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr)
|
||||
{
|
||||
int result = __KernelWaitSema(id, wantedCount, timeoutPtr, true);
|
||||
if (result == SCE_KERNEL_ERROR_ILLEGAL_COUNT)
|
||||
if (result == (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT)
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr)
|
||||
else if (result == 0)
|
||||
DEBUG_LOG(HLE, "0=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr)
|
||||
@@ -504,7 +504,7 @@ int sceKernelPollSema(SceUID id, int wantedCount)
|
||||
if (wantedCount <= 0)
|
||||
{
|
||||
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelPollSema(%i, %i)", id, wantedCount);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
return (int)SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
}
|
||||
|
||||
u32 error;
|
||||
|
||||
@@ -68,6 +68,7 @@ const WaitTypeNames waitTypeNames[] = {
|
||||
{ WAITTYPE_MODULE, "Module" },
|
||||
{ WAITTYPE_HLEDELAY, "HleDelay" },
|
||||
{ WAITTYPE_TLS, "TLS" },
|
||||
{ WAITTYPE_VMEM, "Volatile Mem" },
|
||||
};
|
||||
|
||||
const char *getWaitTypeName(WaitType type)
|
||||
@@ -822,6 +823,9 @@ int actionAfterMipsCall;
|
||||
// Doesn't need state saving.
|
||||
WaitTypeFuncs waitTypeFuncs[NUM_WAITTYPES];
|
||||
|
||||
// Doesn't really need state saving, just for logging purposes.
|
||||
static u64 lastSwitchCycles = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//STATE END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -971,6 +975,7 @@ void __KernelThreadingInit()
|
||||
g_inCbCount = 0;
|
||||
currentCallbackThreadID = 0;
|
||||
readyCallbacksCount = 0;
|
||||
lastSwitchCycles = 0;
|
||||
idleThreadHackAddr = kernelMemory.Alloc(blockSize, false, "threadrethack");
|
||||
|
||||
Memory::Memcpy(idleThreadHackAddr, idleThreadCode, sizeof(idleThreadCode));
|
||||
@@ -1025,6 +1030,7 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
__KernelRestoreActionType(actionAfterCallback, ActionAfterCallback::Create);
|
||||
|
||||
hleCurrentThreadName = __KernelGetThreadName(currentThread);
|
||||
lastSwitchCycles = CoreTiming::GetTicks();
|
||||
|
||||
p.DoMarker("sceKernelThread");
|
||||
}
|
||||
@@ -2124,7 +2130,10 @@ void sceKernelExitDeleteThread(int exitStatus)
|
||||
u32 sceKernelSuspendDispatchThread()
|
||||
{
|
||||
if (!__InterruptsEnabled())
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelSuspendDispatchThread(): interrupts disabled");
|
||||
return SCE_KERNEL_ERROR_CPUDI;
|
||||
}
|
||||
|
||||
u32 oldDispatchEnabled = dispatchEnabled;
|
||||
dispatchEnabled = false;
|
||||
@@ -2135,7 +2144,10 @@ u32 sceKernelSuspendDispatchThread()
|
||||
u32 sceKernelResumeDispatchThread(u32 enabled)
|
||||
{
|
||||
if (!__InterruptsEnabled())
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelResumeDispatchThread(%i): interrupts disabled", enabled);
|
||||
return SCE_KERNEL_ERROR_CPUDI;
|
||||
}
|
||||
|
||||
u32 oldDispatchEnabled = dispatchEnabled;
|
||||
dispatchEnabled = enabled != 0;
|
||||
@@ -2404,44 +2416,42 @@ int sceKernelDelayThread(u32 usec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelDelaySysClockThreadCB()
|
||||
int sceKernelDelaySysClockThreadCB(u32 sysclockAddr)
|
||||
{
|
||||
u32 sysclockAddr = PARAM(0);
|
||||
if (!Memory::IsValidAddress(sysclockAddr)) {
|
||||
ERROR_LOG(HLE, "sceKernelDelaySysClockThread(%08x) - bad pointer", sysclockAddr);
|
||||
RETURN(-1);
|
||||
return;
|
||||
PSPPointer<SceKernelSysClock> sysclock;
|
||||
sysclock = sysclockAddr;
|
||||
if (!sysclock.IsValid()) {
|
||||
ERROR_LOG(HLE, "sceKernelDelaySysClockThreadCB(%08x) - bad pointer", sysclockAddr);
|
||||
return -1;
|
||||
}
|
||||
SceKernelSysClock sysclock;
|
||||
Memory::ReadStruct(sysclockAddr, &sysclock);
|
||||
|
||||
// TODO: Which unit?
|
||||
u64 usec = sysclock.lo | ((u64)sysclock.hi << 32);
|
||||
DEBUG_LOG(HLE, "sceKernelDelaySysClockThread(%08x (%llu))", sysclockAddr, usec);
|
||||
u64 usec = sysclock->lo | ((u64)sysclock->hi << 32);
|
||||
DEBUG_LOG(HLE, "sceKernelDelaySysClockThreadCB(%08x (%llu))", sysclockAddr, usec);
|
||||
|
||||
SceUID curThread = __KernelGetCurThread();
|
||||
__KernelScheduleWakeup(curThread, __KernelDelayThreadUs(usec));
|
||||
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, true, "thread delayed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceKernelDelaySysClockThread()
|
||||
int sceKernelDelaySysClockThread(u32 sysclockAddr)
|
||||
{
|
||||
u32 sysclockAddr = PARAM(0);
|
||||
if (!Memory::IsValidAddress(sysclockAddr)) {
|
||||
PSPPointer<SceKernelSysClock> sysclock;
|
||||
sysclock = sysclockAddr;
|
||||
if (!sysclock.IsValid()) {
|
||||
ERROR_LOG(HLE, "sceKernelDelaySysClockThread(%08x) - bad pointer", sysclockAddr);
|
||||
RETURN(-1);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
SceKernelSysClock sysclock;
|
||||
Memory::ReadStruct(sysclockAddr, &sysclock);
|
||||
|
||||
// TODO: Which unit?
|
||||
u64 usec = sysclock.lo | ((u64)sysclock.hi << 32);
|
||||
u64 usec = sysclock->lo | ((u64)sysclock->hi << 32);
|
||||
DEBUG_LOG(HLE, "sceKernelDelaySysClockThread(%08x (%llu))", sysclockAddr, usec);
|
||||
|
||||
SceUID curThread = __KernelGetCurThread();
|
||||
__KernelScheduleWakeup(curThread, __KernelDelayThreadUs(usec));
|
||||
__KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, false, "thread delayed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 __KernelGetThreadPrio(SceUID id)
|
||||
@@ -2537,6 +2547,11 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr)
|
||||
if (threadID == 0 || threadID == currentThread)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_THID;
|
||||
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
if (__IsInInterrupt())
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
@@ -2563,6 +2578,11 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr)
|
||||
if (threadID == 0 || threadID == currentThread)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_THID;
|
||||
|
||||
if (!__KernelIsDispatchEnabled())
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
if (__IsInInterrupt())
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
@@ -2945,8 +2965,7 @@ void Thread::resumeFromWait()
|
||||
if (action)
|
||||
{
|
||||
action->status &= ~THREADSTATUS_WAIT;
|
||||
// TODO: What if DORMANT or DEAD?
|
||||
if (!(action->status & THREADSTATUS_WAITSUSPEND))
|
||||
if (!(action->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD)))
|
||||
action->status = THREADSTATUS_READY;
|
||||
|
||||
// Non-waiting threads do not process callbacks.
|
||||
@@ -2955,8 +2974,7 @@ void Thread::resumeFromWait()
|
||||
else
|
||||
{
|
||||
this->nt.status &= ~THREADSTATUS_WAIT;
|
||||
// TODO: What if DORMANT or DEAD?
|
||||
if (!(this->nt.status & THREADSTATUS_WAITSUSPEND))
|
||||
if (!(this->nt.status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD)))
|
||||
__KernelChangeReadyState(this, this->GetUID(), true);
|
||||
|
||||
// Non-waiting threads do not process callbacks.
|
||||
@@ -3010,7 +3028,7 @@ void __KernelSwitchContext(Thread *target, const char *reason)
|
||||
{
|
||||
u32 oldPC = 0;
|
||||
SceUID oldUID = 0;
|
||||
const char *oldName = "(none)";
|
||||
const char *oldName = hleCurrentThreadName != NULL ? hleCurrentThreadName : "(none)";
|
||||
|
||||
Thread *cur = __GetCurrentThread();
|
||||
if (cur) // It might just have been deleted.
|
||||
@@ -3019,10 +3037,6 @@ void __KernelSwitchContext(Thread *target, const char *reason)
|
||||
oldPC = currentMIPS->pc;
|
||||
oldUID = cur->GetUID();
|
||||
|
||||
// Profile on Windows shows this takes time, skip it.
|
||||
if (DEBUG_LEVEL <= MAX_LOGLEVEL)
|
||||
oldName = cur->GetName();
|
||||
|
||||
// Normally this is taken care of in __KernelNextThread().
|
||||
if (cur->isRunning())
|
||||
__KernelChangeReadyState(cur, oldUID, true);
|
||||
@@ -3043,15 +3057,23 @@ void __KernelSwitchContext(Thread *target, const char *reason)
|
||||
hleCurrentThreadName = NULL;
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL <= MAX_LOGLEVEL || DEBUG_LOG == NOTICE_LOG
|
||||
bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1];
|
||||
bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1];
|
||||
if (!(fromIdle && toIdle))
|
||||
{
|
||||
DEBUG_LOG(HLE,"Context switched: %s -> %s (%s) (%i - pc: %08x -> %i - pc: %08x)",
|
||||
u64 nowCycles = CoreTiming::GetTicks();
|
||||
s64 consumedCycles = nowCycles - lastSwitchCycles;
|
||||
lastSwitchCycles = nowCycles;
|
||||
|
||||
DEBUG_LOG(HLE, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus",
|
||||
oldName, hleCurrentThreadName,
|
||||
oldUID, currentThread,
|
||||
oldPC, currentMIPS->pc,
|
||||
reason,
|
||||
oldUID, oldPC, currentThread, currentMIPS->pc);
|
||||
cyclesToUs(consumedCycles));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (target)
|
||||
{
|
||||
|
||||
@@ -29,8 +29,8 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32
|
||||
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
|
||||
int sceKernelDelayThread(u32 usec);
|
||||
int sceKernelDelayThreadCB(u32 usec);
|
||||
void sceKernelDelaySysClockThread();
|
||||
void sceKernelDelaySysClockThreadCB();
|
||||
int sceKernelDelaySysClockThread(u32 sysclockAddr);
|
||||
int sceKernelDelaySysClockThreadCB(u32 sysclockAddr);
|
||||
int sceKernelDeleteThread(int threadHandle);
|
||||
void sceKernelExitDeleteThread(int exitStatus);
|
||||
void sceKernelExitThread(int exitStatus);
|
||||
@@ -67,7 +67,7 @@ struct SceKernelSysClock {
|
||||
};
|
||||
|
||||
|
||||
// TODO: Map these to PSP wait types.
|
||||
// TODO: Map these to PSP wait types. Most of these are wrong.
|
||||
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
|
||||
enum WaitType
|
||||
{
|
||||
@@ -93,6 +93,7 @@ enum WaitType
|
||||
WAITTYPE_MODULE = 19,
|
||||
WAITTYPE_HLEDELAY = 20,
|
||||
WAITTYPE_TLS = 21,
|
||||
WAITTYPE_VMEM = 22,
|
||||
|
||||
NUM_WAITTYPES
|
||||
};
|
||||
|
||||
+68
-15
@@ -301,18 +301,71 @@ int sceNetAdhocTerm() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Homebrew SDK claims it's a void function, but tests seem to indicate otherwise
|
||||
int sceNetEtherNtostr(const char *mac, u32 bufferPtr) {
|
||||
DEBUG_LOG(HLE, "UNTESTED sceNetEtherNtostr(%s, %x)", mac, bufferPtr);
|
||||
if(Memory::IsValidAddress(bufferPtr)) {
|
||||
int len = (int)strlen(mac);
|
||||
for (int i = 0; i < len; i++)
|
||||
Memory::Write_U8(mac[i], bufferPtr + i);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(HLE, "UNTESTED sceNetEtherNtostr(%s, %x): Tried to write to an invalid pointer", mac, bufferPtr);
|
||||
// Probably a void function, but often returns a useful value.
|
||||
int sceNetEtherNtostr(u32 macPtr, u32 bufferPtr) {
|
||||
DEBUG_LOG(HLE, "sceNetEtherNtostr(%08x, %08x)", macPtr, bufferPtr);
|
||||
|
||||
return 0;
|
||||
if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) {
|
||||
char *buffer = (char *)Memory::GetPointer(bufferPtr);
|
||||
const u8 *mac = Memory::GetPointer(macPtr);
|
||||
|
||||
// MAC address is always 6 bytes / 48 bits.
|
||||
return sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
} else {
|
||||
// Possibly a void function, seems to return this on bad args.
|
||||
return 0x09d40000;
|
||||
}
|
||||
}
|
||||
|
||||
static int hex_to_digit(int c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Probably a void function, but sometimes returns a useful-ish value.
|
||||
int sceNetEtherStrton(u32 bufferPtr, u32 macPtr) {
|
||||
DEBUG_LOG(HLE, "sceNetEtherStrton(%08x, %08x)", bufferPtr, macPtr);
|
||||
|
||||
if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) {
|
||||
const char *buffer = (char *)Memory::GetPointer(bufferPtr);
|
||||
u8 *mac = Memory::GetPointer(macPtr);
|
||||
|
||||
// MAC address is always 6 pairs of hex digits.
|
||||
// TODO: Funny stuff happens if it's too short.
|
||||
u8 value = 0;
|
||||
for (int i = 0; i < 6 && *buffer != 0; ++i) {
|
||||
value = 0;
|
||||
|
||||
int c = hex_to_digit(*buffer++);
|
||||
if (c != -1) {
|
||||
value |= c << 4;
|
||||
}
|
||||
c = hex_to_digit(*buffer++);
|
||||
if (c != -1) {
|
||||
value |= c;
|
||||
}
|
||||
|
||||
*mac++ = value;
|
||||
|
||||
// Skip a single character in between.
|
||||
// TODO: Strange behavior on the PSP, let's just null check.
|
||||
if (*buffer++ == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Seems to maybe kinda return the last value. Probably returns void.
|
||||
return value;
|
||||
} else {
|
||||
// Possibly a void function, seems to return this on bad args (or crash.)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Seems to always return 0, and write 0 to the pointer..
|
||||
@@ -534,10 +587,10 @@ int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLength) {
|
||||
const HLEFunction sceNet[] = {
|
||||
{0x39AF39A6, sceNetInit, "sceNetInit"},
|
||||
{0x281928A9, WrapU_V<sceNetTerm>, "sceNetTerm"},
|
||||
{0x89360950, WrapI_CU<sceNetEtherNtostr>, "sceNetEtherNtostr"},
|
||||
{0x0bf0a3ae, 0, "sceNetGetLocalEtherAddr"},
|
||||
{0xd27961c9, 0, "sceNetEtherStrton"},
|
||||
{0x50647530, 0, "sceNetFreeThreadinfo"},
|
||||
{0x89360950, WrapI_UU<sceNetEtherNtostr>, "sceNetEtherNtostr"},
|
||||
{0xd27961c9, WrapI_UU<sceNetEtherStrton>, "sceNetEtherStrton"},
|
||||
{0x0bf0a3ae, 0, "sceNetGetLocalEtherAddr"},
|
||||
{0x50647530, 0, "sceNetFreeThreadinfo"},
|
||||
{0xcc393e48, WrapI_U<sceNetGetMallocStat>, "sceNetGetMallocStat"},
|
||||
{0xad6844c6, 0, "sceNetThreadAbort"},
|
||||
};
|
||||
|
||||
+94
-27
@@ -15,6 +15,7 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
@@ -24,6 +25,12 @@
|
||||
#include "Core/HLE/scePower.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
|
||||
struct VolatileWaitingThread {
|
||||
SceUID threadID;
|
||||
u32 addrPtr;
|
||||
u32 sizePtr;
|
||||
};
|
||||
|
||||
const int PSP_POWER_ERROR_TAKEN_SLOT = 0x80000020;
|
||||
const int PSP_POWER_ERROR_SLOTS_FULL = 0x80000022;
|
||||
const int PSP_POWER_ERROR_PRIVATE_SLOT = 0x80000023;
|
||||
@@ -45,6 +52,7 @@ const int numberOfCBPowerSlotsPrivate = 32;
|
||||
|
||||
static bool volatileMemLocked;
|
||||
static int powerCbSlots[numberOfCBPowerSlots];
|
||||
static std::vector<VolatileWaitingThread> volatileWaitingThreads;
|
||||
|
||||
// this should belong here on in CoreTiming?
|
||||
static int pllFreq = 222;
|
||||
@@ -53,6 +61,7 @@ static int busFreq = 111;
|
||||
void __PowerInit() {
|
||||
memset(powerCbSlots, 0, sizeof(powerCbSlots));
|
||||
volatileMemLocked = false;
|
||||
volatileWaitingThreads.clear();
|
||||
|
||||
if(g_Config.iLockedCPUSpeed > 0) {
|
||||
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
|
||||
@@ -64,6 +73,7 @@ void __PowerInit() {
|
||||
void __PowerDoState(PointerWrap &p) {
|
||||
p.DoArray(powerCbSlots, ARRAY_SIZE(powerCbSlots));
|
||||
p.Do(volatileMemLocked);
|
||||
p.Do(volatileWaitingThreads);
|
||||
p.DoMarker("scePower");
|
||||
}
|
||||
|
||||
@@ -199,12 +209,11 @@ int sceKernelPowerTick(int flag) {
|
||||
|
||||
#define ERROR_POWER_VMEM_IN_USE 0x802b0200
|
||||
|
||||
int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
|
||||
if (!volatileMemLocked) {
|
||||
INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize);
|
||||
volatileMemLocked = true;
|
||||
} else {
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize);
|
||||
int __KernelVolatileMemLock(int type, u32 paddr, u32 psize) {
|
||||
if (type != 0) {
|
||||
return SCE_KERNEL_ERROR_INVALID_MODE;
|
||||
}
|
||||
if (volatileMemLocked) {
|
||||
return ERROR_POWER_VMEM_IN_USE;
|
||||
}
|
||||
|
||||
@@ -213,22 +222,89 @@ int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
|
||||
// TODO: Should really reserve this properly!
|
||||
Memory::Write_U32(0x08400000, paddr);
|
||||
Memory::Write_U32(0x00400000, psize);
|
||||
volatileMemLocked = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) {
|
||||
u32 error = __KernelVolatileMemLock(type, paddr, psize);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
INFO_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize);
|
||||
break;
|
||||
|
||||
case ERROR_POWER_VMEM_IN_USE:
|
||||
ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int sceKernelVolatileMemUnlock(int type) {
|
||||
if (type != 0) {
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type);
|
||||
return SCE_KERNEL_ERROR_INVALID_MODE;
|
||||
}
|
||||
if (volatileMemLocked) {
|
||||
INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type);
|
||||
volatileMemLocked = false;
|
||||
|
||||
// Wake someone, always fifo.
|
||||
bool wokeThreads = false;
|
||||
u32 error;
|
||||
while (!volatileWaitingThreads.empty() && !volatileMemLocked) {
|
||||
VolatileWaitingThread waitInfo = volatileWaitingThreads.front();
|
||||
volatileWaitingThreads.erase(volatileWaitingThreads.begin());
|
||||
|
||||
int waitID = __KernelGetWaitID(waitInfo.threadID, WAITTYPE_VMEM, error);
|
||||
// If they were force-released, just skip.
|
||||
if (waitID == 1 && __KernelVolatileMemLock(0, waitInfo.addrPtr, waitInfo.sizePtr) == 0) {
|
||||
__KernelResumeThreadFromWait(waitInfo.threadID, 0);
|
||||
wokeThreads = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wokeThreads) {
|
||||
INFO_LOG(HLE, "sceKernelVolatileMemUnlock(%i) handed over to another thread", type);
|
||||
hleReSchedule("volatile mem unlocked");
|
||||
} else {
|
||||
INFO_LOG(HLE, "sceKernelVolatileMemUnlock(%i)", type);
|
||||
}
|
||||
} else {
|
||||
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceKernelVolatileMemLock(int type, int paddr, int psize) {
|
||||
return sceKernelVolatileMemTryLock(type, paddr, psize);
|
||||
int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) {
|
||||
u32 error = __KernelVolatileMemLock(type, paddr, psize);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
INFO_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize);
|
||||
break;
|
||||
|
||||
case ERROR_POWER_VMEM_IN_USE:
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize);
|
||||
const VolatileWaitingThread waitInfo = { __KernelGetCurThread(), paddr, psize };
|
||||
volatileWaitingThreads.push_back(waitInfo);
|
||||
__KernelWaitCurThread(WAITTYPE_VMEM, 1, 0, 0, false, "volatile mem waited");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,17 +343,6 @@ u32 scePowerSetBusClockFrequency(u32 busfreq) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 scePowerGetCpuClockFrequency() {
|
||||
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
|
||||
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequency()", cpuFreq);
|
||||
return cpuFreq;
|
||||
}
|
||||
|
||||
u32 scePowerGetBusClockFrequency() {
|
||||
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequency()", busFreq);
|
||||
return busFreq;
|
||||
}
|
||||
|
||||
u32 scePowerGetCpuClockFrequencyInt() {
|
||||
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
|
||||
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq);
|
||||
@@ -361,8 +426,8 @@ static const HLEFunction scePower[] = {
|
||||
{0xDB9D28DD,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"},
|
||||
{0x843FBF43,WrapU_U<scePowerSetCpuClockFrequency>,"scePowerSetCpuClockFrequency"},
|
||||
{0xB8D7B3FB,WrapU_U<scePowerSetBusClockFrequency>,"scePowerSetBusClockFrequency"},
|
||||
{0xFEE03A2F,WrapU_V<scePowerGetCpuClockFrequency>,"scePowerGetCpuClockFrequency"},
|
||||
{0x478FE6F5,WrapU_V<scePowerGetBusClockFrequency>,"scePowerGetBusClockFrequency"},
|
||||
{0xFEE03A2F,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequency"},
|
||||
{0x478FE6F5,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequency"},
|
||||
{0xFDB5BFE9,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequencyInt"},
|
||||
{0xBD681969,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequencyInt"},
|
||||
{0xB1A52C83,WrapF_V<scePowerGetCpuClockFrequencyFloat>,"scePowerGetCpuClockFrequencyFloat"},
|
||||
@@ -379,9 +444,11 @@ static const HLEFunction scePower[] = {
|
||||
{0x0442d852,0,"scePowerRequestColdReset"},
|
||||
{0xbafa3df0,0,"scePowerGetCallbackMode"},
|
||||
{0xa9d22232,0,"scePowerSetCallbackMode"},
|
||||
{0x23c31ffe,0,"scePowerVolatileMemLock"},
|
||||
{0xfa97a599,0,"scePowerVolatileMemTryLock"},
|
||||
{0xb3edd801,0,"scePowerVolatileMemUnlock"},
|
||||
|
||||
// These seem to be aliases.
|
||||
{0x23c31ffe,&WrapI_IUU<sceKernelVolatileMemLock>,"scePowerVolatileMemLock", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED},
|
||||
{0xfa97a599,&WrapI_IUU<sceKernelVolatileMemTryLock>,"scePowerVolatileMemTryLock"},
|
||||
{0xb3edd801,&WrapI_I<sceKernelVolatileMemUnlock>,"scePowerVolatileMemUnlock"},
|
||||
};
|
||||
|
||||
//890129c in tyshooter looks bogus
|
||||
@@ -392,9 +459,9 @@ const HLEFunction sceSuspendForUser[] = {
|
||||
|
||||
// There's an extra 4MB that can be allocated, which seems to be "volatile". These functions
|
||||
// let you grab it.
|
||||
{0xa14f40b2,&WrapI_III<sceKernelVolatileMemTryLock>,"sceKernelVolatileMemTryLock"},
|
||||
{0xa14f40b2,&WrapI_IUU<sceKernelVolatileMemTryLock>,"sceKernelVolatileMemTryLock"},
|
||||
{0xa569e425,&WrapI_I<sceKernelVolatileMemUnlock>,"sceKernelVolatileMemUnlock"},
|
||||
{0x3e0271d3,&WrapI_III<sceKernelVolatileMemLock>,"sceKernelVolatileMemLock"}, //when "acquiring mem pool" (fired up)
|
||||
{0x3e0271d3,&WrapI_IUU<sceKernelVolatileMemLock>,"sceKernelVolatileMemLock", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, //when "acquiring mem pool" (fired up)
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -256,6 +256,15 @@ u32 sceSasSetPitch(u32 core, int voiceNum, int pitch) {
|
||||
}
|
||||
|
||||
SasVoice &v = sas->voices[voiceNum];
|
||||
// Clamp pitch
|
||||
if (pitch < PSP_SAS_PITCH_MIN) {
|
||||
WARN_LOG(SAS, "bad pitch %i, clamping to %i", pitch, PSP_SAS_PITCH_MIN);
|
||||
pitch = PSP_SAS_PITCH_MIN;
|
||||
} else if (pitch > PSP_SAS_PITCH_MAX) {
|
||||
WARN_LOG(SAS, "bad pitch %i, clamping to %i", pitch, PSP_SAS_PITCH_MAX);
|
||||
pitch = PSP_SAS_PITCH_MAX;
|
||||
}
|
||||
|
||||
v.pitch = pitch;
|
||||
v.ChangedParams(false);
|
||||
return 0;
|
||||
|
||||
+65
-17
@@ -15,12 +15,13 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "sceUmd.h"
|
||||
#include "sceKernelThread.h"
|
||||
#include "Core/HLE/sceUmd.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
|
||||
const u64 MICRO_DELAY_ACTIVATE = 4000;
|
||||
|
||||
@@ -270,51 +271,98 @@ void __UmdWaitStat(u32 timeout)
|
||||
*/
|
||||
int sceUmdWaitDriveStat(u32 stat)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStat(stat = %08x)", stat);
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0) {
|
||||
umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat));
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited");
|
||||
if (stat == 0) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStat(stat = %08x): bad status", stat);
|
||||
return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStat(stat = %08x): dispatch disabled", stat);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStat(stat = %08x): inside interrupt", stat);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStat(stat = %08x): waiting", stat);
|
||||
umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat));
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "0=sceUmdWaitDriveStat(stat = %08x)", stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d)", stat, timeout);
|
||||
if (stat == 0) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): bad status", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): dispatch disabled", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): inside interrupt", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): waiting", stat, timeout);
|
||||
__UmdWaitStat(timeout);
|
||||
umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat));
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0, "umd stat waited with timer");
|
||||
} else
|
||||
hleReSchedule("umd stat waited with timer");
|
||||
return 0;
|
||||
} else {
|
||||
hleReSchedule("umd stat checked");
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "0=sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d)", stat, timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUmdWaitDriveStatCB(u32 stat, u32 timeout)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout);
|
||||
if (stat == 0) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): bad status", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!__KernelIsDispatchEnabled()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): dispatch disabled", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
|
||||
}
|
||||
if (__IsInInterrupt()) {
|
||||
DEBUG_LOG(HLE, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): inside interrupt", stat, timeout);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
|
||||
}
|
||||
|
||||
hleCheckCurrentCallbacks();
|
||||
if ((stat & __KernelUmdGetState()) == 0) {
|
||||
if (timeout == 0)
|
||||
DEBUG_LOG(HLE, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): waiting", stat, timeout);
|
||||
if (timeout == 0) {
|
||||
timeout = 8000;
|
||||
}
|
||||
|
||||
__UmdWaitStat(timeout);
|
||||
umdWaitingThreads.push_back(UmdWaitingThread::Make(__KernelGetCurThread(), stat));
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true, "umd stat waited");
|
||||
} else
|
||||
} else {
|
||||
hleReSchedule("umd stat waited");
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceUmdCancelWaitDriveStat()
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdCancelWaitDriveStat()");
|
||||
DEBUG_LOG(HLE, "0=sceUmdCancelWaitDriveStat()");
|
||||
|
||||
__KernelTriggerWait(WAITTYPE_UMD, 1, SCE_KERNEL_ERROR_WAIT_CANCEL, "umd stat ready", true);
|
||||
// TODO: We should call UnscheduleEvent() event here?
|
||||
|
||||
+94
-14
@@ -43,6 +43,8 @@ enum UtilityDialogType {
|
||||
UTILITY_DIALOG_MSG,
|
||||
UTILITY_DIALOG_OSK,
|
||||
UTILITY_DIALOG_NET,
|
||||
UTILITY_DIALOG_SCREENSHOT,
|
||||
UTILITY_DIALOG_GAMESHARING,
|
||||
};
|
||||
|
||||
// Only a single dialog is allowed at a time.
|
||||
@@ -384,33 +386,60 @@ int sceUtilityNetconfGetStatus()
|
||||
//but it requires more investigation
|
||||
u32 sceUtilityScreenshotInitStart(u32 unknown1, u32 unknown2, u32 unknown3, u32 unknown4, u32 unknown5, u32 unknown6)
|
||||
{
|
||||
if (currentDialogActive && currentDialogType != UTILITY_DIALOG_SCREENSHOT)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityScreenshotInitStart(%x, %x, %x, %x, %x, %x): wrong dialog type", unknown1, unknown2, unknown3, unknown4, unknown5, unknown6);
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
currentDialogType = UTILITY_DIALOG_SCREENSHOT;
|
||||
currentDialogActive = true;
|
||||
|
||||
u32 retval = screenshotDialog.Init();
|
||||
WARN_LOG(HLE, "UNIMPL %i=sceUtilityScreenshotInitStart(%x, %x, %x, %x, %x, %x)", retval, unknown1, unknown2, unknown3, unknown4, unknown5, unknown6);
|
||||
WARN_LOG_REPORT(HLE, "UNIMPL %i=sceUtilityScreenshotInitStart(%x, %x, %x, %x, %x, %x)", retval, unknown1, unknown2, unknown3, unknown4, unknown5, unknown6);
|
||||
return retval;
|
||||
}
|
||||
|
||||
u32 sceUtilityScreenshotShutdownStart()
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_SCREENSHOT)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityScreenshotShutdownStart(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
currentDialogActive = false;
|
||||
|
||||
WARN_LOG(HLE, "UNTESTED sceUtilityScreenshotShutdownStart()");
|
||||
return screenshotDialog.Shutdown();
|
||||
}
|
||||
|
||||
u32 sceUtilityScreenshotUpdate(u32 unknown)
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_SCREENSHOT)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityScreenshotUpdate(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceUtilityScreenshotUpdate(%d)", unknown);
|
||||
return screenshotDialog.Update();
|
||||
}
|
||||
|
||||
int sceUtilityScreenshotGetStatus()
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_SCREENSHOT)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceUtilityScreenshotGetStatus(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
|
||||
u32 retval = screenshotDialog.GetStatus();
|
||||
WARN_LOG(HLE, "UNIMPL %i=sceUtilityScreenshotGetStatus()", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void sceUtilityGamedataInstallInitStart(u32 unkown)
|
||||
void sceUtilityGamedataInstallInitStart(u32 unknown)
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceUtilityGamedataInstallInitStart(%i)", unkown);
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceUtilityGamedataInstallInitStart(%i)", unknown);
|
||||
}
|
||||
|
||||
int sceUtilityGamedataInstallGetStatus()
|
||||
@@ -423,7 +452,7 @@ int sceUtilityGamedataInstallGetStatus()
|
||||
//TODO: should save to config file
|
||||
u32 sceUtilitySetSystemParamString(u32 id, u32 strPtr)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilitySetSystemParamString(%i, %08x)", id, strPtr);
|
||||
WARN_LOG_REPORT(HLE, "sceUtilitySetSystemParamString(%i, %08x)", id, strPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -459,15 +488,19 @@ u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr)
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_DATE_FORMAT:
|
||||
param = g_Config.iDateFormat;
|
||||
INFO_LOG_REPORT(HLE, "sceUtilitySystemGetSystemParamInt: %s", "Date Format")
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_TIME_FORMAT:
|
||||
param = g_Config.iTimeFormat?PSP_SYSTEMPARAM_TIME_FORMAT_12HR:PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
|
||||
INFO_LOG_REPORT(HLE, "sceUtilitySystemGetSystemParamInt: %s", "Time Format")
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_TIMEZONE:
|
||||
param = g_Config.iTimeZone;
|
||||
INFO_LOG_REPORT(HLE, "sceUtilitySystemGetSystemParamInt: %s", "Timezone")
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS:
|
||||
param = g_Config.bDayLightSavings?PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_SAVING:PSP_SYSTEMPARAM_DAYLIGHTSAVINGS_STD;
|
||||
INFO_LOG_REPORT(HLE, "sceUtilitySystemGetSystemParamInt: %s", "Daylight Savings");
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_LANGUAGE:
|
||||
param = g_Config.ilanguage;
|
||||
@@ -477,6 +510,7 @@ u32 sceUtilityGetSystemParamInt(u32 id, u32 destaddr)
|
||||
break;
|
||||
case PSP_SYSTEMPARAM_ID_INT_LOCK_PARENTAL_LEVEL:
|
||||
param = g_Config.iLockParentalLevel;
|
||||
INFO_LOG_REPORT(HLE, "sceUtilitySystemGetSystemParamInt: %s", "Lock Parental Level");
|
||||
break;
|
||||
default:
|
||||
return PSP_SYSTEMPARAM_RETVAL_FAIL;
|
||||
@@ -501,7 +535,7 @@ u32 sceUtilityUnloadNetModule(u32 module)
|
||||
|
||||
void sceUtilityInstallInitStart(u32 unknown)
|
||||
{
|
||||
DEBUG_LOG(HLE,"FAKE sceUtilityInstallInitStart()");
|
||||
WARN_LOG_REPORT(HLE, "UNIMPL sceUtilityInstallInitStart()");
|
||||
}
|
||||
|
||||
int sceUtilityStoreCheckoutShutdownStart()
|
||||
@@ -528,6 +562,57 @@ int sceUtilityStoreCheckoutGetStatus()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUtilityGameSharingShutdownStart()
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_GAMESHARING)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityGameSharingShutdownStart(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
currentDialogActive = false;
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceUtilityGameSharingShutdownStart()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUtilityGameSharingInitStart(u32 paramsPtr)
|
||||
{
|
||||
if (currentDialogActive && currentDialogType != UTILITY_DIALOG_GAMESHARING)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityGameSharingInitStart(%08x)", paramsPtr);
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
currentDialogType = UTILITY_DIALOG_GAMESHARING;
|
||||
currentDialogActive = true;
|
||||
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceUtilityGameSharingInitStart(%08x)", paramsPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUtilityGameSharingUpdate(int drawSpeed)
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_GAMESHARING)
|
||||
{
|
||||
WARN_LOG(HLE, "sceUtilityScreenshotUpdate(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceUtilityGameSharingUpdate(%d)", drawSpeed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceUtilityGameSharingGetStatus()
|
||||
{
|
||||
if (currentDialogType != UTILITY_DIALOG_GAMESHARING)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceUtilityGameSharingGetStatus(): wrong dialog type");
|
||||
return SCE_ERROR_UTILITY_WRONG_TYPE;
|
||||
}
|
||||
|
||||
ERROR_LOG(HLE, "UNIMPL sceUtilityGameSharingGetStatus()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HLEFunction sceUtility[] =
|
||||
{
|
||||
{0x1579a159, &WrapU_U<sceUtilityLoadNetModule>, "sceUtilityLoadNetModule"},
|
||||
@@ -564,10 +649,10 @@ const HLEFunction sceUtility[] =
|
||||
{0xA5DA2406, &WrapU_UU<sceUtilityGetSystemParamInt>, "sceUtilityGetSystemParamInt"},
|
||||
|
||||
|
||||
{0xc492f751, 0, "sceUtilityGameSharingInitStart"},
|
||||
{0xefc6f80f, 0, "sceUtilityGameSharingShutdownStart"},
|
||||
{0x7853182d, 0, "sceUtilityGameSharingUpdate"},
|
||||
{0x946963f3, 0, "sceUtilityGameSharingGetStatus"},
|
||||
{0xc492f751, &WrapI_U<sceUtilityGameSharingInitStart>, "sceUtilityGameSharingInitStart"},
|
||||
{0xefc6f80f, &WrapI_V<sceUtilityGameSharingShutdownStart>, "sceUtilityGameSharingShutdownStart"},
|
||||
{0x7853182d, &WrapI_I<sceUtilityGameSharingUpdate>, "sceUtilityGameSharingUpdate"},
|
||||
{0x946963f3, &WrapI_V<sceUtilityGameSharingGetStatus>, "sceUtilityGameSharingGetStatus"},
|
||||
|
||||
{0x2995d020, 0, "sceUtilitySavedataErrInitStart"},
|
||||
{0xb62a4061, 0, "sceUtilitySavedataErrShutdownStart"},
|
||||
@@ -662,12 +747,7 @@ const HLEFunction sceUtility[] =
|
||||
{0xb6cee597, 0, "sceNetplayDialogGetStatus"},
|
||||
|
||||
{0x28d35634, 0, "sceUtility_28D35634"},
|
||||
{0x6f56f9cf, 0, "sceUtility_6F56F9CF"},
|
||||
{0x70267adf, 0, "sceUtility_70267ADF"},
|
||||
{0x81c44706, 0, "sceUtility_81C44706"},
|
||||
{0x8326ab05, 0, "sceUtility_8326AB05"},
|
||||
{0xb0fb7ff5, 0, "sceUtility_B0fB7FF5"},
|
||||
{0xe7b778d8, 0, "sceUtility_E7B778D8"},
|
||||
{0xece1d3e5, 0, "sceUtility_ECE1D3E5"},
|
||||
{0xef3582b2, 0, "sceUtility_EF3582B2"},
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "MediaEngine.h"
|
||||
#include "../MemMap.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "Core/HW/atrac3plus.h"
|
||||
|
||||
@@ -221,6 +222,11 @@ bool MediaEngine::openContext() {
|
||||
if(avformat_find_stream_info(m_pFormatCtx, NULL) < 0)
|
||||
return false;
|
||||
|
||||
if (m_videoStream >= (int)m_pFormatCtx->nb_streams) {
|
||||
WARN_LOG_REPORT(ME, "Bad video stream %d", m_videoStream);
|
||||
m_videoStream = -1;
|
||||
}
|
||||
|
||||
if (m_videoStream == -1) {
|
||||
// Find the first video stream
|
||||
for(int i = 0; i < (int)m_pFormatCtx->nb_streams; i++) {
|
||||
|
||||
@@ -250,7 +250,7 @@ static int getReleaseRate(int bitfield2) {
|
||||
if (getReleaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
|
||||
return (0x40000000 >> (n + 2));
|
||||
}
|
||||
return (0x08000000 >> n);
|
||||
return (0x40000000 >> n);
|
||||
}
|
||||
|
||||
static int getSustainLevel(int bitfield1) {
|
||||
|
||||
+5
-4
@@ -21,16 +21,14 @@
|
||||
|
||||
struct InputState;
|
||||
|
||||
class PMixer
|
||||
{
|
||||
class PMixer {
|
||||
public:
|
||||
PMixer() {}
|
||||
virtual ~PMixer() {}
|
||||
virtual int Mix(short *stereoout, int numSamples) {memset(stereoout,0,numSamples*2*sizeof(short)); return numSamples;}
|
||||
};
|
||||
|
||||
class Host
|
||||
{
|
||||
class Host {
|
||||
public:
|
||||
virtual ~Host() {}
|
||||
//virtual void StartThread()
|
||||
@@ -64,10 +62,13 @@ public:
|
||||
virtual void SendGPUWait(u32 cmd, u32 addr, void* data) {}
|
||||
virtual void SetGPUStep(bool value, int flag = 0, int data = 0) {}
|
||||
virtual void NextGPUStep() {}
|
||||
virtual bool CanCreateShortcut() {return false;}
|
||||
virtual bool CreateDesktopShortcut(std::string argumentPath, std::string title) {return false;}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Implement this on your platform to grab text input from the user for whatever purpose.
|
||||
virtual bool InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outlength) { return false; }
|
||||
virtual bool InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; }
|
||||
#endif
|
||||
|
||||
// Used for headless.
|
||||
|
||||
+10
-1
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "file/file_util.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "MIPS/MIPS.h"
|
||||
#include "MIPS/MIPSCodeUtils.h"
|
||||
|
||||
@@ -71,7 +72,7 @@ IdentifiedFileType Identify_File(std::string &filename)
|
||||
return FILETYPE_NORMAL_DIRECTORY;
|
||||
}
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
FILE *f = File::OpenCFile(filename.c_str(), "rb");
|
||||
if (!f) {
|
||||
// File does not exists
|
||||
return FILETYPE_ERROR;
|
||||
@@ -161,6 +162,13 @@ bool LoadFile(std::string &filename, std::string *error_string) {
|
||||
|
||||
if (fileInfo.exists) {
|
||||
INFO_LOG(LOADER, "File is a PBP in a directory!");
|
||||
std::string ebootPath = filename + "/EBOOT.PBP";
|
||||
IdentifiedFileType ebootType = Identify_File(ebootPath);
|
||||
if(ebootType == FILETYPE_PSP_ISO_NP) {
|
||||
InitMemoryForGameISO(ebootPath);
|
||||
pspFileSystem.SetStartingDirectory("disc0:/PSP_GAME/USRDIR");
|
||||
return Load_PSP_ISO(filename.c_str(), error_string);
|
||||
}
|
||||
std::string path = filename;
|
||||
size_t pos = path.find("/PSP/GAME/");
|
||||
if (pos != std::string::npos)
|
||||
@@ -212,6 +220,7 @@ bool LoadFile(std::string &filename, std::string *error_string) {
|
||||
|
||||
case FILETYPE_NORMAL_DIRECTORY:
|
||||
ERROR_LOG(LOADER, "Just a directory.");
|
||||
*error_string = "Just a directory.";
|
||||
break;
|
||||
|
||||
case FILETYPE_UNKNOWN_BIN:
|
||||
|
||||
@@ -15,19 +15,24 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "ArmJit.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Core/MIPS/ARM/ArmJit.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
|
||||
using namespace MIPSAnalyst;
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _SA ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _SIZE ((op>>11 ) & 0x1F)
|
||||
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
@@ -61,15 +66,15 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_IType(u32 op)
|
||||
void Jit::Comp_IType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = (u32)(s32)simm;
|
||||
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
// noop, won't write to ZERO.
|
||||
if (rt == 0)
|
||||
@@ -127,10 +132,10 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_RType2(u32 op)
|
||||
void Jit::Comp_RType2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
int rd = _RD;
|
||||
|
||||
// Don't change $zr.
|
||||
@@ -180,11 +185,11 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_RType3(u32 op)
|
||||
void Jit::Comp_RType3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
int rd = _RD;
|
||||
|
||||
// noop, won't write to ZERO.
|
||||
@@ -325,21 +330,21 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::CompShiftImm(u32 op, ArmGen::ShiftType shiftType)
|
||||
void Jit::CompShiftImm(MIPSOpcode op, ArmGen::ShiftType shiftType)
|
||||
{
|
||||
int rd = _RD;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rt = _RT;
|
||||
int sa = _SA;
|
||||
|
||||
gpr.MapDirtyIn(rd, rt);
|
||||
MOV(gpr.R(rd), Operand2(gpr.R(rt), shiftType, sa));
|
||||
}
|
||||
|
||||
void Jit::CompShiftVar(u32 op, ArmGen::ShiftType shiftType)
|
||||
void Jit::CompShiftVar(MIPSOpcode op, ArmGen::ShiftType shiftType)
|
||||
{
|
||||
int rd = _RD;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
if (gpr.IsImm(rs))
|
||||
{
|
||||
int sa = gpr.GetImm(rs) & 0x1F;
|
||||
@@ -352,10 +357,10 @@ namespace MIPSComp
|
||||
MOV(gpr.R(rd), Operand2(gpr.R(rt), shiftType, R0));
|
||||
}
|
||||
|
||||
void Jit::Comp_ShiftType(u32 op)
|
||||
void Jit::Comp_ShiftType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
int rd = _RD;
|
||||
int fd = _FD;
|
||||
|
||||
@@ -379,12 +384,12 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Special3(u32 op)
|
||||
void Jit::Comp_Special3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int rs = _RS;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
int pos = _POS;
|
||||
int size = _SIZE + 1;
|
||||
@@ -447,10 +452,10 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Allegrex(u32 op)
|
||||
void Jit::Comp_Allegrex(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rt = _RT;
|
||||
int rd = _RD;
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
@@ -505,10 +510,10 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Allegrex2(u32 op)
|
||||
void Jit::Comp_Allegrex2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rt = _RT;
|
||||
int rd = _RD;
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
@@ -538,11 +543,11 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_MulDivType(u32 op)
|
||||
void Jit::Comp_MulDivType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
int rd = _RD;
|
||||
|
||||
switch (op & 63)
|
||||
|
||||
@@ -31,15 +31,16 @@
|
||||
|
||||
#include "Common/ArmEmitter.h"
|
||||
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _SIZE ((op>>11 ) & 0x1F)
|
||||
#define _IMM16 (signed short)(op&0xFFFF)
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
#define LOOPOPTIMIZATION 0
|
||||
@@ -53,18 +54,18 @@ using namespace MIPSAnalyst;
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
||||
void Jit::BranchRSRTComp(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
void Jit::BranchRSRTComp(MIPSOpcode op, ArmGen::CCFlags cc, bool likely)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
return;
|
||||
}
|
||||
int offset = _IMM16 << 2;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
u32 targetAddr = js.compilerPC + offset + 4;
|
||||
|
||||
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC+4);
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC+4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rt, rs);
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
if (!likely && delaySlotIsNice)
|
||||
@@ -113,17 +114,17 @@ void Jit::BranchRSRTComp(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
}
|
||||
|
||||
|
||||
void Jit::BranchRSZeroComp(u32 op, ArmGen::CCFlags cc, bool andLink, bool likely)
|
||||
void Jit::BranchRSZeroComp(MIPSOpcode op, ArmGen::CCFlags cc, bool andLink, bool likely)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
return;
|
||||
}
|
||||
int offset = _IMM16 << 2;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
u32 targetAddr = js.compilerPC + offset + 4;
|
||||
|
||||
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
if (!likely && delaySlotIsNice)
|
||||
@@ -164,7 +165,7 @@ void Jit::BranchRSZeroComp(u32 op, ArmGen::CCFlags cc, bool andLink, bool likely
|
||||
}
|
||||
|
||||
|
||||
void Jit::Comp_RelBranch(u32 op)
|
||||
void Jit::Comp_RelBranch(MIPSOpcode op)
|
||||
{
|
||||
// The CC flags here should be opposite of the actual branch becuase they skip the branching action.
|
||||
switch (op>>26)
|
||||
@@ -187,7 +188,7 @@ void Jit::Comp_RelBranch(u32 op)
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_RelBranchRI(u32 op)
|
||||
void Jit::Comp_RelBranchRI(MIPSOpcode op)
|
||||
{
|
||||
switch ((op >> 16) & 0x1F)
|
||||
{
|
||||
@@ -206,7 +207,7 @@ void Jit::Comp_RelBranchRI(u32 op)
|
||||
}
|
||||
|
||||
// If likely is set, discard the branch slot if NOT taken.
|
||||
void Jit::BranchFPFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
void Jit::BranchFPFlag(MIPSOpcode op, ArmGen::CCFlags cc, bool likely)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
@@ -215,7 +216,7 @@ void Jit::BranchFPFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
int offset = _IMM16 << 2;
|
||||
u32 targetAddr = js.compilerPC + offset + 4;
|
||||
|
||||
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceFPU(op, delaySlotOp);
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
if (!likely && delaySlotIsNice)
|
||||
@@ -249,7 +250,7 @@ void Jit::BranchFPFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
js.compiling = false;
|
||||
}
|
||||
|
||||
void Jit::Comp_FPUBranch(u32 op)
|
||||
void Jit::Comp_FPUBranch(MIPSOpcode op)
|
||||
{
|
||||
switch((op >> 16) & 0x1f)
|
||||
{
|
||||
@@ -264,7 +265,7 @@ void Jit::Comp_FPUBranch(u32 op)
|
||||
}
|
||||
|
||||
// If likely is set, discard the branch slot if NOT taken.
|
||||
void Jit::BranchVFPUFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
void Jit::BranchVFPUFlag(MIPSOpcode op, ArmGen::CCFlags cc, bool likely)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
@@ -273,7 +274,7 @@ void Jit::BranchVFPUFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
int offset = _IMM16 << 2;
|
||||
u32 targetAddr = js.compilerPC + offset + 4;
|
||||
|
||||
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
|
||||
// Sometimes there's a VFPU branch in a delay slot (Disgaea 2: Dark Hero Days, Zettai Hero Project, La Pucelle)
|
||||
// The behavior is undefined - the CPU may take the second branch even if the first one passes.
|
||||
@@ -321,7 +322,7 @@ void Jit::BranchVFPUFlag(u32 op, ArmGen::CCFlags cc, bool likely)
|
||||
js.compiling = false;
|
||||
}
|
||||
|
||||
void Jit::Comp_VBranch(u32 op)
|
||||
void Jit::Comp_VBranch(MIPSOpcode op)
|
||||
{
|
||||
switch ((op >> 16) & 3)
|
||||
{
|
||||
@@ -332,7 +333,7 @@ void Jit::Comp_VBranch(u32 op)
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Jump(u32 op)
|
||||
void Jit::Comp_Jump(MIPSOpcode op)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
@@ -364,15 +365,15 @@ void Jit::Comp_Jump(u32 op)
|
||||
js.compiling = false;
|
||||
}
|
||||
|
||||
void Jit::Comp_JumpReg(u32 op)
|
||||
void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart);
|
||||
return;
|
||||
}
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
u32 delaySlotOp = Memory::ReadUnchecked_U32(js.compilerPC + 4);
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
|
||||
@@ -413,7 +414,7 @@ void Jit::Comp_JumpReg(u32 op)
|
||||
}
|
||||
|
||||
|
||||
void Jit::Comp_Syscall(u32 op)
|
||||
void Jit::Comp_Syscall(MIPSOpcode op)
|
||||
{
|
||||
FlushAll();
|
||||
|
||||
@@ -428,7 +429,7 @@ void Jit::Comp_Syscall(u32 op)
|
||||
QuickCallFunction(R1, (void *)GetFunc("FakeSysCalls", NID_IDLE)->func);
|
||||
else
|
||||
{
|
||||
MOVI2R(R0, op);
|
||||
MOVI2R(R0, op.encoding);
|
||||
QuickCallFunction(R1, (void *)&CallSyscall);
|
||||
}
|
||||
RestoreDowncount();
|
||||
@@ -437,7 +438,7 @@ void Jit::Comp_Syscall(u32 op)
|
||||
js.compiling = false;
|
||||
}
|
||||
|
||||
void Jit::Comp_Break(u32 op)
|
||||
void Jit::Comp_Break(MIPSOpcode op)
|
||||
{
|
||||
Comp_Generic(op);
|
||||
WriteSyscallExit();
|
||||
|
||||
@@ -14,21 +14,26 @@
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Core/MIPS/MIPSTables.h"
|
||||
|
||||
#include "ArmJit.h"
|
||||
#include "ArmRegCache.h"
|
||||
#include "Core/MIPS/ARM/ArmJit.h"
|
||||
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
@@ -40,7 +45,7 @@
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
||||
void Jit::Comp_FPU3op(u32 op)
|
||||
void Jit::Comp_FPU3op(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
@@ -54,7 +59,7 @@ void Jit::Comp_FPU3op(u32 op)
|
||||
case 0: VADD(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) + F(ft); //add
|
||||
case 1: VSUB(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) - F(ft); //sub
|
||||
case 2: { //F(fd) = F(fs) * F(ft); //mul
|
||||
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
// Optimization possible if destination is the same
|
||||
if (fd == (int)((nextOp>>6) & 0x1F)) {
|
||||
// VMUL + VNEG -> VNMUL
|
||||
@@ -78,13 +83,13 @@ void Jit::Comp_FPU3op(u32 op)
|
||||
|
||||
extern int logBlocks;
|
||||
|
||||
void Jit::Comp_FPULS(u32 op)
|
||||
void Jit::Comp_FPULS(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
s32 offset = (s16)(op & 0xFFFF);
|
||||
int ft = _FT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
// u32 addr = R(rs) + offset;
|
||||
// logBlocks = 1;
|
||||
bool doCheck = false;
|
||||
@@ -167,7 +172,7 @@ void Jit::Comp_FPULS(u32 op)
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_FPUComp(u32 op) {
|
||||
void Jit::Comp_FPUComp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
int opc = op & 0xF;
|
||||
if (opc >= 8) opc -= 8; // alias
|
||||
@@ -233,7 +238,7 @@ void Jit::Comp_FPUComp(u32 op) {
|
||||
STR(R0, CTXREG, offsetof(MIPSState, fpcond));
|
||||
}
|
||||
|
||||
void Jit::Comp_FPU2op(u32 op)
|
||||
void Jit::Comp_FPU2op(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
@@ -307,12 +312,12 @@ void Jit::Comp_FPU2op(u32 op)
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_mxc1(u32 op)
|
||||
void Jit::Comp_mxc1(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int fs = _FS;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
switch ((op >> 21) & 0x1f)
|
||||
{
|
||||
|
||||
@@ -37,20 +37,25 @@
|
||||
// (pointer or data), we could avoid many BIC instructions.
|
||||
|
||||
|
||||
#include "../../MemMap.h"
|
||||
#include "../MIPSAnalyst.h"
|
||||
#include "../../Config.h"
|
||||
#include "ArmJit.h"
|
||||
#include "ArmRegCache.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Core/MIPS/ARM/ArmJit.h"
|
||||
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _SIZE ((op>>11 ) & 0x1F)
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
@@ -121,15 +126,15 @@ namespace MIPSComp
|
||||
SetCC(CC_GT);
|
||||
}
|
||||
|
||||
void Jit::Comp_ITypeMem(u32 op)
|
||||
void Jit::Comp_ITypeMem(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int offset = (signed short)(op&0xFFFF);
|
||||
bool load = false;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
int o = op>>26;
|
||||
if (((op >> 29) & 1) == 0 && rt == 0) {
|
||||
if (((op >> 29) & 1) == 0 && rt == MIPS_REG_ZERO) {
|
||||
// Don't load anything into $zr
|
||||
return;
|
||||
}
|
||||
@@ -194,13 +199,13 @@ namespace MIPSComp
|
||||
if (!js.inDelaySlot) {
|
||||
// Optimisation: Combine to single unaligned load/store
|
||||
bool isLeft = (o == 34 || o == 42);
|
||||
u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
// Find a matching shift in opposite direction with opposite offset.
|
||||
if (nextOp == (isLeft ? (op + (4<<26) - 3)
|
||||
: (op - (4<<26) + 3)))
|
||||
if (nextOp == (isLeft ? (op.encoding + (4<<26) - 3)
|
||||
: (op.encoding - (4<<26) + 3)))
|
||||
{
|
||||
EatInstruction(nextOp);
|
||||
nextOp = ((load ? 35 : 43) << 26) | ((isLeft ? nextOp : op) & 0x03FFFFFF); //lw, sw
|
||||
nextOp = MIPSOpcode(((load ? 35 : 43) << 26) | ((isLeft ? nextOp : op) & 0x03FFFFFF)); //lw, sw
|
||||
Comp_ITypeMem(nextOp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
#include "ArmJit.h"
|
||||
#include "ArmRegCache.h"
|
||||
#include "Core/MIPS/ARM/ArmJit.h"
|
||||
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||
|
||||
|
||||
const bool disablePrefixes = false;
|
||||
@@ -38,14 +39,17 @@ const bool disablePrefixes = false;
|
||||
#define CONDITIONAL_DISABLE ;
|
||||
#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _SIZE ((op>>11 ) & 0x1F)
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
namespace MIPSComp
|
||||
{
|
||||
@@ -73,7 +77,7 @@ namespace MIPSComp
|
||||
return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg;
|
||||
}
|
||||
|
||||
void Jit::Comp_VPFX(u32 op)
|
||||
void Jit::Comp_VPFX(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int data = op & 0xFFFFF;
|
||||
@@ -231,12 +235,12 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_SV(u32 op) {
|
||||
void Jit::Comp_SV(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
s32 imm = (signed short)(op&0xFFFC);
|
||||
int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
bool doCheck = false;
|
||||
switch (op >> 26)
|
||||
@@ -321,13 +325,13 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_SVQ(u32 op)
|
||||
void Jit::Comp_SVQ(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int imm = (signed short)(op&0xFFFC);
|
||||
int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5);
|
||||
int rs = _RS;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
bool doCheck = false;
|
||||
switch (op >> 26)
|
||||
@@ -433,7 +437,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VVectorInit(u32 op)
|
||||
void Jit::Comp_VVectorInit(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
@@ -470,7 +474,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VIdt(u32 op) {
|
||||
void Jit::Comp_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -507,7 +511,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VMatrixInit(u32 op)
|
||||
void Jit::Comp_VMatrixInit(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
@@ -555,7 +559,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VDot(u32 op) {
|
||||
void Jit::Comp_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
DISABLE;
|
||||
@@ -592,7 +596,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vhoriz(u32 op) {
|
||||
void Jit::Comp_Vhoriz(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
|
||||
switch ((op >> 16) & 31) {
|
||||
@@ -603,12 +607,12 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_VHdp(u32 op) {
|
||||
void Jit::Comp_VHdp(MIPSOpcode op) {
|
||||
// Similar to vdot
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_VecDo3(u32 op) {
|
||||
void Jit::Comp_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -723,7 +727,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VV2Op(u32 op) {
|
||||
void Jit::Comp_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -849,7 +853,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vi2f(u32 op) {
|
||||
void Jit::Comp_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes)
|
||||
@@ -895,7 +899,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vf2i(u32 op) {
|
||||
void Jit::Comp_Vf2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
DISABLE;
|
||||
|
||||
@@ -963,12 +967,12 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Mftv(u32 op)
|
||||
void Jit::Comp_Mftv(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int imm = op & 0xFF;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rt = _RT;
|
||||
switch ((op >> 21) & 0x1f)
|
||||
{
|
||||
case 3: //mfv / mfvc
|
||||
@@ -1024,7 +1028,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmtvc(u32 op) {
|
||||
void Jit::Comp_Vmtvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int vs = _VS;
|
||||
@@ -1045,7 +1049,7 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmmov(u32 op) {
|
||||
void Jit::Comp_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
// TODO: This probably ignores prefixes?
|
||||
@@ -1086,7 +1090,7 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_VScl(u32 op) {
|
||||
void Jit::Comp_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -1135,7 +1139,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmmul(u32 op) {
|
||||
void Jit::Comp_Vmmul(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
// TODO: This probably ignores prefixes?
|
||||
@@ -1177,11 +1181,11 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Vmscl(u32 op) {
|
||||
void Jit::Comp_Vmscl(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_Vtfm(u32 op) {
|
||||
void Jit::Comp_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
// TODO: This probably ignores prefixes? Or maybe uses D?
|
||||
@@ -1241,23 +1245,23 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_VCrs(u32 op) {
|
||||
void Jit::Comp_VCrs(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_VDet(u32 op) {
|
||||
void Jit::Comp_VDet(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_Vi2x(u32 op) {
|
||||
void Jit::Comp_Vi2x(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_Vx2i(u32 op) {
|
||||
void Jit::Comp_Vx2i(MIPSOpcode op) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
void Jit::Comp_VCrossQuat(u32 op) {
|
||||
void Jit::Comp_VCrossQuat(MIPSOpcode op) {
|
||||
// This op does not support prefixes.
|
||||
if (js.HasUnknownPrefix() || disablePrefixes)
|
||||
DISABLE;
|
||||
@@ -1303,7 +1307,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vcmp(u32 op) {
|
||||
void Jit::Comp_Vcmp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes)
|
||||
@@ -1441,7 +1445,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vcmov(u32 op) {
|
||||
void Jit::Comp_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes)
|
||||
@@ -1489,7 +1493,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Viim(u32 op) {
|
||||
void Jit::Comp_Viim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
u8 dreg;
|
||||
@@ -1503,7 +1507,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vfim(u32 op) {
|
||||
void Jit::Comp_Vfim(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -1523,7 +1527,7 @@ namespace MIPSComp
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
}
|
||||
|
||||
void Jit::Comp_Vcst(u32 op) {
|
||||
void Jit::Comp_Vcst(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
if (js.HasUnknownPrefix() || disablePrefixes) {
|
||||
@@ -1572,7 +1576,7 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
// Very heavily used by FF:CC
|
||||
void Jit::Comp_VRot(u32 op) {
|
||||
void Jit::Comp_VRot(MIPSOpcode op) {
|
||||
// Not sure about the ABI so I disable on non-Android.
|
||||
#if !defined(ARMV7) || !defined(ANDROID)
|
||||
DISABLE;
|
||||
|
||||
+12
-13
@@ -118,21 +118,20 @@ void Jit::ClearCache()
|
||||
GenerateFixedCode();
|
||||
}
|
||||
|
||||
void Jit::ClearCacheAt(u32 em_address)
|
||||
void Jit::ClearCacheAt(u32 em_address, int length)
|
||||
{
|
||||
// TODO: Properly.
|
||||
ClearCache();
|
||||
blocks.InvalidateICache(em_address, length);
|
||||
}
|
||||
|
||||
void Jit::CompileAt(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
MIPSCompileOp(op);
|
||||
}
|
||||
|
||||
void Jit::EatInstruction(u32 op)
|
||||
void Jit::EatInstruction(MIPSOpcode op)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
_dbg_assert_msg_(JIT, !(info & DELAYSLOT), "Never eat a branch op.");
|
||||
_dbg_assert_msg_(JIT, !js.inDelaySlot, "Never eat an instruction inside a delayslot.");
|
||||
|
||||
@@ -149,7 +148,7 @@ void Jit::CompileDelaySlot(int flags)
|
||||
MRS(R8); // Save flags register. R8 is preserved through function calls and is not allocated.
|
||||
|
||||
js.inDelaySlot = true;
|
||||
u32 op = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
MIPSOpcode op = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
MIPSCompileOp(op);
|
||||
js.inDelaySlot = false;
|
||||
|
||||
@@ -224,7 +223,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
||||
{
|
||||
gpr.SetCompilerPC(js.compilerPC); // Let it know for log messages
|
||||
fpr.SetCompilerPC(js.compilerPC);
|
||||
u32 inst = Memory::Read_Instruction(js.compilerPC);
|
||||
MIPSOpcode inst = Memory::Read_Instruction(js.compilerPC);
|
||||
js.downcountAmount += MIPSGetInstructionCycleEstimate(inst);
|
||||
|
||||
MIPSCompileOp(inst);
|
||||
@@ -266,13 +265,13 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
||||
return b->normalEntry;
|
||||
}
|
||||
|
||||
void Jit::Comp_RunBlock(u32 op)
|
||||
void Jit::Comp_RunBlock(MIPSOpcode op)
|
||||
{
|
||||
// This shouldn't be necessary, the dispatcher should catch us before we get here.
|
||||
ERROR_LOG(DYNA_REC, "Comp_RunBlock should never be reached!");
|
||||
}
|
||||
|
||||
void Jit::Comp_Generic(u32 op)
|
||||
void Jit::Comp_Generic(MIPSOpcode op)
|
||||
{
|
||||
FlushAll();
|
||||
MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
|
||||
@@ -281,12 +280,12 @@ void Jit::Comp_Generic(u32 op)
|
||||
SaveDowncount();
|
||||
MOVI2R(R0, js.compilerPC);
|
||||
MovToPC(R0);
|
||||
MOVI2R(R0, op);
|
||||
MOVI2R(R0, op.encoding);
|
||||
QuickCallFunction(R1, (void *)func);
|
||||
RestoreDowncount();
|
||||
}
|
||||
|
||||
const int info = MIPSGetInfo(op);
|
||||
const MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0)
|
||||
{
|
||||
// If it does eat them, it'll happen in MIPSCompileOp().
|
||||
@@ -383,7 +382,7 @@ void Jit::WriteSyscallExit()
|
||||
B((const void *)dispatcherCheckCoreState);
|
||||
}
|
||||
|
||||
void Jit::Comp_DoNothing(u32 op) { }
|
||||
void Jit::Comp_DoNothing(MIPSOpcode op) { }
|
||||
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
|
||||
+67
-67
@@ -152,7 +152,7 @@ public:
|
||||
// Compiled ops should ignore delay slots
|
||||
// the compiler will take care of them by itself
|
||||
// OR NOT
|
||||
void Comp_Generic(u32 op);
|
||||
void Comp_Generic(MIPSOpcode op);
|
||||
|
||||
void RunLoopUntil(u64 globalticks);
|
||||
|
||||
@@ -161,76 +161,76 @@ public:
|
||||
|
||||
void CompileDelaySlot(int flags);
|
||||
void CompileAt(u32 addr);
|
||||
void EatInstruction(u32 op);
|
||||
void Comp_RunBlock(u32 op);
|
||||
void EatInstruction(MIPSOpcode op);
|
||||
void Comp_RunBlock(MIPSOpcode op);
|
||||
|
||||
// Ops
|
||||
void Comp_ITypeMem(u32 op);
|
||||
void Comp_ITypeMem(MIPSOpcode op);
|
||||
|
||||
void Comp_RelBranch(u32 op);
|
||||
void Comp_RelBranchRI(u32 op);
|
||||
void Comp_FPUBranch(u32 op);
|
||||
void Comp_FPULS(u32 op);
|
||||
void Comp_FPUComp(u32 op);
|
||||
void Comp_Jump(u32 op);
|
||||
void Comp_JumpReg(u32 op);
|
||||
void Comp_Syscall(u32 op);
|
||||
void Comp_Break(u32 op);
|
||||
void Comp_RelBranch(MIPSOpcode op);
|
||||
void Comp_RelBranchRI(MIPSOpcode op);
|
||||
void Comp_FPUBranch(MIPSOpcode op);
|
||||
void Comp_FPULS(MIPSOpcode op);
|
||||
void Comp_FPUComp(MIPSOpcode op);
|
||||
void Comp_Jump(MIPSOpcode op);
|
||||
void Comp_JumpReg(MIPSOpcode op);
|
||||
void Comp_Syscall(MIPSOpcode op);
|
||||
void Comp_Break(MIPSOpcode op);
|
||||
|
||||
void Comp_IType(u32 op);
|
||||
void Comp_RType2(u32 op);
|
||||
void Comp_RType3(u32 op);
|
||||
void Comp_ShiftType(u32 op);
|
||||
void Comp_Allegrex(u32 op);
|
||||
void Comp_Allegrex2(u32 op);
|
||||
void Comp_VBranch(u32 op);
|
||||
void Comp_MulDivType(u32 op);
|
||||
void Comp_Special3(u32 op);
|
||||
void Comp_IType(MIPSOpcode op);
|
||||
void Comp_RType2(MIPSOpcode op);
|
||||
void Comp_RType3(MIPSOpcode op);
|
||||
void Comp_ShiftType(MIPSOpcode op);
|
||||
void Comp_Allegrex(MIPSOpcode op);
|
||||
void Comp_Allegrex2(MIPSOpcode op);
|
||||
void Comp_VBranch(MIPSOpcode op);
|
||||
void Comp_MulDivType(MIPSOpcode op);
|
||||
void Comp_Special3(MIPSOpcode op);
|
||||
|
||||
void Comp_FPU3op(u32 op);
|
||||
void Comp_FPU2op(u32 op);
|
||||
void Comp_mxc1(u32 op);
|
||||
void Comp_FPU3op(MIPSOpcode op);
|
||||
void Comp_FPU2op(MIPSOpcode op);
|
||||
void Comp_mxc1(MIPSOpcode op);
|
||||
|
||||
void Comp_DoNothing(u32 op);
|
||||
void Comp_DoNothing(MIPSOpcode op);
|
||||
|
||||
void Comp_SV(u32 op);
|
||||
void Comp_SVQ(u32 op);
|
||||
void Comp_VPFX(u32 op);
|
||||
void Comp_VVectorInit(u32 op);
|
||||
void Comp_VMatrixInit(u32 op);
|
||||
void Comp_VDot(u32 op);
|
||||
void Comp_VecDo3(u32 op);
|
||||
void Comp_VV2Op(u32 op);
|
||||
void Comp_Mftv(u32 op);
|
||||
void Comp_Vmtvc(u32 op);
|
||||
void Comp_Vmmov(u32 op);
|
||||
void Comp_VScl(u32 op);
|
||||
void Comp_Vmmul(u32 op);
|
||||
void Comp_Vmscl(u32 op);
|
||||
void Comp_Vtfm(u32 op);
|
||||
void Comp_VHdp(u32 op);
|
||||
void Comp_VCrs(u32 op);
|
||||
void Comp_VDet(u32 op);
|
||||
void Comp_Vi2x(u32 op);
|
||||
void Comp_Vx2i(u32 op);
|
||||
void Comp_Vf2i(u32 op);
|
||||
void Comp_Vi2f(u32 op);
|
||||
void Comp_Vcst(u32 op);
|
||||
void Comp_Vhoriz(u32 op);
|
||||
void Comp_VRot(u32 op);
|
||||
void Comp_VIdt(u32 op);
|
||||
void Comp_Vcmp(u32 op);
|
||||
void Comp_Vcmov(u32 op);
|
||||
void Comp_Viim(u32 op);
|
||||
void Comp_Vfim(u32 op);
|
||||
void Comp_VCrossQuat(u32 op);
|
||||
void Comp_Vsge(u32 op);
|
||||
void Comp_Vslt(u32 op);
|
||||
void Comp_SV(MIPSOpcode op);
|
||||
void Comp_SVQ(MIPSOpcode op);
|
||||
void Comp_VPFX(MIPSOpcode op);
|
||||
void Comp_VVectorInit(MIPSOpcode op);
|
||||
void Comp_VMatrixInit(MIPSOpcode op);
|
||||
void Comp_VDot(MIPSOpcode op);
|
||||
void Comp_VecDo3(MIPSOpcode op);
|
||||
void Comp_VV2Op(MIPSOpcode op);
|
||||
void Comp_Mftv(MIPSOpcode op);
|
||||
void Comp_Vmtvc(MIPSOpcode op);
|
||||
void Comp_Vmmov(MIPSOpcode op);
|
||||
void Comp_VScl(MIPSOpcode op);
|
||||
void Comp_Vmmul(MIPSOpcode op);
|
||||
void Comp_Vmscl(MIPSOpcode op);
|
||||
void Comp_Vtfm(MIPSOpcode op);
|
||||
void Comp_VHdp(MIPSOpcode op);
|
||||
void Comp_VCrs(MIPSOpcode op);
|
||||
void Comp_VDet(MIPSOpcode op);
|
||||
void Comp_Vi2x(MIPSOpcode op);
|
||||
void Comp_Vx2i(MIPSOpcode op);
|
||||
void Comp_Vf2i(MIPSOpcode op);
|
||||
void Comp_Vi2f(MIPSOpcode op);
|
||||
void Comp_Vcst(MIPSOpcode op);
|
||||
void Comp_Vhoriz(MIPSOpcode op);
|
||||
void Comp_VRot(MIPSOpcode op);
|
||||
void Comp_VIdt(MIPSOpcode op);
|
||||
void Comp_Vcmp(MIPSOpcode op);
|
||||
void Comp_Vcmov(MIPSOpcode op);
|
||||
void Comp_Viim(MIPSOpcode op);
|
||||
void Comp_Vfim(MIPSOpcode op);
|
||||
void Comp_VCrossQuat(MIPSOpcode op);
|
||||
void Comp_Vsge(MIPSOpcode op);
|
||||
void Comp_Vslt(MIPSOpcode op);
|
||||
|
||||
JitBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
void ClearCache();
|
||||
void ClearCacheAt(u32 em_address);
|
||||
void ClearCacheAt(u32 em_address, int length = 4);
|
||||
|
||||
void EatPrefix() { js.EatPrefix(); }
|
||||
|
||||
@@ -251,17 +251,17 @@ private:
|
||||
void WriteSyscallExit();
|
||||
|
||||
// Utility compilation functions
|
||||
void BranchFPFlag(u32 op, ArmGen::CCFlags cc, bool likely);
|
||||
void BranchVFPUFlag(u32 op, ArmGen::CCFlags cc, bool likely);
|
||||
void BranchRSZeroComp(u32 op, ArmGen::CCFlags cc, bool andLink, bool likely);
|
||||
void BranchRSRTComp(u32 op, ArmGen::CCFlags cc, bool likely);
|
||||
void BranchFPFlag(MIPSOpcode op, ArmGen::CCFlags cc, bool likely);
|
||||
void BranchVFPUFlag(MIPSOpcode op, ArmGen::CCFlags cc, bool likely);
|
||||
void BranchRSZeroComp(MIPSOpcode op, ArmGen::CCFlags cc, bool andLink, bool likely);
|
||||
void BranchRSRTComp(MIPSOpcode op, ArmGen::CCFlags cc, bool likely);
|
||||
|
||||
// Utilities to reduce duplicated code
|
||||
void CompImmLogic(int rs, int rt, u32 uimm, void (ARMXEmitter::*arith)(ARMReg dst, ARMReg src, Operand2 op2), u32 (*eval)(u32 a, u32 b));
|
||||
void CompType3(int rd, int rs, int rt, void (ARMXEmitter::*arithOp2)(ARMReg dst, ARMReg rm, Operand2 rn), u32 (*eval)(u32 a, u32 b), bool isSub = false);
|
||||
|
||||
void CompShiftImm(u32 op, ArmGen::ShiftType shiftType);
|
||||
void CompShiftVar(u32 op, ArmGen::ShiftType shiftType);
|
||||
void CompShiftImm(MIPSOpcode op, ArmGen::ShiftType shiftType);
|
||||
void CompShiftVar(MIPSOpcode op, ArmGen::ShiftType shiftType);
|
||||
|
||||
void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz);
|
||||
void ApplyPrefixD(const u8 *vregs, VectorSize sz);
|
||||
@@ -307,7 +307,7 @@ public:
|
||||
const u8 *breakpointBailout;
|
||||
};
|
||||
|
||||
typedef void (Jit::*MIPSCompileFunc)(u32 opcode);
|
||||
typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode);
|
||||
|
||||
} // namespace MIPSComp
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Core/Core.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Reporting.h"
|
||||
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSTables.h"
|
||||
@@ -157,7 +158,7 @@ void JitBlockCache::FinalizeBlock(int block_num, bool block_link)
|
||||
JitBlock &b = blocks[block_num];
|
||||
|
||||
b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress);
|
||||
u32 opcode = GetEmuHackOpForBlock(block_num);
|
||||
MIPSOpcode opcode = GetEmuHackOpForBlock(block_num);
|
||||
Memory::Write_Opcode_JIT(b.originalAddress, opcode);
|
||||
|
||||
// Convert the logical address to a physical address for the block map
|
||||
@@ -215,25 +216,28 @@ int binary_search(JitBlock blocks[], const u8 *baseoff, int imin, int imax)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int JitBlockCache::GetBlockNumberFromEmuHackOp(u32 inst) const {
|
||||
int JitBlockCache::GetBlockNumberFromEmuHackOp(MIPSOpcode inst) const {
|
||||
if (!num_blocks || !MIPS_IS_EMUHACK(inst)) // definitely not a JIT block
|
||||
return -1;
|
||||
int off = (inst & MIPS_EMUHACK_VALUE_MASK);
|
||||
|
||||
const u8 *baseoff = codeBlock_->GetBasePtr() + off;
|
||||
return binary_search(blocks, baseoff, 0, num_blocks-1);
|
||||
int bl = binary_search(blocks, baseoff, 0, num_blocks-1);
|
||||
if (blocks[bl].invalid)
|
||||
return -1;
|
||||
return bl;
|
||||
}
|
||||
|
||||
u32 JitBlockCache::GetEmuHackOpForBlock(int blockNum) const {
|
||||
MIPSOpcode JitBlockCache::GetEmuHackOpForBlock(int blockNum) const {
|
||||
int off = (int)(blocks[blockNum].normalEntry - codeBlock_->GetBasePtr());
|
||||
return (MIPS_EMUHACK_OPCODE | off);
|
||||
return MIPSOpcode(MIPS_EMUHACK_OPCODE | off);
|
||||
}
|
||||
|
||||
int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr)
|
||||
{
|
||||
if (!blocks)
|
||||
return -1;
|
||||
u32 inst = Memory::Read_U32(addr);
|
||||
MIPSOpcode inst = MIPSOpcode(Memory::Read_U32(addr));
|
||||
int bl = GetBlockNumberFromEmuHackOp(inst);
|
||||
if (bl < 0)
|
||||
return -1;
|
||||
@@ -249,12 +253,12 @@ void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector<int>
|
||||
block_numbers->push_back(i);
|
||||
}
|
||||
|
||||
u32 JitBlockCache::GetOriginalFirstOp(int block_num)
|
||||
MIPSOpcode JitBlockCache::GetOriginalFirstOp(int block_num)
|
||||
{
|
||||
if (block_num >= num_blocks || block_num < 0)
|
||||
{
|
||||
//PanicAlert("JitBlockCache::GetOriginalFirstOp - block_num = %u is out of range", block_num);
|
||||
return block_num;
|
||||
return MIPSOpcode(block_num);
|
||||
}
|
||||
return blocks[block_num].originalFirstOpcode;
|
||||
}
|
||||
@@ -327,7 +331,7 @@ void JitBlockCache::UnlinkBlock(int i)
|
||||
void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||
{
|
||||
if (block_num < 0 || block_num >= num_blocks) {
|
||||
ERROR_LOG(JIT, "DestroyBlock: Invalid block number %d", block_num);
|
||||
ERROR_LOG_REPORT(JIT, "DestroyBlock: Invalid block number %d", block_num);
|
||||
return;
|
||||
}
|
||||
JitBlock &b = blocks[block_num];
|
||||
@@ -337,9 +341,9 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||
return;
|
||||
}
|
||||
b.invalid = true;
|
||||
if (Memory::ReadUnchecked_U32(b.originalAddress) == GetEmuHackOpForBlock(block_num))
|
||||
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
|
||||
b.normalEntry = 0;
|
||||
if (Memory::ReadUnchecked_U32(b.originalAddress) == GetEmuHackOpForBlock(block_num).encoding)
|
||||
Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode);
|
||||
// It's not safe to set normalEntry to 0 here, since we use a binary search.
|
||||
|
||||
UnlinkBlock(block_num);
|
||||
|
||||
@@ -380,6 +384,7 @@ void JitBlockCache::InvalidateICache(u32 address, const u32 length)
|
||||
|
||||
// destroy JIT blocks
|
||||
// !! this works correctly under assumption that any two overlapping blocks end at the same address
|
||||
// TODO: This may not be a safe assumption with jit continuing enabled.
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1;
|
||||
while (it2 != block_map.end() && it2->first.second < pAddr + length) {
|
||||
DestroyBlock(it2->second, true);
|
||||
|
||||
@@ -65,7 +65,7 @@ struct JitBlock {
|
||||
u32 exitAddress[MAX_JIT_BLOCK_EXITS]; // 0xFFFFFFFF == unknown
|
||||
|
||||
u32 originalAddress;
|
||||
u32 originalFirstOpcode; //to be able to restore
|
||||
MIPSOpcode originalFirstOpcode; //to be able to restore
|
||||
u16 codeSize;
|
||||
u16 originalSize;
|
||||
u16 blockNum;
|
||||
@@ -107,9 +107,9 @@ public:
|
||||
// Returns a list of block numbers - only one block can start at a particular address, but they CAN overlap.
|
||||
// This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime.
|
||||
void GetBlockNumbersFromAddress(u32 em_address, std::vector<int> *block_numbers);
|
||||
int GetBlockNumberFromEmuHackOp(u32 inst) const;
|
||||
int GetBlockNumberFromEmuHackOp(MIPSOpcode inst) const;
|
||||
|
||||
u32 GetOriginalFirstOp(int block_num);
|
||||
MIPSOpcode GetOriginalFirstOp(int block_num);
|
||||
|
||||
// DOES NOT WORK CORRECTLY WITH JIT INLINING
|
||||
void InvalidateICache(u32 address, const u32 length);
|
||||
@@ -120,7 +120,7 @@ private:
|
||||
void LinkBlock(int i);
|
||||
void UnlinkBlock(int i);
|
||||
|
||||
u32 GetEmuHackOpForBlock(int block_num) const;
|
||||
MIPSOpcode GetEmuHackOpForBlock(int block_num) const;
|
||||
|
||||
MIPSState *mips;
|
||||
CodeBlock *codeBlock_;
|
||||
|
||||
@@ -44,5 +44,4 @@
|
||||
|
||||
namespace MIPSComp {
|
||||
extern Jit *jit;
|
||||
extern const float cst_constants[32];
|
||||
}
|
||||
+8
-1
@@ -60,7 +60,7 @@ MIPSDebugInterface *currentDebugMIPS = &debugr4k;
|
||||
#define M_SQRT1_2 0.707106781186547524401f
|
||||
#endif
|
||||
|
||||
extern const float cst_constants[32] = {
|
||||
const float cst_constants[32] = {
|
||||
0,
|
||||
std::numeric_limits<float>::max(), // all these are verified on real PSP
|
||||
sqrtf(2.0f),
|
||||
@@ -230,6 +230,13 @@ u32 MIPSState::ReadFCR(int reg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MIPSState::InvalidateICache(u32 address, int length)
|
||||
{
|
||||
// Only really applies to jit.
|
||||
if (MIPSComp::jit)
|
||||
MIPSComp::jit->ClearCacheAt(address, length);
|
||||
}
|
||||
|
||||
|
||||
// Interrupts should be served directly on the running thread.
|
||||
void MIPSState::Irq()
|
||||
|
||||
+9
-9
@@ -17,11 +17,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "../CPU.h"
|
||||
#include "Globals.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/CPU.h"
|
||||
#include "util/random/rng.h"
|
||||
|
||||
enum
|
||||
typedef Memory::Opcode MIPSOpcode;
|
||||
|
||||
enum MIPSGPReg
|
||||
{
|
||||
MIPS_REG_ZERO=0,
|
||||
MIPS_REG_COMPILER_SCRATCH=1,
|
||||
@@ -53,6 +56,7 @@ enum
|
||||
|
||||
// ID for mipscall "callback" is stored here - from JPCSP
|
||||
MIPS_REG_CALL_ID=MIPS_REG_S0,
|
||||
MIPS_REG_INVALID=-1,
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -164,6 +168,8 @@ public:
|
||||
|
||||
void SingleStep();
|
||||
int RunLoopUntil(u64 globalTicks);
|
||||
// To clear jit caches, etc.
|
||||
void InvalidateICache(u32 address, int length = 4);
|
||||
|
||||
// for logging messages only.
|
||||
const char *DisasmAt(u32 compilerPC);
|
||||
@@ -177,12 +183,6 @@ extern MIPSState *currentMIPS;
|
||||
extern MIPSDebugInterface *currentDebugMIPS;
|
||||
extern MIPSState mipsr4k;
|
||||
|
||||
void MIPS_Init();
|
||||
int MIPS_SingleStep();
|
||||
|
||||
void MIPS_Shutdown();
|
||||
|
||||
void MIPS_Irq();
|
||||
void MIPS_SWI();
|
||||
|
||||
extern const float cst_constants[32];
|
||||
+100
-151
@@ -16,186 +16,135 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <map>
|
||||
#include "../../Globals.h"
|
||||
#include "Globals.h"
|
||||
|
||||
#include "MIPS.h"
|
||||
#include "MIPSTables.h"
|
||||
#include "MIPSAnalyst.h"
|
||||
#include "MIPSCodeUtils.h"
|
||||
#include "../Debugger/SymbolMap.h"
|
||||
#include "../Debugger/DebugInterface.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSTables.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/Debugger/DebugInterface.h"
|
||||
|
||||
using namespace MIPSCodeUtils;
|
||||
using namespace std;
|
||||
|
||||
namespace MIPSAnalyst
|
||||
{
|
||||
RegisterAnalysisResults regAnal[32];
|
||||
RegisterAnalysisResults total[32];
|
||||
int numAnalysisDone=0;
|
||||
|
||||
int GetOutReg(u32 op)
|
||||
{
|
||||
u32 opinfo = MIPSGetInfo(op);
|
||||
if (opinfo & OUT_RT)
|
||||
return MIPS_GET_RT(op);
|
||||
if (opinfo & OUT_RD)
|
||||
return MIPS_GET_RD(op);
|
||||
if (opinfo & OUT_RA)
|
||||
return MIPS_REG_RA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ReadsFromReg(u32 op, u32 reg)
|
||||
{
|
||||
u32 opinfo = MIPSGetInfo(op);
|
||||
if (opinfo & IN_RT)
|
||||
{
|
||||
if (MIPS_GET_RT(opinfo) == reg)
|
||||
return true;
|
||||
}
|
||||
if (opinfo & IN_RS)
|
||||
{
|
||||
if (MIPS_GET_RS(opinfo) == reg)
|
||||
return true;
|
||||
}
|
||||
return false; //TODO: there are more cases!
|
||||
}
|
||||
|
||||
// TODO: Remove me?
|
||||
bool IsDelaySlotNice(u32 branch, u32 delayslot)
|
||||
{
|
||||
int outReg = GetOutReg(delayslot);
|
||||
if (outReg != -1)
|
||||
{
|
||||
if (ReadsFromReg(branch, outReg))
|
||||
{
|
||||
return false; //evil :(
|
||||
// Only can ever output a single reg.
|
||||
MIPSGPReg GetOutGPReg(MIPSOpcode op) {
|
||||
MIPSInfo opinfo = MIPSGetInfo(op);
|
||||
if ((opinfo & IS_VFPU) == 0) {
|
||||
if (opinfo & OUT_RT) {
|
||||
return MIPS_GET_RT(op);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; //aggh this should be true but doesn't work
|
||||
if (opinfo & OUT_RD) {
|
||||
return MIPS_GET_RD(op);
|
||||
}
|
||||
if (opinfo & OUT_RA) {
|
||||
return MIPS_REG_RA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for FPU flag
|
||||
if ((MIPSGetInfo(delayslot) & OUT_FPUFLAG) && (MIPSGetInfo(branch) & IN_FPUFLAG))
|
||||
return false;
|
||||
|
||||
return true; //nice :)
|
||||
}
|
||||
return MIPS_REG_INVALID;
|
||||
}
|
||||
|
||||
bool IsDelaySlotNiceReg(u32 branchOp, u32 op, int reg1, int reg2)
|
||||
{
|
||||
bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg) {
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_VFPU) == 0) {
|
||||
if ((info & IN_RS) != 0 && MIPS_GET_RS(op) == reg) {
|
||||
return true;
|
||||
}
|
||||
if ((info & IN_RT) != 0 && MIPS_GET_RT(op) == reg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2) {
|
||||
// $0 is never an out reg, it's always 0.
|
||||
if (reg1 != 0 && GetOutReg(op) == reg1)
|
||||
if (reg1 != MIPS_REG_ZERO && GetOutGPReg(op) == reg1) {
|
||||
return false;
|
||||
if (reg2 != 0 && GetOutReg(op) == reg2)
|
||||
}
|
||||
if (reg2 != MIPS_REG_ZERO && GetOutGPReg(op) == reg2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsDelaySlotNiceVFPU(u32 branchOp, u32 op)
|
||||
{
|
||||
bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op) {
|
||||
// TODO: There may be IS_VFPU cases which are safe...
|
||||
return (MIPSGetInfo(op) & IS_VFPU) == 0;
|
||||
}
|
||||
|
||||
bool IsDelaySlotNiceFPU(u32 branchOp, u32 op)
|
||||
{
|
||||
bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op) {
|
||||
return (MIPSGetInfo(op) & OUT_FPUFLAG) == 0;
|
||||
}
|
||||
|
||||
bool IsSyscall(u32 op)
|
||||
{
|
||||
bool IsSyscall(MIPSOpcode op) {
|
||||
// Syscalls look like this: 0000 00-- ---- ---- ---- --00 1100
|
||||
return (op >> 26) == 0 && (op & 0x3f) == 12;
|
||||
}
|
||||
|
||||
void Analyze(u32 address)
|
||||
{
|
||||
AnalysisResults Analyze(u32 address) {
|
||||
const int MAX_ANALYZE = 10000;
|
||||
|
||||
AnalysisResults results;
|
||||
|
||||
//set everything to -1 (FF)
|
||||
memset(regAnal, 255, sizeof(AnalysisResults)*32);
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
regAnal[i].used=false;
|
||||
regAnal[i].readCount=0;
|
||||
regAnal[i].writeCount=0;
|
||||
regAnal[i].readAsAddrCount=0;
|
||||
memset(&results, 255, sizeof(AnalysisResults));
|
||||
for (int i = 0; i < MIPS_NUM_GPRS; i++) {
|
||||
results.r[i].used = false;
|
||||
results.r[i].readCount = 0;
|
||||
results.r[i].writeCount = 0;
|
||||
results.r[i].readAsAddrCount = 0;
|
||||
}
|
||||
|
||||
u32 addr = address;
|
||||
bool exitFlag = false;
|
||||
while (true)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
u32 info = MIPSGetInfo(op);
|
||||
for (u32 addr = address, endAddr = address + MAX_ANALYZE; addr <= endAddr; addr += 4) {
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
|
||||
for (int reg=0; reg < 32; reg++)
|
||||
{
|
||||
int rs = MIPS_GET_RS(op);
|
||||
int rt = MIPS_GET_RT(op);
|
||||
int rd = MIPS_GET_RD(op);
|
||||
MIPSGPReg rs = MIPS_GET_RS(op);
|
||||
MIPSGPReg rt = MIPS_GET_RT(op);
|
||||
|
||||
if (
|
||||
((info & IN_RS) && (info & IN_RS_ADDR) == IN_RS && (rs == reg)) ||
|
||||
((info & IN_RT) && (rt == reg)))
|
||||
{
|
||||
if (regAnal[reg].firstRead == -1)
|
||||
regAnal[reg].firstRead = addr;
|
||||
regAnal[reg].lastRead = addr;
|
||||
regAnal[reg].readCount++;
|
||||
regAnal[reg].used=true;
|
||||
}
|
||||
if (
|
||||
((info & IN_RS_ADDR) && (rs == reg))
|
||||
)
|
||||
{
|
||||
if (regAnal[reg].firstReadAsAddr == -1)
|
||||
regAnal[reg].firstReadAsAddr = addr;
|
||||
regAnal[reg].lastReadAsAddr = addr;
|
||||
regAnal[reg].readAsAddrCount++;
|
||||
regAnal[reg].used=true;
|
||||
}
|
||||
if (
|
||||
((info & OUT_RT) && (rt == reg)) ||
|
||||
((info & OUT_RD) && (rd == reg)) ||
|
||||
((info & OUT_RA) && (reg == MIPS_REG_RA))
|
||||
)
|
||||
{
|
||||
if (regAnal[reg].firstWrite == -1)
|
||||
regAnal[reg].firstWrite = addr;
|
||||
regAnal[reg].lastWrite = addr;
|
||||
regAnal[reg].writeCount++;
|
||||
regAnal[reg].used=true;
|
||||
if (info & IN_RS) {
|
||||
if ((info & IN_RS_ADDR) == IN_RS_ADDR) {
|
||||
results.r[rs].MarkReadAsAddr(addr);
|
||||
} else {
|
||||
results.r[rs].MarkRead(addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (exitFlag) //delay slot done, let's quit!
|
||||
break;
|
||||
|
||||
if ((info & IS_JUMP) || (info & IS_CONDBRANCH))
|
||||
{
|
||||
exitFlag = true; // now do the delay slot
|
||||
if (info & IN_RT) {
|
||||
results.r[rt].MarkRead(addr);
|
||||
}
|
||||
|
||||
addr += 4;
|
||||
MIPSGPReg outReg = GetOutGPReg(op);
|
||||
if (outReg != MIPS_REG_INVALID) {
|
||||
results.r[outReg].MarkWrite(addr);
|
||||
}
|
||||
|
||||
if (info & DELAYSLOT)
|
||||
{
|
||||
// Let's just finish the delay slot before bailing.
|
||||
endAddr = addr + 4;
|
||||
}
|
||||
}
|
||||
|
||||
int numUsedRegs=0;
|
||||
static int totalUsedRegs=0;
|
||||
static int numAnalyzings=0;
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
if (regAnal[i].used)
|
||||
for (int i = 0; i < MIPS_NUM_GPRS; i++) {
|
||||
if (results.r[i].used) {
|
||||
numUsedRegs++;
|
||||
}
|
||||
}
|
||||
totalUsedRegs+=numUsedRegs;
|
||||
numAnalyzings++;
|
||||
DEBUG_LOG(CPU,"[ %08x ] Used regs: %i Average: %f",address,numUsedRegs,(float)totalUsedRegs/(float)numAnalyzings);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,12 +185,12 @@ namespace MIPSAnalyst
|
||||
}
|
||||
|
||||
|
||||
bool IsRegisterUsed(u32 reg, u32 addr)
|
||||
bool IsRegisterUsed(MIPSGPReg reg, u32 addr)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
|
||||
if ((info & IN_RS) && (MIPS_GET_RS(op) == reg))
|
||||
return true;
|
||||
@@ -271,8 +220,8 @@ namespace MIPSAnalyst
|
||||
for (u32 addr = f.start; addr <= f.end; addr += 4)
|
||||
{
|
||||
u32 validbits = 0xFFFFFFFF;
|
||||
u32 instr = Memory::Read_Instruction(addr);
|
||||
u32 flags = MIPSGetInfo(instr);
|
||||
MIPSOpcode instr = Memory::Read_Instruction(addr);
|
||||
MIPSInfo flags = MIPSGetInfo(instr);
|
||||
if (flags & IN_IMM16)
|
||||
validbits&=~0xFFFF;
|
||||
if (flags & IN_IMM26)
|
||||
@@ -303,7 +252,7 @@ namespace MIPSAnalyst
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
u32 target = GetBranchTargetNoRA(addr);
|
||||
if (target != INVALIDTARGET)
|
||||
{
|
||||
@@ -378,7 +327,7 @@ namespace MIPSAnalyst
|
||||
|
||||
void StoreHashMap(const char *filename)
|
||||
{
|
||||
FILE *file = fopen(filename,"wb");
|
||||
FILE *file = File::OpenCFile(filename,"wb");
|
||||
u32 num = 0;
|
||||
if(fwrite(&num,4,1,file) != 1) //fill in later
|
||||
WARN_LOG(CPU, "Could not store hash map %s", filename);
|
||||
@@ -412,7 +361,7 @@ namespace MIPSAnalyst
|
||||
HashFunctions();
|
||||
UpdateHashToFunctionMap();
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
FILE *file = File::OpenCFile(filename, "rb");
|
||||
int num;
|
||||
if(fread(&num,4,1,file) == 1) {
|
||||
for (int i=0; i<num; i++)
|
||||
@@ -452,10 +401,10 @@ namespace MIPSAnalyst
|
||||
LOG(CPU,"Precompiled %i straight leaf functions",count);*/
|
||||
}
|
||||
|
||||
std::vector<int> GetInputRegs(u32 op)
|
||||
std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op)
|
||||
{
|
||||
std::vector<int> vec;
|
||||
u32 info = MIPSGetInfo(op);
|
||||
std::vector<MIPSGPReg> vec;
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_VFPU) == 0)
|
||||
{
|
||||
if (info & IN_RS) vec.push_back(MIPS_GET_RS(op));
|
||||
@@ -463,10 +412,10 @@ namespace MIPSAnalyst
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
std::vector<int> GetOutputRegs(u32 op)
|
||||
std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op)
|
||||
{
|
||||
std::vector<int> vec;
|
||||
u32 info = MIPSGetInfo(op);
|
||||
std::vector<MIPSGPReg> vec;
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_VFPU) == 0)
|
||||
{
|
||||
if (info & OUT_RD) vec.push_back(MIPS_GET_RD(op));
|
||||
@@ -489,8 +438,8 @@ namespace MIPSAnalyst
|
||||
info.opcodeAddress = address;
|
||||
info.encodedOpcode = Memory::Read_Instruction(address);
|
||||
|
||||
u32 op = info.encodedOpcode;
|
||||
u32 opInfo = MIPSGetInfo(op);
|
||||
MIPSOpcode op = info.encodedOpcode;
|
||||
MIPSInfo opInfo = MIPSGetInfo(op);
|
||||
info.isLikelyBranch = (opInfo & LIKELY) != 0;
|
||||
|
||||
//j , jal, ...
|
||||
@@ -505,7 +454,7 @@ namespace MIPSAnalyst
|
||||
if (opInfo & IN_RS) // to register
|
||||
{
|
||||
info.isBranchToRegister = true;
|
||||
info.branchRegisterNum = MIPS_GET_RS(op);
|
||||
info.branchRegisterNum = (int)MIPS_GET_RS(op);
|
||||
info.branchTarget = cpu->GetRegValue(0,info.branchRegisterNum);
|
||||
} else { // to immediate
|
||||
info.branchTarget = GetJumpTarget(address);
|
||||
@@ -517,7 +466,7 @@ namespace MIPSAnalyst
|
||||
{
|
||||
info.isConditional = true;
|
||||
|
||||
u32 rt = cpu->GetRegValue(0,MIPS_GET_RT(op));
|
||||
u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
|
||||
switch (opInfo & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
@@ -541,8 +490,8 @@ namespace MIPSAnalyst
|
||||
info.isLinkedBranch = true;
|
||||
}
|
||||
|
||||
u32 rt = cpu->GetRegValue(0,MIPS_GET_RT(op));
|
||||
u32 rs = cpu->GetRegValue(0,MIPS_GET_RS(op));
|
||||
u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
|
||||
u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op));
|
||||
switch (opInfo & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
@@ -596,7 +545,7 @@ namespace MIPSAnalyst
|
||||
info.dataSize = 16;
|
||||
}
|
||||
|
||||
u32 rs = cpu->GetRegValue(0,MIPS_GET_RS(op));
|
||||
u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op));
|
||||
s16 imm16 = op & 0xFFFF;
|
||||
info.dataAddress = rs + imm16;
|
||||
}
|
||||
|
||||
+46
-21
@@ -17,15 +17,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "Globals.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
|
||||
class DebugInterface;
|
||||
|
||||
namespace MIPSAnalyst
|
||||
{
|
||||
void Analyze(u32 address);
|
||||
struct RegisterAnalysisResults
|
||||
{
|
||||
const int MIPS_NUM_GPRS = 32;
|
||||
|
||||
struct RegisterAnalysisResults {
|
||||
bool used;
|
||||
int firstRead;
|
||||
int lastRead;
|
||||
@@ -37,32 +38,56 @@ namespace MIPSAnalyst
|
||||
int readCount;
|
||||
int writeCount;
|
||||
int readAsAddrCount;
|
||||
bool usesVFPU;
|
||||
|
||||
int TotalReadCount() {return readCount + readAsAddrCount;}
|
||||
int FirstRead() {return firstReadAsAddr < firstRead ? firstReadAsAddr : firstRead;}
|
||||
int LastRead() {return lastReadAsAddr > lastRead ? lastReadAsAddr : lastRead;}
|
||||
int TotalReadCount() const { return readCount + readAsAddrCount; }
|
||||
int FirstRead() const { return firstReadAsAddr < firstRead ? firstReadAsAddr : firstRead; }
|
||||
int LastRead() const { return lastReadAsAddr > lastRead ? lastReadAsAddr : lastRead; }
|
||||
|
||||
void MarkRead(u32 addr) {
|
||||
if (firstRead == -1)
|
||||
firstRead = addr;
|
||||
lastRead = addr;
|
||||
readCount++;
|
||||
used = true;
|
||||
}
|
||||
|
||||
void MarkReadAsAddr(u32 addr) {
|
||||
if (firstReadAsAddr == -1)
|
||||
firstReadAsAddr = addr;
|
||||
lastReadAsAddr = addr;
|
||||
readAsAddrCount++;
|
||||
used = true;
|
||||
}
|
||||
|
||||
void MarkWrite(u32 addr) {
|
||||
if (firstWrite == -1)
|
||||
firstWrite = addr;
|
||||
lastWrite = addr;
|
||||
writeCount++;
|
||||
used = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct AnalysisResults
|
||||
{
|
||||
int x;
|
||||
struct AnalysisResults {
|
||||
RegisterAnalysisResults r[MIPS_NUM_GPRS];
|
||||
};
|
||||
|
||||
AnalysisResults Analyze(u32 address);
|
||||
|
||||
|
||||
bool IsRegisterUsed(u32 reg, u32 addr);
|
||||
void ScanForFunctions(u32 startAddr, u32 endAddr);
|
||||
void CompileLeafs();
|
||||
|
||||
std::vector<int> GetInputRegs(u32 op);
|
||||
std::vector<int> GetOutputRegs(u32 op);
|
||||
std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op);
|
||||
std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op);
|
||||
|
||||
int GetOutReg(u32 op);
|
||||
bool ReadsFromReg(u32 op, u32 reg);
|
||||
bool IsDelaySlotNice(u32 branch, u32 delayslot);
|
||||
bool IsDelaySlotNiceReg(u32 branchOp, u32 op, int reg1, int reg2 = 0);
|
||||
bool IsDelaySlotNiceVFPU(u32 branchOp, u32 op);
|
||||
bool IsDelaySlotNiceFPU(u32 branchOp, u32 op);
|
||||
bool IsSyscall(u32 op);
|
||||
MIPSGPReg GetOutGPReg(MIPSOpcode op);
|
||||
bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg);
|
||||
bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2 = MIPS_REG_ZERO);
|
||||
bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
||||
bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
||||
bool IsSyscall(MIPSOpcode op);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
@@ -70,7 +95,7 @@ namespace MIPSAnalyst
|
||||
{
|
||||
DebugInterface* cpu;
|
||||
u32 opcodeAddress;
|
||||
u32 encodedOpcode;
|
||||
MIPSOpcode encodedOpcode;
|
||||
|
||||
// shared between branches and conditional moves
|
||||
bool isConditional;
|
||||
|
||||
+29
-12
@@ -2,10 +2,27 @@
|
||||
#include "stdafx.h"
|
||||
#endif
|
||||
#include "MIPSAsm.h"
|
||||
#include <cstdarg>
|
||||
|
||||
namespace MIPSAsm
|
||||
{
|
||||
|
||||
char errorMessage[512];
|
||||
|
||||
void SetAssembleError(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args,format);
|
||||
vsprintf(errorMessage,format,args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
char* GetAssembleError()
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
void SplitLine(const char* Line, char* Name, char* Arguments)
|
||||
{
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
@@ -30,7 +47,7 @@ void SplitLine(const char* Line, char* Name, char* Arguments)
|
||||
*Arguments = 0;
|
||||
}
|
||||
|
||||
bool MipsAssembleOpcode(char* line, DebugInterface* cpu, u32 address, u32& dest)
|
||||
bool MipsAssembleOpcode(const char* line, DebugInterface* cpu, u32 address, u32& dest)
|
||||
{
|
||||
char name[64],args[256];
|
||||
SplitLine(line,name,args);
|
||||
@@ -51,7 +68,7 @@ bool MipsAssembleOpcode(char* line, DebugInterface* cpu, u32 address, u32& dest)
|
||||
return true;
|
||||
}
|
||||
|
||||
int MipsGetRegister(char* source, int& RetLen)
|
||||
int MipsGetRegister(const char* source, int& RetLen)
|
||||
{
|
||||
for (int z = 0; MipsRegister[z].name != NULL; z++)
|
||||
{
|
||||
@@ -69,7 +86,7 @@ int MipsGetRegister(char* source, int& RetLen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MipsGetFloatRegister(char* source, int& RetLen)
|
||||
int MipsGetFloatRegister(const char* source, int& RetLen)
|
||||
{
|
||||
for (int z = 0; MipsFloatRegister[z].name != NULL; z++)
|
||||
{
|
||||
@@ -87,7 +104,7 @@ int MipsGetFloatRegister(char* source, int& RetLen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool MipsCheckImmediate(char* Source, char* Dest, int& RetLen)
|
||||
bool MipsCheckImmediate(const char* Source, char* Dest, int& RetLen)
|
||||
{
|
||||
int BufferPos = 0;
|
||||
int l;
|
||||
@@ -166,9 +183,9 @@ bool CMipsInstruction::Load(char* Name, char* Params, int RamPos)
|
||||
{
|
||||
if (paramfail == true)
|
||||
{
|
||||
// PrintError(ERROR_ERROR,"Parameter failure \"%s\"",Params);
|
||||
SetAssembleError("Parameter failure \"%s\"",Params);
|
||||
} else {
|
||||
// PrintError(ERROR_ERROR,"Invalid opcode \"%s\"",Name);
|
||||
SetAssembleError("Invalid opcode \"%s\"",Name);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -181,7 +198,7 @@ bool CMipsInstruction::LoadEncoding(const tMipsOpcode& SourceOpcode, char* Line)
|
||||
int RetLen;
|
||||
bool Immediate = false;
|
||||
|
||||
char* SourceEncoding = SourceOpcode.encoding;
|
||||
const char *SourceEncoding = SourceOpcode.encoding;
|
||||
char* OriginalLine = Line;
|
||||
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
@@ -301,7 +318,7 @@ bool CMipsInstruction::Validate()
|
||||
|
||||
if (num > 0x20000 || num < (-0x20000))
|
||||
{
|
||||
//QueueError(ERROR_ERROR,"Branch target %08X out of range",Vars.Immediate);
|
||||
SetAssembleError("Branch target %08X out of range",Vars.Immediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate = num >> 2;
|
||||
@@ -312,7 +329,7 @@ bool CMipsInstruction::Validate()
|
||||
case MIPS_IMMEDIATE5:
|
||||
if (Vars.Immediate > 0x1F)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %02X out of range",Vars.OriginalImmediate);
|
||||
SetAssembleError("Immediate value %02X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -321,7 +338,7 @@ bool CMipsInstruction::Validate()
|
||||
case MIPS_IMMEDIATE16:
|
||||
if (abs(Vars.Immediate) > 0x0000FFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %04X out of range",Vars.OriginalImmediate);
|
||||
SetAssembleError("Immediate value %04X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0x0000FFFF;
|
||||
@@ -329,7 +346,7 @@ bool CMipsInstruction::Validate()
|
||||
case MIPS_IMMEDIATE20:
|
||||
if (abs(Vars.Immediate) > 0x000FFFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
SetAssembleError("Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0x000FFFFF;
|
||||
@@ -337,7 +354,7 @@ bool CMipsInstruction::Validate()
|
||||
case MIPS_IMMEDIATE26:
|
||||
if (abs(Vars.Immediate) > 0x03FFFFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
SetAssembleError("Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0x03FFFFFF;
|
||||
|
||||
+4
-2
@@ -6,9 +6,9 @@
|
||||
namespace MIPSAsm
|
||||
{
|
||||
|
||||
bool MipsAssembleOpcode(char* line, DebugInterface* cpu, u32 address, u32& dest);
|
||||
bool MipsAssembleOpcode(const char* line, DebugInterface* cpu, u32 address, u32& dest);
|
||||
|
||||
typedef enum eMipsImmediateType { MIPS_NOIMMEDIATE, MIPS_IMMEDIATE5,
|
||||
enum eMipsImmediateType { MIPS_NOIMMEDIATE, MIPS_IMMEDIATE5,
|
||||
MIPS_IMMEDIATE16, MIPS_IMMEDIATE20, MIPS_IMMEDIATE26 };
|
||||
|
||||
typedef struct {
|
||||
@@ -39,4 +39,6 @@ private:
|
||||
u32 encoding;
|
||||
};
|
||||
|
||||
char* GetAssembleError();
|
||||
|
||||
}
|
||||
@@ -4,14 +4,14 @@ namespace MIPSAsm
|
||||
{
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
char* encoding;
|
||||
const char *name;
|
||||
const char *encoding;
|
||||
unsigned int destencoding;
|
||||
unsigned int flags;
|
||||
} tMipsOpcode;
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
const char *name;
|
||||
short num;
|
||||
short len;
|
||||
} tMipsRegister;
|
||||
|
||||
+13
-13
@@ -31,10 +31,10 @@ namespace MIPSCodeUtils
|
||||
|
||||
u32 GetJumpTarget(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
if (op)
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
if (op != 0)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_JUMP) && (info & IN_IMM26))
|
||||
{
|
||||
u32 target = (addr & 0xF0000000) | ((op&0x03FFFFFF) << 2);
|
||||
@@ -49,10 +49,10 @@ namespace MIPSCodeUtils
|
||||
|
||||
u32 GetBranchTarget(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
if (op)
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
if (op != 0)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if (info & IS_CONDBRANCH)
|
||||
{
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
@@ -66,10 +66,10 @@ namespace MIPSCodeUtils
|
||||
|
||||
u32 GetBranchTargetNoRA(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
if (op)
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
if (op != 0)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if ((info & IS_CONDBRANCH) && !(info & OUT_RA))
|
||||
{
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
@@ -83,10 +83,10 @@ namespace MIPSCodeUtils
|
||||
|
||||
u32 GetSureBranchTarget(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
if (op)
|
||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
||||
if (op != 0)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if (info & IS_CONDBRANCH)
|
||||
{
|
||||
bool sure;
|
||||
@@ -133,7 +133,7 @@ namespace MIPSCodeUtils
|
||||
return INVALIDTARGET;
|
||||
}
|
||||
|
||||
bool IsVFPUBranch(u32 op) {
|
||||
bool IsVFPUBranch(MIPSOpcode op) {
|
||||
return (MIPSGetInfo(op) & (IS_VFPU | IS_CONDBRANCH)) == (IS_VFPU | IS_CONDBRANCH);
|
||||
}
|
||||
}
|
||||
@@ -38,11 +38,11 @@
|
||||
|
||||
#define MIPS_GET_OP(op) ((op>>26) & 0x3F)
|
||||
#define MIPS_GET_FUNC(op) (op & 0x3F)
|
||||
#define MIPS_GET_SA(op) (op>>6 & 0x1F)
|
||||
#define MIPS_GET_SA(op) ((op>>6) & 0x1F)
|
||||
|
||||
#define MIPS_GET_RS(op) ((op>>21) & 0x1F)
|
||||
#define MIPS_GET_RT(op) ((op>>16) & 0x1F)
|
||||
#define MIPS_GET_RD(op) ((op>>11) & 0x1F)
|
||||
#define MIPS_GET_RS(op) MIPSGPReg((op>>21) & 0x1F)
|
||||
#define MIPS_GET_RT(op) MIPSGPReg((op>>16) & 0x1F)
|
||||
#define MIPS_GET_RD(op) MIPSGPReg((op>>11) & 0x1F)
|
||||
|
||||
#define MIPS_GET_FS(op) ((op>>11) & 0x1F)
|
||||
#define MIPS_GET_FT(op) ((op>>16) & 0x1F)
|
||||
@@ -57,5 +57,5 @@ namespace MIPSCodeUtils
|
||||
u32 GetBranchTargetNoRA(u32 addr);
|
||||
u32 GetJumpTarget(u32 addr);
|
||||
u32 GetSureBranchTarget(u32 addr);
|
||||
bool IsVFPUBranch(u32 op);
|
||||
bool IsVFPUBranch(MIPSOpcode op);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ const char *MIPSDebugInterface::disasm(unsigned int address, unsigned int align)
|
||||
}
|
||||
unsigned int MIPSDebugInterface::readMemory(unsigned int address)
|
||||
{
|
||||
return Memory::Read_U32(address);
|
||||
return Memory::Read_Instruction(address).encoding;
|
||||
}
|
||||
|
||||
bool MIPSDebugInterface::isAlive()
|
||||
@@ -171,7 +171,7 @@ bool MIPSDebugInterface::getSymbolValue(char* symbol, u32& dest)
|
||||
return symbolMap.getSymbolValue(symbol,dest);
|
||||
}
|
||||
|
||||
bool MIPSDebugInterface::initExpression(char* exp, PostfixExpression& dest)
|
||||
bool MIPSDebugInterface::initExpression(const char* exp, PostfixExpression& dest)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this);
|
||||
return initPostfixExpression(exp,&funcs,dest);
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
virtual const char *getDescription(unsigned int address);
|
||||
virtual const char *findSymbolForAddress(unsigned int address);
|
||||
virtual bool getSymbolValue(char* symbol, u32& dest);
|
||||
virtual bool initExpression(char* exp, PostfixExpression& dest);
|
||||
virtual bool initExpression(const char* exp, PostfixExpression& dest);
|
||||
virtual bool parseExpression(PostfixExpression& exp, u32& dest);
|
||||
|
||||
//overridden functions
|
||||
|
||||
+33
-33
@@ -56,12 +56,12 @@ namespace MIPSDis
|
||||
return temp;
|
||||
}
|
||||
|
||||
void Dis_Generic(u32 op, char *out)
|
||||
void Dis_Generic(MIPSOpcode op, char *out)
|
||||
{
|
||||
sprintf(out, "%s\t --- unknown ---", MIPSGetName(op));
|
||||
}
|
||||
|
||||
void Dis_mxc1(u32 op, char *out)
|
||||
void Dis_mxc1(MIPSOpcode op, char *out)
|
||||
{
|
||||
int fs = _FS;
|
||||
int rt = _RT;
|
||||
@@ -69,24 +69,24 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s",name,RN(rt),FN(fs));
|
||||
}
|
||||
|
||||
void Dis_FPU3op(u32 op, char *out)
|
||||
void Dis_FPU3op(MIPSOpcode op, char *out)
|
||||
{
|
||||
int ft = _FT;
|
||||
int fs = _FS;
|
||||
int fd = _FD;;
|
||||
int fd = _FD;
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t%s, %s, %s",name,FN(fd),FN(fs),FN(ft));
|
||||
}
|
||||
|
||||
void Dis_FPU2op(u32 op, char *out)
|
||||
void Dis_FPU2op(MIPSOpcode op, char *out)
|
||||
{
|
||||
int fs = _FS;
|
||||
int fd = _FD;;
|
||||
int fd = _FD;
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t%s, %s",name,FN(fd),FN(fs));
|
||||
}
|
||||
|
||||
void Dis_FPULS(u32 op, char *out)
|
||||
void Dis_FPULS(MIPSOpcode op, char *out)
|
||||
{
|
||||
int offset = (signed short)(op&0xFFFF);
|
||||
int ft = _FT;
|
||||
@@ -94,7 +94,7 @@ namespace MIPSDis
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t%s, %s(%s)",name,FN(ft),SignedHex(offset),RN(rs));
|
||||
}
|
||||
void Dis_FPUComp(u32 op, char *out)
|
||||
void Dis_FPUComp(MIPSOpcode op, char *out)
|
||||
{
|
||||
int fs = _FS;
|
||||
int ft = _FT;
|
||||
@@ -102,7 +102,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s",name,FN(fs),FN(ft));
|
||||
}
|
||||
|
||||
void Dis_FPUBranch(u32 op, char *out)
|
||||
void Dis_FPUBranch(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 off = disPC;
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
@@ -111,7 +111,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t->$%08x",name,off);
|
||||
}
|
||||
|
||||
void Dis_RelBranch(u32 op, char *out)
|
||||
void Dis_RelBranch(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 off = disPC;
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
@@ -122,7 +122,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, ->$%08x",name,RN(rs),off);
|
||||
}
|
||||
|
||||
void Dis_Syscall(u32 op, char *out)
|
||||
void Dis_Syscall(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 callno = (op>>6) & 0xFFFFF; //20 bits
|
||||
int funcnum = callno & 0xFFF;
|
||||
@@ -130,20 +130,20 @@ namespace MIPSDis
|
||||
sprintf(out, "syscall\t %s",/*PSPHLE::GetModuleName(modulenum),*/GetFuncName(modulenum, funcnum));
|
||||
}
|
||||
|
||||
void Dis_ToHiloTransfer(u32 op, char *out)
|
||||
void Dis_ToHiloTransfer(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rs = _RS;
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t%s",name,RN(rs));
|
||||
}
|
||||
void Dis_FromHiloTransfer(u32 op, char *out)
|
||||
void Dis_FromHiloTransfer(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rd = _RD;
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t%s",name,RN(rd));
|
||||
}
|
||||
|
||||
void Dis_RelBranch2(u32 op, char *out)
|
||||
void Dis_RelBranch2(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 off = disPC;
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
@@ -161,7 +161,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s, ->$%08x",name,RN(rt),RN(rs),off);
|
||||
}
|
||||
|
||||
void Dis_IType(u32 op, char *out)
|
||||
void Dis_IType(MIPSOpcode op, char *out)
|
||||
{
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF);
|
||||
u32 uimm = (u32)(u16)(op & 0xFFFF);
|
||||
@@ -185,7 +185,7 @@ namespace MIPSDis
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Dis_ori(u32 op, char *out)
|
||||
void Dis_ori(MIPSOpcode op, char *out)
|
||||
{
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF);
|
||||
u32 uimm = (u32)(u16)(op & 0xFFFF);
|
||||
@@ -198,7 +198,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),uimm);
|
||||
}
|
||||
|
||||
void Dis_IType1(u32 op, char *out)
|
||||
void Dis_IType1(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 uimm = (u32)(u16)(op & 0xFFFF);
|
||||
int rt = _RT;
|
||||
@@ -206,7 +206,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, 0x%X",name,RN(rt),uimm);
|
||||
}
|
||||
|
||||
void Dis_addi(u32 op, char *out)
|
||||
void Dis_addi(MIPSOpcode op, char *out)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
int rt = _RT;
|
||||
@@ -217,7 +217,7 @@ namespace MIPSDis
|
||||
Dis_IType(op,out);
|
||||
}
|
||||
|
||||
void Dis_ITypeMem(u32 op, char *out)
|
||||
void Dis_ITypeMem(MIPSOpcode op, char *out)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
int rt = _RT;
|
||||
@@ -226,7 +226,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s(%s)",name,RN(rt),SignedHex(imm),RN(rs));
|
||||
}
|
||||
|
||||
void Dis_RType2(u32 op, char *out)
|
||||
void Dis_RType2(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
@@ -234,7 +234,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s",name,RN(rd),RN(rs));
|
||||
}
|
||||
|
||||
void Dis_RType3(u32 op, char *out)
|
||||
void Dis_RType3(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -243,7 +243,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s, %s",name,RN(rd),RN(rs),RN(rt));
|
||||
}
|
||||
|
||||
void Dis_addu(u32 op, char *out)
|
||||
void Dis_addu(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -252,14 +252,14 @@ namespace MIPSDis
|
||||
if (rs==0 && rt==0)
|
||||
sprintf(out,"li\t%s, 0",RN(rd));
|
||||
else if (rs == 0)
|
||||
sprintf(out,"mov\t%s, %s",RN(rd),RN(rt));
|
||||
sprintf(out,"move\t%s, %s",RN(rd),RN(rt));
|
||||
else if (rt == 0)
|
||||
sprintf(out,"mov\t%s, %s",RN(rd),RN(rs));
|
||||
sprintf(out,"move\t%s, %s",RN(rd),RN(rs));
|
||||
else
|
||||
sprintf(out, "%s\t%s, %s, %s",name,RN(rd),RN(rs),RN(rt));
|
||||
}
|
||||
|
||||
void Dis_ShiftType(u32 op, char *out)
|
||||
void Dis_ShiftType(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -273,7 +273,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rd),RN(rt),sa);
|
||||
}
|
||||
|
||||
void Dis_VarShiftType(u32 op, char *out)
|
||||
void Dis_VarShiftType(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -283,7 +283,7 @@ namespace MIPSDis
|
||||
}
|
||||
|
||||
|
||||
void Dis_MulDivType(u32 op, char *out)
|
||||
void Dis_MulDivType(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -292,7 +292,7 @@ namespace MIPSDis
|
||||
}
|
||||
|
||||
|
||||
void Dis_Special3(u32 op, char *out)
|
||||
void Dis_Special3(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rs = _RS;
|
||||
int Rt = _RT;
|
||||
@@ -316,14 +316,14 @@ namespace MIPSDis
|
||||
}
|
||||
}
|
||||
|
||||
void Dis_JumpType(u32 op, char *out)
|
||||
void Dis_JumpType(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 off = ((op & 0x03FFFFFF) << 2);
|
||||
u32 addr = (disPC & 0xF0000000) | off;
|
||||
const char *name = MIPSGetName(op);
|
||||
sprintf(out, "%s\t->$%08x",name,addr);
|
||||
}
|
||||
void Dis_JumpRegType(u32 op, char *out)
|
||||
void Dis_JumpRegType(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rs = (op>>21)&0x1f;
|
||||
const char *name = MIPSGetName(op);
|
||||
@@ -331,7 +331,7 @@ namespace MIPSDis
|
||||
|
||||
}
|
||||
|
||||
void Dis_Allegrex(u32 op, char *out)
|
||||
void Dis_Allegrex(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
@@ -339,7 +339,7 @@ namespace MIPSDis
|
||||
sprintf(out,"%s\t%s,%s",name,RN(rd),RN(rt));
|
||||
}
|
||||
|
||||
void Dis_Allegrex2(u32 op, char *out)
|
||||
void Dis_Allegrex2(MIPSOpcode op, char *out)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
@@ -347,7 +347,7 @@ namespace MIPSDis
|
||||
sprintf(out,"%s\t%s,%s",name,RN(rd),RN(rt));
|
||||
}
|
||||
|
||||
void Dis_Emuhack(u32 op, char *out)
|
||||
void Dis_Emuhack(MIPSOpcode op, char *out)
|
||||
{
|
||||
//const char *name = MIPSGetName(op);
|
||||
//sprintf(out,"%s\t-",name);
|
||||
|
||||
+33
-32
@@ -17,45 +17,46 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "Globals.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
|
||||
extern u32 disPC;
|
||||
|
||||
namespace MIPSDis
|
||||
{
|
||||
void Dis_Unknown(u32 op, char *out);
|
||||
void Dis_Unimpl(u32 op, char *out);
|
||||
void Dis_Syscall(u32 op, char *out);
|
||||
void Dis_Unknown(MIPSOpcode op, char *out);
|
||||
void Dis_Unimpl(MIPSOpcode op, char *out);
|
||||
void Dis_Syscall(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_mxc1(u32 op, char *out);
|
||||
void Dis_addi(u32 op, char *out);
|
||||
void Dis_addu(u32 op, char *out);
|
||||
void Dis_RelBranch2(u32 op, char *out);
|
||||
void Dis_RelBranch(u32 op, char *out);
|
||||
void Dis_Generic(u32 op, char *out);
|
||||
void Dis_IType(u32 op, char *out);
|
||||
void Dis_IType1(u32 op, char *out);
|
||||
void Dis_ITypeMem(u32 op, char *out);
|
||||
void Dis_RType2(u32 op, char *out);
|
||||
void Dis_RType3(u32 op, char *out);
|
||||
void Dis_MulDivType(u32 op, char *out);
|
||||
void Dis_ShiftType(u32 op, char *out);
|
||||
void Dis_VarShiftType(u32 op, char *out);
|
||||
void Dis_FPU3op(u32 op, char *out);
|
||||
void Dis_FPU2op(u32 op, char *out);
|
||||
void Dis_FPULS(u32 op, char *out);
|
||||
void Dis_FPUComp(u32 op, char *out);
|
||||
void Dis_FPUBranch(u32 op, char *out);
|
||||
void Dis_ori(u32 op, char *out);
|
||||
void Dis_Special3(u32 op, char *out);
|
||||
void Dis_mxc1(MIPSOpcode op, char *out);
|
||||
void Dis_addi(MIPSOpcode op, char *out);
|
||||
void Dis_addu(MIPSOpcode op, char *out);
|
||||
void Dis_RelBranch2(MIPSOpcode op, char *out);
|
||||
void Dis_RelBranch(MIPSOpcode op, char *out);
|
||||
void Dis_Generic(MIPSOpcode op, char *out);
|
||||
void Dis_IType(MIPSOpcode op, char *out);
|
||||
void Dis_IType1(MIPSOpcode op, char *out);
|
||||
void Dis_ITypeMem(MIPSOpcode op, char *out);
|
||||
void Dis_RType2(MIPSOpcode op, char *out);
|
||||
void Dis_RType3(MIPSOpcode op, char *out);
|
||||
void Dis_MulDivType(MIPSOpcode op, char *out);
|
||||
void Dis_ShiftType(MIPSOpcode op, char *out);
|
||||
void Dis_VarShiftType(MIPSOpcode op, char *out);
|
||||
void Dis_FPU3op(MIPSOpcode op, char *out);
|
||||
void Dis_FPU2op(MIPSOpcode op, char *out);
|
||||
void Dis_FPULS(MIPSOpcode op, char *out);
|
||||
void Dis_FPUComp(MIPSOpcode op, char *out);
|
||||
void Dis_FPUBranch(MIPSOpcode op, char *out);
|
||||
void Dis_ori(MIPSOpcode op, char *out);
|
||||
void Dis_Special3(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_ToHiloTransfer(u32 op, char *out);
|
||||
void Dis_FromHiloTransfer(u32 op, char *out);
|
||||
void Dis_JumpType(u32 op, char *out);
|
||||
void Dis_JumpRegType(u32 op, char *out);
|
||||
void Dis_ToHiloTransfer(MIPSOpcode op, char *out);
|
||||
void Dis_FromHiloTransfer(MIPSOpcode op, char *out);
|
||||
void Dis_JumpType(MIPSOpcode op, char *out);
|
||||
void Dis_JumpRegType(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_Allegrex(u32 op, char *out);
|
||||
void Dis_Allegrex2(u32 op, char *out);
|
||||
void Dis_Allegrex(MIPSOpcode op, char *out);
|
||||
void Dis_Allegrex2(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_Emuhack(u32 op, char *out);
|
||||
void Dis_Emuhack(MIPSOpcode op, char *out);
|
||||
}
|
||||
+31
-31
@@ -82,7 +82,7 @@ inline const char *MN(int v, MatrixSize size)
|
||||
return GetMatrixNotation(v, size);
|
||||
}
|
||||
|
||||
inline const char *VSuff(u32 op)
|
||||
inline const char *VSuff(MIPSOpcode op)
|
||||
{
|
||||
int a = (op>>7)&1;
|
||||
int b = (op>>15)&1;
|
||||
@@ -99,7 +99,7 @@ inline const char *VSuff(u32 op)
|
||||
|
||||
namespace MIPSDis
|
||||
{
|
||||
void Dis_SV(u32 op, char *out)
|
||||
void Dis_SV(MIPSOpcode op, char *out)
|
||||
{
|
||||
int offset = (signed short)(op&0xFFFC);
|
||||
int vt = ((op>>16)&0x1f)|((op&3)<<5);
|
||||
@@ -108,7 +108,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s\t%s, %d(%s)",name,VN(vt, V_Single),offset,RN(rs));
|
||||
}
|
||||
|
||||
void Dis_SVQ(u32 op, char *out)
|
||||
void Dis_SVQ(MIPSOpcode op, char *out)
|
||||
{
|
||||
int offset = (signed short)(op&0xFFFC);
|
||||
int vt = (((op>>16)&0x1f))|((op&1)<<5);
|
||||
@@ -119,7 +119,7 @@ namespace MIPSDis
|
||||
strcat(out, ", wb");
|
||||
}
|
||||
|
||||
void Dis_SVLRQ(u32 op, char *out)
|
||||
void Dis_SVLRQ(MIPSOpcode op, char *out)
|
||||
{
|
||||
int offset = (signed short)(op&0xFFFC);
|
||||
int vt = (((op>>16)&0x1f))|((op&1)<<5);
|
||||
@@ -129,7 +129,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s.q\t%s, %d(%s)",name,lr?"r":"l",VN(vt,V_Quad),offset,RN(rs));
|
||||
}
|
||||
|
||||
void Dis_Mftv(u32 op, char *out)
|
||||
void Dis_Mftv(MIPSOpcode op, char *out)
|
||||
{
|
||||
int vr = op & 0xFF;
|
||||
int rt = _RT;
|
||||
@@ -137,7 +137,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s",name,vr>127?"c":"", RN(rt), VN(vr, V_Single));
|
||||
}
|
||||
|
||||
void Dis_VPFXST(u32 op, char *out)
|
||||
void Dis_VPFXST(MIPSOpcode op, char *out)
|
||||
{
|
||||
int data = op & 0xFFFFF;
|
||||
const char *name = MIPSGetName(op);
|
||||
@@ -170,7 +170,7 @@ namespace MIPSDis
|
||||
}
|
||||
}
|
||||
|
||||
void Dis_VPFXD(u32 op, char *out)
|
||||
void Dis_VPFXD(MIPSOpcode op, char *out)
|
||||
{
|
||||
int data = op & 0xFFFFF;
|
||||
const char *name = MIPSGetName(op);
|
||||
@@ -189,7 +189,7 @@ namespace MIPSDis
|
||||
}
|
||||
|
||||
|
||||
void Dis_Viim(u32 op, char *out)
|
||||
void Dis_Viim(MIPSOpcode op, char *out)
|
||||
{
|
||||
int vt = _VT;
|
||||
int imm = op&0xFFFF;
|
||||
@@ -205,7 +205,7 @@ namespace MIPSDis
|
||||
sprintf(out, "ARGH");
|
||||
}
|
||||
|
||||
void Dis_Vcst(u32 op, char *out)
|
||||
void Dis_Vcst(MIPSOpcode op, char *out)
|
||||
{
|
||||
int conNum = (op>>16) & 0x1f;
|
||||
int vd = _VD;
|
||||
@@ -239,14 +239,14 @@ namespace MIPSDis
|
||||
}
|
||||
|
||||
|
||||
void Dis_MatrixSet1(u32 op, char *out)
|
||||
void Dis_MatrixSet1(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
MatrixSize sz = GetMtxSize(op);
|
||||
sprintf(out, "%s%s\t%s",name,VSuff(op),MN(vd, sz));
|
||||
}
|
||||
void Dis_MatrixSet2(u32 op, char *out)
|
||||
void Dis_MatrixSet2(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -254,7 +254,7 @@ namespace MIPSDis
|
||||
MatrixSize sz = GetMtxSize(op);
|
||||
sprintf(out, "%s%s\t%s, %s",name,VSuff(op),MN(vd, sz),MN(vs,sz));
|
||||
}
|
||||
void Dis_MatrixSet3(u32 op, char *out)
|
||||
void Dis_MatrixSet3(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -264,7 +264,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s",name,VSuff(op),MN(vd, sz),MN(vs,sz),MN(vt,sz));
|
||||
}
|
||||
|
||||
void Dis_MatrixMult(u32 op, char *out)
|
||||
void Dis_MatrixMult(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -274,7 +274,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s",name,VSuff(op),MN(vd, sz),MN(Xpose(vs),sz),MN(vt,sz));
|
||||
}
|
||||
|
||||
void Dis_VectorDot(u32 op, char *out)
|
||||
void Dis_VectorDot(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -284,7 +284,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s", name, VSuff(op), VN(vd, V_Single), VN(vs,sz), VN(vt, sz));
|
||||
}
|
||||
|
||||
void Dis_Vtfm(u32 op, char *out)
|
||||
void Dis_Vtfm(MIPSOpcode op, char *out)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -309,12 +309,12 @@ namespace MIPSDis
|
||||
}
|
||||
}
|
||||
|
||||
void Dis_Vflush(u32 op, char *out)
|
||||
void Dis_Vflush(MIPSOpcode op, char *out)
|
||||
{
|
||||
sprintf(out,"vflush");
|
||||
}
|
||||
|
||||
void Dis_Vcrs(u32 op, char *out)
|
||||
void Dis_Vcrs(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vt = _VT;
|
||||
@@ -330,7 +330,7 @@ namespace MIPSDis
|
||||
}
|
||||
|
||||
|
||||
void Dis_Vcmp(u32 op, char *out)
|
||||
void Dis_Vcmp(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vt = _VT;
|
||||
@@ -341,7 +341,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s", name, VSuff(op), condNames[cond], VN(vs, sz), VN(vt,sz));
|
||||
}
|
||||
|
||||
void Dis_Vcmov(u32 op, char *out)
|
||||
void Dis_Vcmov(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
VectorSize sz = GetVecSize(op);
|
||||
@@ -361,7 +361,7 @@ namespace MIPSDis
|
||||
|
||||
}
|
||||
|
||||
void Dis_Vfad(u32 op, char *out)
|
||||
void Dis_Vfad(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -370,7 +370,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s", name, VSuff(op), VN(vd, V_Single), VN(vs,sz));
|
||||
}
|
||||
|
||||
void Dis_VScl(u32 op, char *out)
|
||||
void Dis_VScl(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -380,14 +380,14 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s", name, VSuff(op), VN(vd, sz), VN(vs,sz), VN(vt, V_Single));
|
||||
}
|
||||
|
||||
void Dis_VectorSet1(u32 op, char *out)
|
||||
void Dis_VectorSet1(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
sprintf(out, "%s%s\t%s",name,VSuff(op),VN(vd, sz));
|
||||
}
|
||||
void Dis_VectorSet2(u32 op, char *out)
|
||||
void Dis_VectorSet2(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -395,7 +395,7 @@ namespace MIPSDis
|
||||
VectorSize sz = GetVecSize(op);
|
||||
sprintf(out, "%s%s\t%s, %s",name,VSuff(op),VN(vd, sz),VN(vs, sz));
|
||||
}
|
||||
void Dis_VectorSet3(u32 op, char *out)
|
||||
void Dis_VectorSet3(MIPSOpcode op, char *out)
|
||||
{
|
||||
const char *name = MIPSGetName(op);
|
||||
int vd = _VD;
|
||||
@@ -405,7 +405,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s", name, VSuff(op), VN(vd, sz), VN(vs,sz), VN(vt, sz));
|
||||
}
|
||||
|
||||
void Dis_VRot(u32 op, char *out)
|
||||
void Dis_VRot(MIPSOpcode op, char *out)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -439,7 +439,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s",name,VSuff(op),VN(vd, sz),VN(vs, V_Single),temp);
|
||||
}
|
||||
|
||||
void Dis_CrossQuat(u32 op, char *out)
|
||||
void Dis_CrossQuat(MIPSOpcode op, char *out)
|
||||
{
|
||||
VectorSize sz = GetVecSize(op);
|
||||
const char *name;
|
||||
@@ -464,7 +464,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %s", name, VSuff(op), VN(vd, sz), VN(vs,sz), VN(vt, sz));
|
||||
}
|
||||
|
||||
void Dis_Vbfy(u32 op, char *out)
|
||||
void Dis_Vbfy(MIPSOpcode op, char *out)
|
||||
{
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int vd = _VD;
|
||||
@@ -473,7 +473,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s",name,VSuff(op),VN(vd, sz),VN(vs, sz));
|
||||
}
|
||||
|
||||
void Dis_Vf2i(u32 op, char *out)
|
||||
void Dis_Vf2i(MIPSOpcode op, char *out)
|
||||
{
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int vd = _VD;
|
||||
@@ -483,7 +483,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s, %i",name,VSuff(op),VN(vd, sz),VN(vs, sz),imm);
|
||||
}
|
||||
|
||||
void Dis_Vs2i(u32 op, char *out)
|
||||
void Dis_Vs2i(MIPSOpcode op, char *out)
|
||||
{
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int vd = _VD;
|
||||
@@ -492,7 +492,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s",name,VSuff(op),VN(vd, sz),VN(vs, sz));
|
||||
}
|
||||
|
||||
void Dis_Vi2x(u32 op, char *out)
|
||||
void Dis_Vi2x(MIPSOpcode op, char *out)
|
||||
{
|
||||
VectorSize sz = GetVecSize(op);
|
||||
VectorSize dsz = GetHalfVectorSize(sz);
|
||||
@@ -505,7 +505,7 @@ namespace MIPSDis
|
||||
sprintf(out, "%s%s\t%s, %s",name,VSuff(op),VN(vd, dsz),VN(vs, sz));
|
||||
}
|
||||
|
||||
void Dis_VBranch(u32 op, char *out)
|
||||
void Dis_VBranch(MIPSOpcode op, char *out)
|
||||
{
|
||||
u32 off = disPC;
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
|
||||
+30
-30
@@ -23,38 +23,38 @@ extern u32 disPC;
|
||||
|
||||
namespace MIPSDis
|
||||
{
|
||||
void Dis_Mftv(u32 op, char *out);
|
||||
void Dis_Mftv(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_SV(u32 op, char *out);
|
||||
void Dis_SVQ(u32 op, char *out);
|
||||
void Dis_SVLRQ(u32 op, char *out);
|
||||
void Dis_SV(MIPSOpcode op, char *out);
|
||||
void Dis_SVQ(MIPSOpcode op, char *out);
|
||||
void Dis_SVLRQ(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_MatrixSet1(u32 op, char *out);
|
||||
void Dis_MatrixSet2(u32 op, char *out);
|
||||
void Dis_MatrixSet3(u32 op, char *out);
|
||||
void Dis_MatrixMult(u32 op, char *out);
|
||||
void Dis_MatrixSet1(MIPSOpcode op, char *out);
|
||||
void Dis_MatrixSet2(MIPSOpcode op, char *out);
|
||||
void Dis_MatrixSet3(MIPSOpcode op, char *out);
|
||||
void Dis_MatrixMult(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_VectorDot(u32 op, char *out);
|
||||
void Dis_Vfad(u32 op, char *out);
|
||||
void Dis_VectorSet1(u32 op, char *out);
|
||||
void Dis_VectorSet2(u32 op, char *out);
|
||||
void Dis_VectorSet3(u32 op, char *out);
|
||||
void Dis_VRot(u32 op, char *out);
|
||||
void Dis_VScl(u32 op, char *out);
|
||||
void Dis_VectorDot(MIPSOpcode op, char *out);
|
||||
void Dis_Vfad(MIPSOpcode op, char *out);
|
||||
void Dis_VectorSet1(MIPSOpcode op, char *out);
|
||||
void Dis_VectorSet2(MIPSOpcode op, char *out);
|
||||
void Dis_VectorSet3(MIPSOpcode op, char *out);
|
||||
void Dis_VRot(MIPSOpcode op, char *out);
|
||||
void Dis_VScl(MIPSOpcode op, char *out);
|
||||
|
||||
void Dis_VPFXST(u32 op, char *out);
|
||||
void Dis_VPFXD(u32 op, char *out);
|
||||
void Dis_Vcrs(u32 op, char *out);
|
||||
void Dis_Viim(u32 op, char *out);
|
||||
void Dis_Vcst(u32 op, char *out);
|
||||
void Dis_CrossQuat(u32 op, char *out);
|
||||
void Dis_Vtfm(u32 op, char *out);
|
||||
void Dis_Vcmp(u32 op, char *out);
|
||||
void Dis_Vcmov(u32 op, char *out);
|
||||
void Dis_Vflush(u32 op, char *out);
|
||||
void Dis_Vbfy(u32 op, char *out);
|
||||
void Dis_Vf2i(u32 op, char *out);
|
||||
void Dis_Vi2x(u32 op, char *out);
|
||||
void Dis_Vs2i(u32 op, char *out);
|
||||
void Dis_VBranch(u32 op, char *out);
|
||||
void Dis_VPFXST(MIPSOpcode op, char *out);
|
||||
void Dis_VPFXD(MIPSOpcode op, char *out);
|
||||
void Dis_Vcrs(MIPSOpcode op, char *out);
|
||||
void Dis_Viim(MIPSOpcode op, char *out);
|
||||
void Dis_Vcst(MIPSOpcode op, char *out);
|
||||
void Dis_CrossQuat(MIPSOpcode op, char *out);
|
||||
void Dis_Vtfm(MIPSOpcode op, char *out);
|
||||
void Dis_Vcmp(MIPSOpcode op, char *out);
|
||||
void Dis_Vcmov(MIPSOpcode op, char *out);
|
||||
void Dis_Vflush(MIPSOpcode op, char *out);
|
||||
void Dis_Vbfy(MIPSOpcode op, char *out);
|
||||
void Dis_Vf2i(MIPSOpcode op, char *out);
|
||||
void Dis_Vi2x(MIPSOpcode op, char *out);
|
||||
void Dis_Vs2i(MIPSOpcode op, char *out);
|
||||
void Dis_VBranch(MIPSOpcode op, char *out);
|
||||
}
|
||||
+53
-30
@@ -66,13 +66,13 @@ static inline void SkipLikely()
|
||||
int MIPS_SingleStep()
|
||||
{
|
||||
#if defined(ARM)
|
||||
u32 op = Memory::ReadUnchecked_U32(mipsr4k.pc);
|
||||
MIPSOpcode op = MIPSOpcode(Memory::ReadUnchecked_U32(mipsr4k.pc));
|
||||
#else
|
||||
u32 op = Memory::Read_Opcode_JIT(mipsr4k.pc);
|
||||
MIPSOpcode op = Memory::Read_Opcode_JIT(mipsr4k.pc);
|
||||
#endif
|
||||
/*
|
||||
// Choke on VFPU
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if (info & IS_VFPU)
|
||||
{
|
||||
if (!Core_IsStepping() && !GetAsyncKeyState(VK_LSHIFT))
|
||||
@@ -117,7 +117,7 @@ void MIPS_ClearDelaySlot()
|
||||
|
||||
namespace MIPSInt
|
||||
{
|
||||
void Int_Cache(u32 op)
|
||||
void Int_Cache(MIPSOpcode op)
|
||||
{
|
||||
int imm = (s16)(op & 0xFFFF);
|
||||
int rs = _RS;
|
||||
@@ -145,7 +145,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Syscall(u32 op)
|
||||
void Int_Syscall(MIPSOpcode op)
|
||||
{
|
||||
// Need to pre-move PC, as CallSyscall may result in a rescheduling!
|
||||
// To do this neater, we'll need a little generated kernel loop that syscall can jump to and then RFI from
|
||||
@@ -162,13 +162,13 @@ namespace MIPSInt
|
||||
CallSyscall(op);
|
||||
}
|
||||
|
||||
void Int_Sync(u32 op)
|
||||
void Int_Sync(MIPSOpcode op)
|
||||
{
|
||||
//DEBUG_LOG(CPU, "sync");
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Break(u32 op)
|
||||
void Int_Break(MIPSOpcode op)
|
||||
{
|
||||
Reporting::ReportMessage("BREAK instruction hit");
|
||||
ERROR_LOG(CPU, "BREAK!");
|
||||
@@ -177,7 +177,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_RelBranch(u32 op)
|
||||
void Int_RelBranch(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
int rs = _RS;
|
||||
@@ -202,7 +202,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_RelBranchRI(u32 op)
|
||||
void Int_RelBranchRI(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
int rs = _RS;
|
||||
@@ -225,7 +225,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_VBranch(u32 op)
|
||||
void Int_VBranch(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
u32 addr = PC + imm + 4;
|
||||
@@ -243,7 +243,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_FPUBranch(u32 op)
|
||||
void Int_FPUBranch(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF)<<2;
|
||||
u32 addr = PC + imm + 4;
|
||||
@@ -259,7 +259,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_JumpType(u32 op)
|
||||
void Int_JumpType(MIPSOpcode op)
|
||||
{
|
||||
if (mipsr4k.inDelaySlot)
|
||||
_dbg_assert_msg_(CPU,0,"Jump in delay slot :(");
|
||||
@@ -280,7 +280,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_JumpRegType(u32 op)
|
||||
void Int_JumpRegType(MIPSOpcode op)
|
||||
{
|
||||
if (mipsr4k.inDelaySlot)
|
||||
{
|
||||
@@ -306,7 +306,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_IType(u32 op)
|
||||
void Int_IType(MIPSOpcode op)
|
||||
{
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF);
|
||||
u32 uimm = (u32)(u16)(op & 0xFFFF);
|
||||
@@ -338,7 +338,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_StoreSync(u32 op)
|
||||
void Int_StoreSync(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
int rt = _RT;
|
||||
@@ -371,7 +371,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_RType3(u32 op)
|
||||
void Int_RType3(MIPSOpcode op)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -419,7 +419,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_ITypeMem(u32 op)
|
||||
void Int_ITypeMem(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
int rt = _RT;
|
||||
@@ -489,7 +489,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_FPULS(u32 op)
|
||||
void Int_FPULS(MIPSOpcode op)
|
||||
{
|
||||
s32 offset = (s16)(op&0xFFFF);
|
||||
int ft = _FT;
|
||||
@@ -507,7 +507,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_mxc1(u32 op)
|
||||
void Int_mxc1(MIPSOpcode op)
|
||||
{
|
||||
int fs = _FS;
|
||||
int rt = _RT;
|
||||
@@ -526,7 +526,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_RType2(u32 op)
|
||||
void Int_RType2(MIPSOpcode op)
|
||||
{
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
@@ -571,7 +571,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_MulDivType(u32 op)
|
||||
void Int_MulDivType(MIPSOpcode op)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -674,7 +674,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_ShiftType(u32 op)
|
||||
void Int_ShiftType(MIPSOpcode op)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
@@ -728,7 +728,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Allegrex(u32 op)
|
||||
void Int_Allegrex(MIPSOpcode op)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
@@ -771,7 +771,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Allegrex2(u32 op)
|
||||
void Int_Allegrex2(MIPSOpcode op)
|
||||
{
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
@@ -798,7 +798,30 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Special3(u32 op)
|
||||
void Int_Special2(MIPSOpcode op)
|
||||
{
|
||||
static int reported = 0;
|
||||
switch (op & 0x3F)
|
||||
{
|
||||
case 36:
|
||||
if (!reported) {
|
||||
Reporting::ReportMessage("MFIC instruction hit (%08x) at %08x", op, currentMIPS->pc);
|
||||
WARN_LOG(CPU,"MFIC Disable/Enable Interrupt CPU instruction");
|
||||
reported = 1;
|
||||
}
|
||||
break;
|
||||
case 38:
|
||||
if (!reported) {
|
||||
Reporting::ReportMessage("MTIC instruction hit (%08x) at %08x", op, currentMIPS->pc);
|
||||
WARN_LOG(CPU,"MTIC Disable/Enable Interrupt CPU instruction");
|
||||
reported = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Special3(MIPSOpcode op)
|
||||
{
|
||||
int rs = _RS;
|
||||
int rt = _RT;
|
||||
@@ -832,7 +855,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_FPU2op(u32 op)
|
||||
void Int_FPU2op(MIPSOpcode op)
|
||||
{
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
@@ -865,7 +888,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_FPUComp(u32 op)
|
||||
void Int_FPUComp(MIPSOpcode op)
|
||||
{
|
||||
int fs = _FS;
|
||||
int ft = _FT;
|
||||
@@ -921,7 +944,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_FPU3op(u32 op)
|
||||
void Int_FPU3op(MIPSOpcode op)
|
||||
{
|
||||
int ft = _FT;
|
||||
int fs = _FS;
|
||||
@@ -940,7 +963,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Interrupt(u32 op)
|
||||
void Int_Interrupt(MIPSOpcode op)
|
||||
{
|
||||
static int reported = 0;
|
||||
switch (op & 1)
|
||||
@@ -957,7 +980,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_Emuhack(u32 op)
|
||||
void Int_Emuhack(MIPSOpcode op)
|
||||
{
|
||||
_dbg_assert_msg_(CPU,0,"Trying to interpret emuhack instruction that can't be interpreted");
|
||||
}
|
||||
|
||||
+29
-28
@@ -25,33 +25,34 @@ int MIPS_SingleStep();
|
||||
|
||||
namespace MIPSInt
|
||||
{
|
||||
void Int_Unknown(u32 op);
|
||||
void Int_Unimpl(u32 op);
|
||||
void Int_Syscall(u32 op);
|
||||
void Int_Unknown(MIPSOpcode op);
|
||||
void Int_Unimpl(MIPSOpcode op);
|
||||
void Int_Syscall(MIPSOpcode op);
|
||||
|
||||
void Int_mxc1(u32 op);
|
||||
void Int_RelBranch(u32 op);
|
||||
void Int_RelBranchRI(u32 op);
|
||||
void Int_IType(u32 op);
|
||||
void Int_ITypeMem(u32 op);
|
||||
void Int_RType2(u32 op);
|
||||
void Int_RType3(u32 op);
|
||||
void Int_ShiftType(u32 op);
|
||||
void Int_MulDivType(u32 op);
|
||||
void Int_JumpType(u32 op);
|
||||
void Int_JumpRegType(u32 op);
|
||||
void Int_Allegrex2(u32 op);
|
||||
void Int_FPULS(u32 op);
|
||||
void Int_FPU3op(u32 op);
|
||||
void Int_FPU2op(u32 op);
|
||||
void Int_Allegrex(u32 op);
|
||||
void Int_FPUComp(u32 op);
|
||||
void Int_FPUBranch(u32 op);
|
||||
void Int_Emuhack(u32 op);
|
||||
void Int_Special3(u32 op);
|
||||
void Int_Interrupt(u32 op);
|
||||
void Int_Cache(u32 op);
|
||||
void Int_Sync(u32 op);
|
||||
void Int_Break(u32 op);
|
||||
void Int_StoreSync(u32 op);
|
||||
void Int_mxc1(MIPSOpcode op);
|
||||
void Int_RelBranch(MIPSOpcode op);
|
||||
void Int_RelBranchRI(MIPSOpcode op);
|
||||
void Int_IType(MIPSOpcode op);
|
||||
void Int_ITypeMem(MIPSOpcode op);
|
||||
void Int_RType2(MIPSOpcode op);
|
||||
void Int_RType3(MIPSOpcode op);
|
||||
void Int_ShiftType(MIPSOpcode op);
|
||||
void Int_MulDivType(MIPSOpcode op);
|
||||
void Int_JumpType(MIPSOpcode op);
|
||||
void Int_JumpRegType(MIPSOpcode op);
|
||||
void Int_Allegrex2(MIPSOpcode op);
|
||||
void Int_FPULS(MIPSOpcode op);
|
||||
void Int_FPU3op(MIPSOpcode op);
|
||||
void Int_FPU2op(MIPSOpcode op);
|
||||
void Int_Allegrex(MIPSOpcode op);
|
||||
void Int_FPUComp(MIPSOpcode op);
|
||||
void Int_FPUBranch(MIPSOpcode op);
|
||||
void Int_Emuhack(MIPSOpcode op);
|
||||
void Int_Special2(MIPSOpcode op);
|
||||
void Int_Special3(MIPSOpcode op);
|
||||
void Int_Interrupt(MIPSOpcode op);
|
||||
void Int_Cache(MIPSOpcode op);
|
||||
void Int_Sync(MIPSOpcode op);
|
||||
void Int_Break(MIPSOpcode op);
|
||||
void Int_StoreSync(MIPSOpcode op);
|
||||
}
|
||||
+54
-54
@@ -196,7 +196,7 @@ void EatPrefixes()
|
||||
|
||||
namespace MIPSInt
|
||||
{
|
||||
void Int_VPFX(u32 op)
|
||||
void Int_VPFX(MIPSOpcode op)
|
||||
{
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
@@ -204,7 +204,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_SVQ(u32 op)
|
||||
void Int_SVQ(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFC);
|
||||
int rs = _RS;
|
||||
@@ -315,7 +315,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_VMatrixInit(u32 op)
|
||||
void Int_VMatrixInit(MIPSOpcode op)
|
||||
{
|
||||
static const float idt[16] =
|
||||
{
|
||||
@@ -359,7 +359,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VVectorInit(u32 op)
|
||||
void Int_VVectorInit(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
@@ -387,7 +387,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Viim(u32 op)
|
||||
void Int_Viim(MIPSOpcode op)
|
||||
{
|
||||
int vt = _VT;
|
||||
s32 imm = (s16)(op&0xFFFF);
|
||||
@@ -408,7 +408,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vidt(u32 op)
|
||||
void Int_Vidt(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
@@ -435,7 +435,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
// The test really needs some work.
|
||||
void Int_Vmmul(u32 op)
|
||||
void Int_Vmmul(MIPSOpcode op)
|
||||
{
|
||||
float s[16];
|
||||
float t[16];
|
||||
@@ -468,7 +468,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vmscl(u32 op)
|
||||
void Int_Vmscl(MIPSOpcode op)
|
||||
{
|
||||
float d[16];
|
||||
float s[16];
|
||||
@@ -496,7 +496,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vmmov(u32 op)
|
||||
void Int_Vmmov(MIPSOpcode op)
|
||||
{
|
||||
float s[16];
|
||||
int vd = _VD;
|
||||
@@ -509,13 +509,13 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vflush(u32 op)
|
||||
void Int_Vflush(MIPSOpcode op)
|
||||
{
|
||||
// DEBUG_LOG(CPU,"vflush");
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_VV2Op(u32 op)
|
||||
void Int_VV2Op(MIPSOpcode op)
|
||||
{
|
||||
float s[4], d[4];
|
||||
int vd = _VD;
|
||||
@@ -555,7 +555,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vocp(u32 op)
|
||||
void Int_Vocp(MIPSOpcode op)
|
||||
{
|
||||
float s[4], d[4];
|
||||
int vd = _VD;
|
||||
@@ -573,7 +573,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsocp(u32 op)
|
||||
void Int_Vsocp(MIPSOpcode op)
|
||||
{
|
||||
float s[4], d[4];
|
||||
int vd = _VD;
|
||||
@@ -596,7 +596,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsgn(u32 op)
|
||||
void Int_Vsgn(MIPSOpcode op)
|
||||
{
|
||||
float s[4], d[4];
|
||||
int vd = _VD;
|
||||
@@ -627,7 +627,7 @@ namespace MIPSInt
|
||||
return (int)round_ieee_754(param);
|
||||
}
|
||||
|
||||
void Int_Vf2i(u32 op) {
|
||||
void Int_Vf2i(MIPSOpcode op) {
|
||||
float s[4];
|
||||
int d[4];
|
||||
int vd = _VD;
|
||||
@@ -665,7 +665,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vi2f(u32 op)
|
||||
void Int_Vi2f(MIPSOpcode op)
|
||||
{
|
||||
int s[4];
|
||||
float d[4];
|
||||
@@ -686,7 +686,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vh2f(u32 op)
|
||||
void Int_Vh2f(MIPSOpcode op)
|
||||
{
|
||||
u32 s[4];
|
||||
float d[4];
|
||||
@@ -721,7 +721,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vf2h(u32 op)
|
||||
void Int_Vf2h(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
u32 d[4];
|
||||
@@ -753,7 +753,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vx2i(u32 op)
|
||||
void Int_Vx2i(MIPSOpcode op)
|
||||
{
|
||||
u32 s[4];
|
||||
u32 d[4] = {0};
|
||||
@@ -845,7 +845,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vi2x(u32 op)
|
||||
void Int_Vi2x(MIPSOpcode op)
|
||||
{
|
||||
int s[4];
|
||||
u32 d[2] = {0};
|
||||
@@ -920,7 +920,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_ColorConv(u32 op)
|
||||
void Int_ColorConv(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -969,7 +969,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VDot(u32 op)
|
||||
void Int_VDot(MIPSOpcode op)
|
||||
{
|
||||
float s[4], t[4];
|
||||
float d;
|
||||
@@ -994,7 +994,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VHdp(u32 op)
|
||||
void Int_VHdp(MIPSOpcode op)
|
||||
{
|
||||
float s[4], t[4];
|
||||
float d;
|
||||
@@ -1019,7 +1019,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vbfy(u32 op)
|
||||
void Int_Vbfy(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1051,7 +1051,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsrt1(u32 op)
|
||||
void Int_Vsrt1(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1074,7 +1074,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsrt2(u32 op)
|
||||
void Int_Vsrt2(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1097,7 +1097,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsrt3(u32 op)
|
||||
void Int_Vsrt3(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1120,7 +1120,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsrt4(u32 op)
|
||||
void Int_Vsrt4(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1143,7 +1143,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vcrs(u32 op)
|
||||
void Int_Vcrs(MIPSOpcode op)
|
||||
{
|
||||
//half a cross product
|
||||
float s[4], t[4];
|
||||
@@ -1167,7 +1167,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vdet(u32 op)
|
||||
void Int_Vdet(MIPSOpcode op)
|
||||
{
|
||||
float s[4], t[4];
|
||||
float d[4];
|
||||
@@ -1187,7 +1187,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vfad(u32 op)
|
||||
void Int_Vfad(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d;
|
||||
@@ -1209,7 +1209,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vavg(u32 op)
|
||||
void Int_Vavg(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d;
|
||||
@@ -1231,7 +1231,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VScl(u32 op)
|
||||
void Int_VScl(MIPSOpcode op)
|
||||
{
|
||||
float s[4];
|
||||
float d[4];
|
||||
@@ -1258,7 +1258,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vrnds(u32 op)
|
||||
void Int_Vrnds(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int seed = VI(vd);
|
||||
@@ -1267,7 +1267,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VrndX(u32 op)
|
||||
void Int_VrndX(MIPSOpcode op)
|
||||
{
|
||||
float d[4];
|
||||
int vd = _VD;
|
||||
@@ -1290,7 +1290,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
// Generates one line of a rotation matrix around one of the three axes
|
||||
void Int_Vrot(u32 op)
|
||||
void Int_Vrot(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -1315,7 +1315,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vtfm(u32 op)
|
||||
void Int_Vtfm(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -1372,7 +1372,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_SV(u32 op)
|
||||
void Int_SV(MIPSOpcode op)
|
||||
{
|
||||
s32 imm = (signed short)(op&0xFFFC);
|
||||
int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
|
||||
@@ -1395,7 +1395,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_Mftv(u32 op)
|
||||
void Int_Mftv(MIPSOpcode op)
|
||||
{
|
||||
int imm = op & 0xFF;
|
||||
int rt = _RT;
|
||||
@@ -1433,7 +1433,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Vmfvc(u32 op) {
|
||||
void Int_Vmfvc(MIPSOpcode op) {
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
@@ -1442,7 +1442,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Vmtvc(u32 op) {
|
||||
void Int_Vmtvc(MIPSOpcode op) {
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
@@ -1451,7 +1451,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_Vcst(u32 op)
|
||||
void Int_Vcst(MIPSOpcode op)
|
||||
{
|
||||
int conNum = (op >> 16) & 0x1f;
|
||||
int vd = _VD;
|
||||
@@ -1465,7 +1465,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vcmp(u32 op)
|
||||
void Int_Vcmp(MIPSOpcode op)
|
||||
{
|
||||
int vs = _VS;
|
||||
int vt = _VT;
|
||||
@@ -1527,7 +1527,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vminmax(u32 op) {
|
||||
void Int_Vminmax(MIPSOpcode op) {
|
||||
int vt = _VT;
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1565,7 +1565,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
// This doesn't quite pass all the tests :/
|
||||
void Int_Vscmp(u32 op) {
|
||||
void Int_Vscmp(MIPSOpcode op) {
|
||||
int vt = _VT;
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1588,7 +1588,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsge(u32 op) {
|
||||
void Int_Vsge(MIPSOpcode op) {
|
||||
int vt = _VT;
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1614,7 +1614,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vslt(u32 op) {
|
||||
void Int_Vslt(MIPSOpcode op) {
|
||||
int vt = _VT;
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1641,7 +1641,7 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_Vcmov(u32 op)
|
||||
void Int_Vcmov(MIPSOpcode op)
|
||||
{
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1683,7 +1683,7 @@ namespace MIPSInt
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_VecDo3(u32 op)
|
||||
void Int_VecDo3(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -1729,7 +1729,7 @@ bad:
|
||||
}
|
||||
|
||||
|
||||
void Int_CrossQuat(u32 op)
|
||||
void Int_CrossQuat(MIPSOpcode op)
|
||||
{
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
@@ -1764,7 +1764,7 @@ bad:
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vlgb(u32 op)
|
||||
void Int_Vlgb(MIPSOpcode op)
|
||||
{
|
||||
// S & D valid
|
||||
Reporting::ReportMessage("vlgb not implemented");
|
||||
@@ -1775,7 +1775,7 @@ bad:
|
||||
|
||||
// There has to be a concise way of expressing this in terms of
|
||||
// bit manipulation on the raw floats.
|
||||
void Int_Vwbn(u32 op) {
|
||||
void Int_Vwbn(MIPSOpcode op) {
|
||||
Reporting::ReportMessage("vwbn not implemented");
|
||||
_dbg_assert_msg_(CPU,0,"vwbn not implemented");
|
||||
PC += 4;
|
||||
@@ -1807,7 +1807,7 @@ bad:
|
||||
EatPrefixes();*/
|
||||
}
|
||||
|
||||
void Int_Vsbn(u32 op)
|
||||
void Int_Vsbn(MIPSOpcode op)
|
||||
{
|
||||
Reporting::ReportMessage("vsbn not implemented");
|
||||
_dbg_assert_msg_(CPU,0,"vsbn not implemented");
|
||||
@@ -1815,7 +1815,7 @@ bad:
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
void Int_Vsbz(u32 op)
|
||||
void Int_Vsbz(MIPSOpcode op)
|
||||
{
|
||||
Reporting::ReportMessage("vsbz not implemented");
|
||||
_dbg_assert_msg_(CPU,0,"vsbz not implemented");
|
||||
|
||||
+56
-56
@@ -25,60 +25,60 @@ int MIPS_SingleStep();
|
||||
|
||||
namespace MIPSInt
|
||||
{
|
||||
void Int_SV(u32 op);
|
||||
void Int_SVQ(u32 op);
|
||||
void Int_Mftv(u32 op);
|
||||
void Int_MatrixSet(u32 op);
|
||||
void Int_VecDo3(u32 op);
|
||||
void Int_Vcst(u32 op);
|
||||
void Int_VMatrixInit(u32 op);
|
||||
void Int_VVectorInit(u32 op);
|
||||
void Int_Vmmul(u32 op);
|
||||
void Int_Vmscl(u32 op);
|
||||
void Int_Vmmov(u32 op);
|
||||
void Int_VV2Op(u32 op);
|
||||
void Int_Vrot(u32 op);
|
||||
void Int_VDot(u32 op);
|
||||
void Int_VHdp(u32 op);
|
||||
void Int_Vavg(u32 op);
|
||||
void Int_Vfad(u32 op);
|
||||
void Int_Vocp(u32 op);
|
||||
void Int_Vsocp(u32 op);
|
||||
void Int_Vsgn(u32 op);
|
||||
void Int_Vtfm(u32 op);
|
||||
void Int_Viim(u32 op);
|
||||
void Int_VScl(u32 op);
|
||||
void Int_Vidt(u32 op);
|
||||
void Int_Vcmp(u32 op);
|
||||
void Int_Vminmax(u32 op);
|
||||
void Int_Vscmp(u32 op);
|
||||
void Int_Vcrs(u32 op);
|
||||
void Int_Vdet(u32 op);
|
||||
void Int_Vcmov(u32 op);
|
||||
void Int_CrossQuat(u32 op);
|
||||
void Int_VPFX(u32 op);
|
||||
void Int_Vflush(u32 op);
|
||||
void Int_Vbfy(u32 op);
|
||||
void Int_Vsrt1(u32 op);
|
||||
void Int_Vsrt2(u32 op);
|
||||
void Int_Vsrt3(u32 op);
|
||||
void Int_Vsrt4(u32 op);
|
||||
void Int_Vf2i(u32 op);
|
||||
void Int_Vi2f(u32 op);
|
||||
void Int_Vi2x(u32 op);
|
||||
void Int_Vx2i(u32 op);
|
||||
void Int_VBranch(u32 op);
|
||||
void Int_Vrnds(u32 op);
|
||||
void Int_VrndX(u32 op);
|
||||
void Int_ColorConv(u32 op);
|
||||
void Int_Vh2f(u32 op);
|
||||
void Int_Vf2h(u32 op);
|
||||
void Int_Vsge(u32 op);
|
||||
void Int_Vslt(u32 op);
|
||||
void Int_Vmfvc(u32 op);
|
||||
void Int_Vmtvc(u32 op);
|
||||
void Int_Vlgb(u32 op);
|
||||
void Int_Vwbn(u32 op);
|
||||
void Int_Vsbn(u32 op);
|
||||
void Int_Vsbz(u32 op);
|
||||
void Int_SV(MIPSOpcode op);
|
||||
void Int_SVQ(MIPSOpcode op);
|
||||
void Int_Mftv(MIPSOpcode op);
|
||||
void Int_MatrixSet(MIPSOpcode op);
|
||||
void Int_VecDo3(MIPSOpcode op);
|
||||
void Int_Vcst(MIPSOpcode op);
|
||||
void Int_VMatrixInit(MIPSOpcode op);
|
||||
void Int_VVectorInit(MIPSOpcode op);
|
||||
void Int_Vmmul(MIPSOpcode op);
|
||||
void Int_Vmscl(MIPSOpcode op);
|
||||
void Int_Vmmov(MIPSOpcode op);
|
||||
void Int_VV2Op(MIPSOpcode op);
|
||||
void Int_Vrot(MIPSOpcode op);
|
||||
void Int_VDot(MIPSOpcode op);
|
||||
void Int_VHdp(MIPSOpcode op);
|
||||
void Int_Vavg(MIPSOpcode op);
|
||||
void Int_Vfad(MIPSOpcode op);
|
||||
void Int_Vocp(MIPSOpcode op);
|
||||
void Int_Vsocp(MIPSOpcode op);
|
||||
void Int_Vsgn(MIPSOpcode op);
|
||||
void Int_Vtfm(MIPSOpcode op);
|
||||
void Int_Viim(MIPSOpcode op);
|
||||
void Int_VScl(MIPSOpcode op);
|
||||
void Int_Vidt(MIPSOpcode op);
|
||||
void Int_Vcmp(MIPSOpcode op);
|
||||
void Int_Vminmax(MIPSOpcode op);
|
||||
void Int_Vscmp(MIPSOpcode op);
|
||||
void Int_Vcrs(MIPSOpcode op);
|
||||
void Int_Vdet(MIPSOpcode op);
|
||||
void Int_Vcmov(MIPSOpcode op);
|
||||
void Int_CrossQuat(MIPSOpcode op);
|
||||
void Int_VPFX(MIPSOpcode op);
|
||||
void Int_Vflush(MIPSOpcode op);
|
||||
void Int_Vbfy(MIPSOpcode op);
|
||||
void Int_Vsrt1(MIPSOpcode op);
|
||||
void Int_Vsrt2(MIPSOpcode op);
|
||||
void Int_Vsrt3(MIPSOpcode op);
|
||||
void Int_Vsrt4(MIPSOpcode op);
|
||||
void Int_Vf2i(MIPSOpcode op);
|
||||
void Int_Vi2f(MIPSOpcode op);
|
||||
void Int_Vi2x(MIPSOpcode op);
|
||||
void Int_Vx2i(MIPSOpcode op);
|
||||
void Int_VBranch(MIPSOpcode op);
|
||||
void Int_Vrnds(MIPSOpcode op);
|
||||
void Int_VrndX(MIPSOpcode op);
|
||||
void Int_ColorConv(MIPSOpcode op);
|
||||
void Int_Vh2f(MIPSOpcode op);
|
||||
void Int_Vf2h(MIPSOpcode op);
|
||||
void Int_Vsge(MIPSOpcode op);
|
||||
void Int_Vslt(MIPSOpcode op);
|
||||
void Int_Vmfvc(MIPSOpcode op);
|
||||
void Int_Vmtvc(MIPSOpcode op);
|
||||
void Int_Vlgb(MIPSOpcode op);
|
||||
void Int_Vwbn(MIPSOpcode op);
|
||||
void Int_Vsbn(MIPSOpcode op);
|
||||
void Int_Vsbz(MIPSOpcode op);
|
||||
}
|
||||
@@ -44,15 +44,15 @@ namespace MIPSStackWalk {
|
||||
return INVALIDTARGET;
|
||||
}
|
||||
|
||||
bool IsSWInstr(u32 op) {
|
||||
bool IsSWInstr(MIPSOpcode op) {
|
||||
return (op & MIPSTABLE_IMM_MASK) == 0xAC000000;
|
||||
}
|
||||
|
||||
bool IsAddImmInstr(u32 op) {
|
||||
bool IsAddImmInstr(MIPSOpcode op) {
|
||||
return (op & MIPSTABLE_IMM_MASK) == 0x20000000 || (op & MIPSTABLE_IMM_MASK) == 0x24000000;
|
||||
}
|
||||
|
||||
bool IsMovRegsInstr(u32 op) {
|
||||
bool IsMovRegsInstr(MIPSOpcode op) {
|
||||
// TODO: There are more options here. Let's assume addu for now.
|
||||
if ((op & MIPSTABLE_SPECIAL_MASK) == 0x00000021) {
|
||||
return _RS == 0 || _RT == 0;
|
||||
@@ -67,7 +67,7 @@ namespace MIPSStackWalk {
|
||||
// It ought to be pretty close.
|
||||
u32 stop = pc - 32 * 4;
|
||||
for (; Memory::IsValidAddress(pc) && pc >= stop; pc -= 4) {
|
||||
u32 op = Memory::Read_Instruction(pc);
|
||||
MIPSOpcode op = Memory::Read_Instruction(pc);
|
||||
|
||||
// We're looking for a "mov fp, sp" close by a "addiu sp, sp, -N".
|
||||
if (IsMovRegsInstr(op) && _RD == MIPS_REG_FP && (_RS == MIPS_REG_SP || _RT == MIPS_REG_SP)) {
|
||||
@@ -83,7 +83,7 @@ namespace MIPSStackWalk {
|
||||
int ra_offset = -1;
|
||||
u32 stop = entry == INVALIDTARGET ? 0 : entry;
|
||||
for (u32 pc = frame.pc; Memory::IsValidAddress(pc) && pc >= stop; pc -= 4) {
|
||||
u32 op = Memory::Read_Instruction(pc);
|
||||
MIPSOpcode op = Memory::Read_Instruction(pc);
|
||||
|
||||
// Here's where they store the ra address.
|
||||
if (IsSWInstr(op) && _RT == MIPS_REG_RA && _RS == MIPS_REG_SP) {
|
||||
|
||||
+21
-21
@@ -71,7 +71,7 @@ struct MIPSInstruction
|
||||
#endif
|
||||
MIPSInterpretFunc interpret;
|
||||
//MIPSInstructionInfo information;
|
||||
u32 flags;
|
||||
MIPSInfo flags;
|
||||
};
|
||||
|
||||
#define INVALID {-2}
|
||||
@@ -80,7 +80,7 @@ struct MIPSInstruction
|
||||
|
||||
#ifndef FINAL
|
||||
#define ENCODING(a) {a}
|
||||
#define INSTR(name, comp, dis, inter, flags) {-1, N(name), comp, dis, inter, flags}
|
||||
#define INSTR(name, comp, dis, inter, flags) {-1, N(name), comp, dis, inter, MIPSInfo(flags)}
|
||||
#else
|
||||
#define ENCODING(a) {a}
|
||||
#define INSTR(name, comp, dis, inter, flags) {-1, comp, inter, flags}
|
||||
@@ -257,9 +257,9 @@ const MIPSInstruction tableSpecial2[64] = // 011100 ..... ..... ..... ..... xxxx
|
||||
INVALID_X_8,
|
||||
//32
|
||||
INVALID, INVALID, INVALID, INVALID,
|
||||
INSTR("mfic", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
||||
INSTR("mfic", &Jit::Comp_Generic, Dis_Generic, Int_Special2, 0),
|
||||
INVALID,
|
||||
INSTR("mtic", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
||||
INSTR("mtic", &Jit::Comp_Generic, Dis_Generic, Int_Special2, 0),
|
||||
INVALID,
|
||||
//40
|
||||
INVALID_X_8,
|
||||
@@ -891,7 +891,7 @@ const MIPSInstruction *mipsTables[NumEncodings] =
|
||||
//Todo : generate dispatcher functions from above tables
|
||||
//instead of this horribly slow abomination
|
||||
|
||||
const MIPSInstruction *MIPSGetInstruction(u32 op)
|
||||
const MIPSInstruction *MIPSGetInstruction(MIPSOpcode op)
|
||||
{
|
||||
MipsEncoding encoding = Imme;
|
||||
const MIPSInstruction *instr = &tableImmediate[op>>26];
|
||||
@@ -919,19 +919,19 @@ const MIPSInstruction *MIPSGetInstruction(u32 op)
|
||||
|
||||
|
||||
|
||||
void MIPSCompileOp(u32 op)
|
||||
void MIPSCompileOp(MIPSOpcode op)
|
||||
{
|
||||
if (op==0)
|
||||
return;
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
const int info = MIPSGetInfo(op);
|
||||
const MIPSInfo info = MIPSGetInfo(op);
|
||||
if (instr)
|
||||
{
|
||||
if (instr->compile)
|
||||
(MIPSComp::jit->*(instr->compile))(op); // woohoo, member functions pointers!
|
||||
else
|
||||
{
|
||||
ERROR_LOG_REPORT(CPU,"MIPSCompileOp %08x failed",op);
|
||||
ERROR_LOG_REPORT(CPU,"MIPSCompileOp %08x failed",op.encoding);
|
||||
//MessageBox(0,"ARGH2",0,0);//compile an interpreter call
|
||||
}
|
||||
|
||||
@@ -940,12 +940,12 @@ void MIPSCompileOp(u32 op)
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG_REPORT(CPU, "MIPSCompileOp: Invalid instruction %08x", op);
|
||||
ERROR_LOG_REPORT(CPU, "MIPSCompileOp: Invalid instruction %08x", op.encoding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MIPSDisAsm(u32 op, u32 pc, char *out, bool tabsToSpaces)
|
||||
void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces)
|
||||
{
|
||||
if (op == 0)
|
||||
{
|
||||
@@ -973,7 +973,7 @@ void MIPSDisAsm(u32 op, u32 pc, char *out, bool tabsToSpaces)
|
||||
}
|
||||
|
||||
|
||||
void MIPSInterpret(u32 op) //only for those rare ones
|
||||
void MIPSInterpret(MIPSOpcode op) //only for those rare ones
|
||||
{
|
||||
//if ((op&0xFFFFF000) == 0xd0110000)
|
||||
// Crash();
|
||||
@@ -986,7 +986,7 @@ void MIPSInterpret(u32 op) //only for those rare ones
|
||||
instr->interpret(op);
|
||||
else
|
||||
{
|
||||
ERROR_LOG_REPORT(CPU, "Unknown instruction %08x at %08x", op, currentMIPS->pc);
|
||||
ERROR_LOG_REPORT(CPU, "Unknown instruction %08x at %08x", op.encoding, currentMIPS->pc);
|
||||
// Try to disassemble it
|
||||
char disasm[256];
|
||||
MIPSDisAsm(op, currentMIPS->pc, disasm);
|
||||
@@ -1014,11 +1014,11 @@ int MIPSInterpret_RunUntil(u64 globalTicks)
|
||||
// int cycles = 0;
|
||||
{
|
||||
again:
|
||||
u32 op = Memory::Read_U32(curMips->pc);
|
||||
//u32 op = Memory::Read_Opcode_JIT(mipsr4k.pc);
|
||||
MIPSOpcode op = MIPSOpcode(Memory::Read_U32(curMips->pc));
|
||||
//MIPSOpcode op = Memory::Read_Opcode_JIT(mipsr4k.pc);
|
||||
/*
|
||||
// Choke on VFPU
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if (info & IS_VFPU)
|
||||
{
|
||||
if (!Core_IsStepping() && !GetAsyncKeyState(VK_LSHIFT))
|
||||
@@ -1079,7 +1079,7 @@ static inline void DelayBranchTo(MIPSState *curMips, u32 where)
|
||||
curMips->inDelaySlot = true;
|
||||
}
|
||||
|
||||
const char *MIPSGetName(u32 op)
|
||||
const char *MIPSGetName(MIPSOpcode op)
|
||||
{
|
||||
static const char *noname = "unk";
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
@@ -1089,17 +1089,17 @@ const char *MIPSGetName(u32 op)
|
||||
return instr->name;
|
||||
}
|
||||
|
||||
u32 MIPSGetInfo(u32 op)
|
||||
MIPSInfo MIPSGetInfo(MIPSOpcode op)
|
||||
{
|
||||
// int crunch = CRUNCH_MIPS_OP(op);
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
if (instr)
|
||||
return instr->flags;
|
||||
else
|
||||
return 0;
|
||||
return MIPSInfo(BAD_INSTRUCTION);
|
||||
}
|
||||
|
||||
MIPSInterpretFunc MIPSGetInterpretFunc(u32 op)
|
||||
MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op)
|
||||
{
|
||||
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
||||
if (instr->interpret)
|
||||
@@ -1109,9 +1109,9 @@ MIPSInterpretFunc MIPSGetInterpretFunc(u32 op)
|
||||
}
|
||||
|
||||
// TODO: Do something that makes sense here.
|
||||
int MIPSGetInstructionCycleEstimate(u32 op)
|
||||
int MIPSGetInstructionCycleEstimate(MIPSOpcode op)
|
||||
{
|
||||
u32 info = MIPSGetInfo(op);
|
||||
MIPSInfo info = MIPSGetInfo(op);
|
||||
if (info & DELAYSLOT)
|
||||
return 2;
|
||||
else
|
||||
|
||||
+48
-33
@@ -17,7 +17,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Globals.h"
|
||||
#include "Globals.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
|
||||
struct MIPSInfo {
|
||||
MIPSInfo() {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
explicit MIPSInfo(u32 v) : value(v) {
|
||||
}
|
||||
|
||||
u32 operator & (const u32 &arg) const {
|
||||
return value & arg;
|
||||
}
|
||||
|
||||
u32 value;
|
||||
};
|
||||
|
||||
#define CONDTYPE_MASK 0x00000007
|
||||
#define CONDTYPE_EQ 0x00000001
|
||||
@@ -40,50 +56,49 @@
|
||||
#define IS_CONDMOVE 0x00000008
|
||||
#define DELAYSLOT 0x00000010
|
||||
#define BAD_INSTRUCTION 0x00000020
|
||||
#define UNCONDITIONAL 0x00000040
|
||||
#define LIKELY 0x00000080
|
||||
#define IS_CONDBRANCH 0x00000100
|
||||
#define IS_JUMP 0x00000200
|
||||
#define LIKELY 0x00000040
|
||||
#define IS_CONDBRANCH 0x00000080
|
||||
#define IS_JUMP 0x00000100
|
||||
|
||||
#define IN_RS 0x00000400
|
||||
#define IN_RS_ADDR (0x00000800 | IN_RS)
|
||||
#define IN_RS_SHIFT (0x00001000 | IN_RS)
|
||||
#define IN_RT 0x00002000
|
||||
#define IN_SA 0x00004000
|
||||
#define IN_IMM16 0x00008000
|
||||
#define IN_IMM26 0x00010000
|
||||
#define IN_MEM 0x00020000
|
||||
#define IN_OTHER 0x00040000
|
||||
#define IN_FPUFLAG 0x00080000
|
||||
#define IN_RS 0x00000200
|
||||
#define IN_RS_ADDR (0x00000400 | IN_RS)
|
||||
#define IN_RS_SHIFT (0x00000800 | IN_RS)
|
||||
#define IN_RT 0x00001000
|
||||
#define IN_SA 0x00002000
|
||||
#define IN_IMM16 0x00004000
|
||||
#define IN_IMM26 0x00008000
|
||||
#define IN_MEM 0x00010000
|
||||
#define IN_OTHER 0x00020000
|
||||
#define IN_FPUFLAG 0x00040000
|
||||
|
||||
#define OUT_RT 0x00100000
|
||||
#define OUT_RD 0x00200000
|
||||
#define OUT_RA 0x00400000
|
||||
#define OUT_MEM 0x00800000
|
||||
#define OUT_OTHER 0x01000000
|
||||
#define OUT_FPUFLAG 0x02000000
|
||||
#define OUT_EAT_PREFIX 0x04000000
|
||||
#define OUT_RT 0x00080000
|
||||
#define OUT_RD 0x00100000
|
||||
#define OUT_RA 0x00200000
|
||||
#define OUT_MEM 0x00400000
|
||||
#define OUT_OTHER 0x00800000
|
||||
#define OUT_FPUFLAG 0x01000000
|
||||
#define OUT_EAT_PREFIX 0x02000000
|
||||
|
||||
#define VFPU_NO_PREFIX 0x08000000
|
||||
#define IS_VFPU 0x80000000
|
||||
#define VFPU_NO_PREFIX 0x04000000
|
||||
#define IS_VFPU 0x08000000
|
||||
|
||||
#ifndef CDECL
|
||||
#define CDECL
|
||||
#endif
|
||||
|
||||
typedef void (CDECL *MIPSDisFunc)(u32 opcode, char *out);
|
||||
typedef void (CDECL *MIPSInterpretFunc)(u32 opcode);
|
||||
typedef void (CDECL *MIPSDisFunc)(MIPSOpcode opcode, char *out);
|
||||
typedef void (CDECL *MIPSInterpretFunc)(MIPSOpcode opcode);
|
||||
|
||||
|
||||
void MIPSCompileOp(u32 op);
|
||||
void MIPSDisAsm(u32 op, u32 pc, char *out, bool tabsToSpaces = false);
|
||||
u32 MIPSGetInfo(u32 op);
|
||||
void MIPSInterpret(u32 op); //only for those rare ones
|
||||
void MIPSCompileOp(MIPSOpcode op);
|
||||
void MIPSDisAsm(MIPSOpcode op, u32 pc, char *out, bool tabsToSpaces = false);
|
||||
MIPSInfo MIPSGetInfo(MIPSOpcode op);
|
||||
void MIPSInterpret(MIPSOpcode op); //only for those rare ones
|
||||
int MIPSInterpret_RunUntil(u64 globalTicks);
|
||||
MIPSInterpretFunc MIPSGetInterpretFunc(u32 op);
|
||||
MIPSInterpretFunc MIPSGetInterpretFunc(MIPSOpcode op);
|
||||
|
||||
int MIPSGetInstructionCycleEstimate(u32 op);
|
||||
const char *MIPSGetName(u32 op);
|
||||
int MIPSGetInstructionCycleEstimate(MIPSOpcode op);
|
||||
const char *MIPSGetName(MIPSOpcode op);
|
||||
|
||||
|
||||
void FillMIPSTables();
|
||||
@@ -226,7 +226,7 @@ VectorSize GetHalfVectorSize(VectorSize sz)
|
||||
}
|
||||
}
|
||||
|
||||
VectorSize GetVecSize(u32 op)
|
||||
VectorSize GetVecSize(MIPSOpcode op)
|
||||
{
|
||||
int a = (op>>7)&1;
|
||||
int b = (op>>15)&1;
|
||||
@@ -241,7 +241,7 @@ VectorSize GetVecSize(u32 op)
|
||||
}
|
||||
}
|
||||
|
||||
MatrixSize GetMtxSize(u32 op)
|
||||
MatrixSize GetMtxSize(MIPSOpcode op)
|
||||
{
|
||||
int a = (op>>7)&1;
|
||||
int b = (op>>15)&1;
|
||||
|
||||
@@ -65,8 +65,8 @@ inline int GetMtx(int matrixReg) {
|
||||
return (matrixReg >> 2) & 7;
|
||||
}
|
||||
|
||||
VectorSize GetVecSize(u32 op);
|
||||
MatrixSize GetMtxSize(u32 op);
|
||||
VectorSize GetVecSize(MIPSOpcode op);
|
||||
MatrixSize GetMtxSize(MIPSOpcode op);
|
||||
VectorSize GetHalfVectorSize(VectorSize sz);
|
||||
int GetNumVectorElements(VectorSize sz);
|
||||
int GetMatrixSide(MatrixSize sz);
|
||||
|
||||
@@ -169,8 +169,8 @@ void Jit::ClearCache() {
|
||||
GenerateFixedCode();
|
||||
}
|
||||
|
||||
void Jit::ClearCacheAt(u32 em_address) {
|
||||
ClearCache();
|
||||
void Jit::ClearCacheAt(u32 em_address, int length) {
|
||||
blocks.InvalidateICache(em_address, length);
|
||||
}
|
||||
|
||||
Jit::Jit(MIPSState *mips) : blocks(mips, this), gpr(mips, &jo),mips_(mips)
|
||||
|
||||
@@ -242,7 +242,7 @@ namespace MIPSComp
|
||||
void WriteSyscallExit();
|
||||
|
||||
void ClearCache();
|
||||
void ClearCacheAt(u32 em_address);
|
||||
void ClearCacheAt(u32 em_address, int length = 4);
|
||||
|
||||
void RunLoopUntil(u64 globalticks);
|
||||
void GenerateFixedCode();
|
||||
|
||||
+70
-66
@@ -15,20 +15,24 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Jit.h"
|
||||
#include "RegCache.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
#include "Core/MIPS/x86/Jit.h"
|
||||
#include "Core/MIPS/x86/RegCache.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace MIPSAnalyst;
|
||||
#define _RS ((op>>21) & 0x1F)
|
||||
#define _RT ((op>>16) & 0x1F)
|
||||
#define _RD ((op>>11) & 0x1F)
|
||||
#define _FS ((op>>11) & 0x1F)
|
||||
#define _FT ((op>>16) & 0x1F)
|
||||
#define _FD ((op>>6 ) & 0x1F)
|
||||
#define _SA ((op>>6 ) & 0x1F)
|
||||
#define _POS ((op>>6 ) & 0x1F)
|
||||
#define _SIZE ((op>>11 ) & 0x1F)
|
||||
|
||||
#define _RS MIPS_GET_RS(op)
|
||||
#define _RT MIPS_GET_RT(op)
|
||||
#define _RD MIPS_GET_RD(op)
|
||||
#define _FS MIPS_GET_FS(op)
|
||||
#define _FT MIPS_GET_FT(op)
|
||||
#define _FD MIPS_GET_FD(op)
|
||||
#define _SA MIPS_GET_SA(op)
|
||||
#define _POS ((op>> 6) & 0x1F)
|
||||
#define _SIZE ((op>>11) & 0x1F)
|
||||
#define _IMM16 (signed short)(op & 0xFFFF)
|
||||
#define _IMM26 (op & 0x03FFFFFF)
|
||||
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
@@ -39,11 +43,11 @@ using namespace MIPSAnalyst;
|
||||
|
||||
namespace MIPSComp
|
||||
{
|
||||
void Jit::CompImmLogic(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &))
|
||||
void Jit::CompImmLogic(MIPSOpcode op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &))
|
||||
{
|
||||
u32 uimm = (u16)(op & 0xFFFF);
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
gpr.Lock(rt, rs);
|
||||
gpr.BindToRegister(rt, rt == rs, true);
|
||||
if (rt != rs)
|
||||
@@ -52,18 +56,18 @@ namespace MIPSComp
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
||||
void Jit::Comp_IType(u32 op)
|
||||
void Jit::Comp_IType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
||||
s32 simm = (s32)_IMM16; // sign extension
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = (u32)(s32)simm;
|
||||
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
// noop, won't write to ZERO.
|
||||
if (rt == 0)
|
||||
if (rt == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
switch (op >> 26)
|
||||
@@ -159,14 +163,14 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_RType2(u32 op)
|
||||
void Jit::Comp_RType2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
if (rd == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
switch (op & 63)
|
||||
@@ -266,11 +270,11 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
//rd = rs X rt
|
||||
void Jit::CompTriArith(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &), u32 (*doImm)(const u32, const u32))
|
||||
void Jit::CompTriArith(MIPSOpcode op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &), u32 (*doImm)(const u32, const u32))
|
||||
{
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
// Yes, this happens. Let's make it fast.
|
||||
if (doImm && gpr.IsImmediate(rs) && gpr.IsImmediate(rt))
|
||||
@@ -281,19 +285,19 @@ namespace MIPSComp
|
||||
|
||||
// Act like zero was used if the operand is equivalent. This happens.
|
||||
if (gpr.IsImmediate(rs) && gpr.GetImmediate32(rs) == 0)
|
||||
rs = 0;
|
||||
rs = MIPS_REG_ZERO;
|
||||
if (gpr.IsImmediate(rt) && gpr.GetImmediate32(rt) == 0)
|
||||
rt = 0;
|
||||
rt = MIPS_REG_ZERO;
|
||||
|
||||
gpr.Lock(rt, rs, rd);
|
||||
// Optimize out operations against 0... and is the only one that isn't a MOV.
|
||||
if (rt == 0 || (rs == 0 && doImm != &RType3_ImmSub))
|
||||
if (rt == MIPS_REG_ZERO || (rs == MIPS_REG_ZERO && doImm != &RType3_ImmSub))
|
||||
{
|
||||
if (doImm == &RType3_ImmAnd)
|
||||
gpr.SetImmediate32(rd, 0);
|
||||
else
|
||||
{
|
||||
int rsource = rt == 0 ? rs : rt;
|
||||
MIPSGPReg rsource = rt == MIPS_REG_ZERO ? rs : rt;
|
||||
if (rsource != rd)
|
||||
{
|
||||
gpr.BindToRegister(rd, false, true);
|
||||
@@ -323,16 +327,16 @@ namespace MIPSComp
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
||||
void Jit::Comp_RType3(u32 op)
|
||||
void Jit::Comp_RType3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
// noop, won't write to ZERO.
|
||||
if (rd == 0)
|
||||
if (rd == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
switch (op & 63)
|
||||
@@ -451,7 +455,7 @@ namespace MIPSComp
|
||||
gpr.SetImmediate32(rd, std::max((s32)gpr.GetImmediate32(rs), (s32)gpr.GetImmediate32(rt)));
|
||||
else
|
||||
{
|
||||
int rsrc = rd == rt ? rs : rt;
|
||||
MIPSGPReg rsrc = rd == rt ? rs : rt;
|
||||
gpr.Lock(rd, rs, rt);
|
||||
gpr.KillImmediate(rsrc, true, false);
|
||||
gpr.BindToRegister(rd, rd == rs || rd == rt, true);
|
||||
@@ -468,7 +472,7 @@ namespace MIPSComp
|
||||
gpr.SetImmediate32(rd, std::min((s32)gpr.GetImmediate32(rs), (s32)gpr.GetImmediate32(rt)));
|
||||
else
|
||||
{
|
||||
int rsrc = rd == rt ? rs : rt;
|
||||
MIPSGPReg rsrc = rd == rt ? rs : rt;
|
||||
gpr.Lock(rd, rs, rt);
|
||||
gpr.KillImmediate(rsrc, true, false);
|
||||
gpr.BindToRegister(rd, rd == rs || rd == rt, true);
|
||||
@@ -507,10 +511,10 @@ namespace MIPSComp
|
||||
return (a >> sa) | (a << (32 - sa));
|
||||
}
|
||||
|
||||
void Jit::CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32))
|
||||
void Jit::CompShiftImm(MIPSOpcode op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32))
|
||||
{
|
||||
int rd = _RD;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
int sa = _SA;
|
||||
|
||||
if (doImm && gpr.IsImmediate(rt))
|
||||
@@ -528,11 +532,11 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
// "over-shifts" work the same as on x86 - only bottom 5 bits are used to get the shift value
|
||||
void Jit::CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32))
|
||||
void Jit::CompShiftVar(MIPSOpcode op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32))
|
||||
{
|
||||
int rd = _RD;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
|
||||
if (doImm && gpr.IsImmediate(rs) && gpr.IsImmediate(rt))
|
||||
{
|
||||
@@ -563,15 +567,15 @@ namespace MIPSComp
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
||||
void Jit::Comp_ShiftType(u32 op)
|
||||
void Jit::Comp_ShiftType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
int fd = _FD;
|
||||
int rs = (op>>21) & 0x1F;
|
||||
MIPSGPReg rd = _RD;
|
||||
int fd = (op>>6) & 0x1F;
|
||||
|
||||
// noop, won't write to ZERO.
|
||||
if (rd == 0)
|
||||
if (rd == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
// WARNING : ROTR
|
||||
@@ -591,18 +595,18 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Special3(u32 op)
|
||||
void Jit::Comp_Special3(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rs = _RS;
|
||||
int rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rt = _RT;
|
||||
|
||||
int pos = _POS;
|
||||
int size = _SIZE + 1;
|
||||
u32 mask = 0xFFFFFFFFUL >> (32 - size);
|
||||
|
||||
// Don't change $zr.
|
||||
if (rt == 0)
|
||||
if (rt == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
switch (op & 0x3f)
|
||||
@@ -659,13 +663,13 @@ namespace MIPSComp
|
||||
}
|
||||
|
||||
|
||||
void Jit::Comp_Allegrex(u32 op)
|
||||
void Jit::Comp_Allegrex(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
if (rd == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
switch ((op >> 6) & 31)
|
||||
@@ -769,13 +773,13 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_Allegrex2(u32 op)
|
||||
void Jit::Comp_Allegrex2(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE
|
||||
int rt = _RT;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rd = _RD;
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
if (rd == MIPS_REG_ZERO)
|
||||
return;
|
||||
|
||||
DISABLE;
|
||||
@@ -799,12 +803,12 @@ namespace MIPSComp
|
||||
}
|
||||
}
|
||||
|
||||
void Jit::Comp_MulDivType(u32 op)
|
||||
void Jit::Comp_MulDivType(MIPSOpcode op)
|
||||
{
|
||||
CONDITIONAL_DISABLE;
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
MIPSGPReg rt = _RT;
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
|
||||
switch (op & 63)
|
||||
{
|
||||
|
||||
Loaded 100 of 202 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user