diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e75915160..5a954889ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Common/CPUDetect.cpp b/Common/CPUDetect.cpp index f6bc215514..7d68a26626 100644 --- a/Common/CPUDetect.cpp +++ b/Common/CPUDetect.cpp @@ -15,7 +15,14 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#ifdef ANDROID +#include +#include +#endif + #include +#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 diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 78a468f68d..be4cdd36af 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -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 void Do(std::vector &x) { - T dv; + T dv = T(); DoVector(x, dv); } @@ -291,7 +291,7 @@ public: template void DoPOD(std::vector &x) { - T dv; + T dv = T(); DoVectorPOD(x, dv); } @@ -332,7 +332,7 @@ public: template void Do(std::deque &x) { - T dv; + T dv = T(); DoDeque(x, dv); } @@ -358,7 +358,7 @@ public: template void Do(std::list &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); } diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index ed3003e5f1..c2442eba33 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -27,22 +27,22 @@ StaticLibrary true - MultiByte + Unicode StaticLibrary true - MultiByte + Unicode StaticLibrary false - MultiByte + Unicode StaticLibrary false - MultiByte + Unicode diff --git a/Common/ConsoleListener.cpp b/Common/ConsoleListener.cpp index 61fba341a2..f3a583a36b 100644 --- a/Common/ConsoleListener.cpp +++ b/Common/ConsoleListener.cpp @@ -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> Str; + std::vector> Str; std::vector> Attr; // ReadConsoleOutputAttribute seems to have a limit at this level diff --git a/Common/ExtendedTrace.cpp b/Common/ExtendedTrace.cpp index 751d9b3d54..ba884a1d12 100644 --- a/Common/ExtendedTrace.cpp +++ b/Common/ExtendedTrace.cpp @@ -17,6 +17,8 @@ #include "CommonWindows.h" #include #include "ExtendedTrace.h" + +#include using namespace std; #include @@ -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 diff --git a/Common/ExtendedTrace.h b/Common/ExtendedTrace.h index 433f3e6d07..4b10a98476 100644 --- a/Common/ExtendedTrace.h +++ b/Common/ExtendedTrace.h @@ -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]; diff --git a/Common/FileSearch.cpp b/Common/FileSearch.cpp index fb620e0269..ffd78ff38f 100644 --- a/Common/FileSearch.cpp +++ b/Common/FileSearch.cpp @@ -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); } diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 9f93febbd8..b78d51b8b1 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -41,6 +41,8 @@ #include #endif +#include "util/text/utf8.h" + #include #include @@ -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 diff --git a/Common/FileUtil.h b/Common/FileUtil.h index e11a3d40f8..e8c40d7cf7 100644 --- a/Common/FileUtil.h +++ b/Common/FileUtil.h @@ -59,6 +59,9 @@ struct FSTEntry std::vector 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); diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp index 98ca6f1b2d..ccc78d320b 100644 --- a/Common/KeyMap.cpp +++ b/Common/KeyMap.cpp @@ -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); diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 85d3f638ff..5a6a98a113 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -16,7 +16,7 @@ // http://code.google.com/p/dolphin-emu/ #include - +#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 } diff --git a/Common/Misc.cpp b/Common/Misc.cpp index 37807a0f61..f40187a779 100644 --- a/Common/Misc.cpp +++ b/Common/Misc.cpp @@ -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 diff --git a/Common/MsgHandler.cpp b/Common/MsgHandler.cpp index 1bc7f4cd0c..4ebb401cd6 100644 --- a/Common/MsgHandler.cpp +++ b/Common/MsgHandler.cpp @@ -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 } diff --git a/Core/Config.cpp b/Core/Config.cpp index a39c67b7fe..57ce29f017 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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(); +} diff --git a/Core/Config.h b/Core/Config.h index 64e5443146..f98545acc7 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -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); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 7600d46b7a..850a8af2d5 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -26,24 +26,24 @@ StaticLibrary true - MultiByte + Unicode StaticLibrary true - MultiByte + Unicode StaticLibrary false false - MultiByte + Unicode StaticLibrary false false - MultiByte + Unicode @@ -323,6 +323,54 @@ + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + @@ -481,6 +529,18 @@ + + true + true + true + true + + + true + true + true + true + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 7bce77a33f..9cbfcc44f9 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -52,6 +52,9 @@ {1c79e88d-1c48-450b-8af6-f22ce7d40c66} + + {ac0e396a-6e16-4796-a0a0-b8ebf46ea74c} + @@ -460,6 +463,30 @@ Ext + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + + + MIPS\PPC + @@ -858,6 +885,12 @@ Ext + + MIPS\PPC + + + MIPS\PPC + diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 8b5cd9810d..369bf7b1a5 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -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(); } diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index 54558cdfa4..fc9e9f63bc 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -21,13 +21,17 @@ #include "DebugInterface.h" #include -// 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; diff --git a/Core/Debugger/DebugInterface.h b/Core/Debugger/DebugInterface.h index 7c62443339..7a000d4df9 100644 --- a/Core/Debugger/DebugInterface.h +++ b/Core/Debugger/DebugInterface.h @@ -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; }; diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index b3fa7a9145..adb559bad8 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -23,13 +23,13 @@ #endif #include - -#include "../../Globals.h" -#include "../../Core/MemMap.h" -#include "SymbolMap.h" - #include +#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= 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; diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index ba0b823bd4..7c0e045245 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -160,6 +160,32 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer 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) diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 54ceacdb4f..a2ae2faaa4 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -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); diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp index 1b233a67ad..52672c5dc6 100644 --- a/Core/ELF/PBPReader.cpp +++ b/Core/ELF/PBPReader.cpp @@ -20,10 +20,11 @@ #include #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; } diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 052644d3ee..c2fbfb81ff 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -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 #include @@ -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]; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index a770fabc4c..d156040010 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -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 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 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); diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index 1ab6868696..00de123ac2 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -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); diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp index 54e48f6ced..2131ec4872 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.cpp +++ b/Core/FileSystems/VirtualDiscFileSystem.cpp @@ -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 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 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 diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 86bbcbdb17..897e8f6edc 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -58,8 +58,6 @@ typedef std::vector SyscallVector; typedef std::map SyscallVectorByModule; static std::vector 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(); } diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 1d29280c5c..3e22d2e2a3 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -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); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 51c80b111c..0c6c7ec652 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -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(); diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index e6cbd30480..4638b350f8 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -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) { diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 1fc3c4cd6e..7c8a44ec6c 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -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); diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index 74877c616c..e162ebc314 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -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) { diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 99073cb919..d01dfd3a31 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -16,15 +16,16 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#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; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 922ba5874a..c0271c13bd 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -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"}, {0x289D82FE,WrapU_UIII, "sceDisplaySetFrameBuf"}, {0xEEDA2E54,WrapU_UUUI,"sceDisplayGetFrameBuf"}, - {0x36CDFADE,WrapU_V, "sceDisplayWaitVblank"}, - {0x984C27E7,WrapU_V, "sceDisplayWaitVblankStart"}, + {0x36CDFADE,WrapU_V, "sceDisplayWaitVblank", HLE_NOT_DISPATCH_SUSPENDED}, + {0x984C27E7,WrapU_V, "sceDisplayWaitVblankStart", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0x40f1469c,WrapU_I, "sceDisplayWaitVblankStartMulti"}, - {0x8EB9EC49,WrapU_V, "sceDisplayWaitVblankCB"}, - {0x46F186C3,WrapU_V, "sceDisplayWaitVblankStartCB"}, + {0x8EB9EC49,WrapU_V, "sceDisplayWaitVblankCB", HLE_NOT_DISPATCH_SUSPENDED}, + {0x46F186C3,WrapU_V, "sceDisplayWaitVblankStartCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0x77ed8b3a,WrapU_I,"sceDisplayWaitVblankStartMultiCB"}, {0xdba6c4c4,WrapF_V,"sceDisplayGetFramePerSec"}, {0x773dd3a3,WrapU_V,"sceDisplayGetCurrentHcount"}, diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index fd59923dcc..a22cbab840 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -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) { diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index a3a17ea85f..2fa19ffbb6 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -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" }, { 0x42EC03AC, &WrapU_IUI, "sceIoWrite" }, //(int fd, void *data, int size); { 0x0facab19, &WrapU_IUI, "sceIoWriteAsync" }, - { 0x35dbd746, &WrapI_IU, "sceIoWaitAsyncCB", HLE_NOT_DISPATCH_SUSPENDED }, - { 0xe23eec33, &WrapI_IU, "sceIoWaitAsync", HLE_NOT_DISPATCH_SUSPENDED }, + { 0x35dbd746, &WrapI_IU, "sceIoWaitAsyncCB" }, + { 0xe23eec33, &WrapI_IU, "sceIoWaitAsync" }, { 0x5C2BE2CC, &WrapU_UIU, "sceIoGetFdList"}, }; diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 3cb9784c3f..131ee1b173 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -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"}, {0x812346E4,&WrapU_IU, "sceKernelClearEventFlag"}, {0xEF9E4C70,&WrapU_I, "sceKernelDeleteEventFlag"}, {0x1fb15a32,&WrapU_IU, "sceKernelSetEventFlag"}, - {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag"}, - {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB"}, + {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag", HLE_NOT_IN_INTERRUPT}, + {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB", HLE_NOT_IN_INTERRUPT}, {0x30FD48F0,&WrapI_IUUU, "sceKernelPollEventFlag"}, {0xCD203292,&WrapU_IUU, "sceKernelCancelEventFlag"}, {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, @@ -654,8 +672,8 @@ const HLEFunction ThreadManForUser[] = {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema", HLE_NOT_DISPATCH_SUSPENDED}, - {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB", HLE_NOT_DISPATCH_SUSPENDED}, + {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, @@ -667,14 +685,14 @@ const HLEFunction ThreadManForUser[] = //{0x31327F19,0, "_sceKernelLockLwMutexCB"}, //{0xBEED3A47,0, "_sceKernelUnlockLwMutex"}, - {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, - {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex", HLE_NOT_DISPATCH_SUSPENDED}, - {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB", HLE_NOT_DISPATCH_SUSPENDED}, - {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, - {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, - {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, - {0xA9C2CB9A,&WrapI_IU, "sceKernelReferMutexStatus"}, - {0x87D9223C,0, "sceKernelCancelMutex"}, + {0xf8170fbe,WrapI_I, "sceKernelDeleteMutex"}, + {0xB011B11F,WrapI_IIU, "sceKernelLockMutex", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x5bf4dd27,WrapI_IIU, "sceKernelLockMutexCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x6b30100f,WrapI_II, "sceKernelUnlockMutex"}, + {0xb7d098c6,WrapI_CUIU, "sceKernelCreateMutex"}, + {0x0DDCD2C9,WrapI_II, "sceKernelTryLockMutex"}, + {0xA9C2CB9A,WrapI_IU, "sceKernelReferMutexStatus"}, + {0x87D9223C,WrapI_IIU, "sceKernelCancelMutex"}, {0xFCCFAD26,WrapI_I,"sceKernelCancelWakeupThread"}, {0x1AF94D03,0,"sceKernelDonateWakeupThread"}, @@ -682,10 +700,10 @@ const HLEFunction ThreadManForUser[] = {0x71bc9871,WrapI_II,"sceKernelChangeThreadPriority"}, {0x446D8DE6,WrapI_CUUIUU,"sceKernelCreateThread"}, {0x9fa03cd3,WrapI_I,"sceKernelDeleteThread"}, - {0xBD123D9E,sceKernelDelaySysClockThread,"sceKernelDelaySysClockThread"}, - {0x1181E963,sceKernelDelaySysClockThreadCB,"sceKernelDelaySysClockThreadCB"}, - {0xceadeb47,WrapI_U,"sceKernelDelayThread"}, - {0x68da9e36,WrapI_U,"sceKernelDelayThreadCB"}, + {0xBD123D9E,WrapI_U, "sceKernelDelaySysClockThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x1181E963,WrapI_U, "sceKernelDelaySysClockThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xceadeb47,WrapI_U, "sceKernelDelayThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x68da9e36,WrapI_U, "sceKernelDelayThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0xaa73c935,WrapV_I,"sceKernelExitThread"}, {0x809ce29b,WrapV_I,"sceKernelExitDeleteThread"}, {0x94aa61ee,sceKernelGetThreadCurrentPriority,"sceKernelGetThreadCurrentPriority"}, @@ -696,11 +714,11 @@ const HLEFunction ThreadManForUser[] = {0x17c1684e,WrapU_UU,"sceKernelReferThreadStatus"}, {0x2C34E053,WrapI_I,"sceKernelReleaseWaitThread"}, {0x75156e8f,WrapI_I,"sceKernelResumeThread"}, - {0x3ad58b8c,&WrapU_V,"sceKernelSuspendDispatchThread"}, - {0x27e22ec2,&WrapU_U,"sceKernelResumeDispatchThread"}, + {0x3ad58b8c,&WrapU_V, "sceKernelSuspendDispatchThread", HLE_NOT_IN_INTERRUPT}, + {0x27e22ec2,&WrapU_U, "sceKernelResumeDispatchThread", HLE_NOT_IN_INTERRUPT}, {0x912354a7,&WrapI_I,"sceKernelRotateThreadReadyQueue"}, - {0x9ACE131E,WrapI_V,"sceKernelSleepThread"}, - {0x82826f70,WrapI_V,"sceKernelSleepThreadCB"}, + {0x9ACE131E,WrapI_V, "sceKernelSleepThread", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x82826f70,WrapI_V, "sceKernelSleepThreadCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0xF475845D,&WrapI_IIU,"sceKernelStartThread"}, {0x9944f31f,WrapI_I,"sceKernelSuspendThread"}, {0x616403ba,WrapI_I,"sceKernelTerminateThread"}, @@ -740,51 +758,51 @@ const HLEFunction ThreadManForUser[] = {0x72F3C145,0,"sceKernelReleaseThreadEventHandler"}, {0x369EEB6B,0,"sceKernelReferThreadEventHandlerStatus"}, - {0x349d6d6c,sceKernelCheckCallback, "sceKernelCheckCallback"}, - {0xE81CAF8F,WrapI_CUU, "sceKernelCreateCallback"}, - {0xEDBA5844,WrapI_I, "sceKernelDeleteCallback"}, - {0xC11BA8C4,WrapI_II, "sceKernelNotifyCallback"}, - {0xBA4051D6,WrapI_I, "sceKernelCancelCallback"}, - {0x2A3D44FF,WrapI_I, "sceKernelGetCallbackCount"}, - {0x730ED8BC,WrapI_IU, "sceKernelReferCallbackStatus"}, + {0x349d6d6c,sceKernelCheckCallback, "sceKernelCheckCallback"}, + {0xE81CAF8F,WrapI_CUU, "sceKernelCreateCallback"}, + {0xEDBA5844,WrapI_I, "sceKernelDeleteCallback"}, + {0xC11BA8C4,WrapI_II, "sceKernelNotifyCallback"}, + {0xBA4051D6,WrapI_I, "sceKernelCancelCallback"}, + {0x2A3D44FF,WrapI_I, "sceKernelGetCallbackCount"}, + {0x730ED8BC,WrapI_IU, "sceKernelReferCallbackStatus"}, - {0x8125221D,WrapI_CUU, "sceKernelCreateMbx"}, - {0x86255ADA,WrapI_I, "sceKernelDeleteMbx"}, - {0xE9B3061E,WrapI_IU, "sceKernelSendMbx"}, - {0x18260574,WrapI_IUU, "sceKernelReceiveMbx"}, - {0xF3986382,WrapI_IUU, "sceKernelReceiveMbxCB"}, - {0x0D81716A,WrapI_IU, "sceKernelPollMbx"}, - {0x87D4DD36,WrapI_IU, "sceKernelCancelReceiveMbx"}, - {0xA8E8C846,WrapI_IU, "sceKernelReferMbxStatus"}, + {0x8125221D,WrapI_CUU, "sceKernelCreateMbx"}, + {0x86255ADA,WrapI_I, "sceKernelDeleteMbx"}, + {0xE9B3061E,WrapI_IU, "sceKernelSendMbx"}, + {0x18260574,WrapI_IUU, "sceKernelReceiveMbx", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xF3986382,WrapI_IUU, "sceKernelReceiveMbxCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x0D81716A,WrapI_IU, "sceKernelPollMbx"}, + {0x87D4DD36,WrapI_IU, "sceKernelCancelReceiveMbx"}, + {0xA8E8C846,WrapI_IU, "sceKernelReferMbxStatus"}, - {0x7C0DC2A0,WrapI_CIUUU, "sceKernelCreateMsgPipe"}, - {0xF0B7DA1C,WrapI_I, "sceKernelDeleteMsgPipe"}, - {0x876DBFAD,WrapI_IUUUUU, "sceKernelSendMsgPipe"}, - {0x7C41F2C2,WrapI_IUUUUU, "sceKernelSendMsgPipeCB"}, - {0x884C9F90,WrapI_IUUUU, "sceKernelTrySendMsgPipe"}, - {0x74829B76,WrapI_IUUUUU, "sceKernelReceiveMsgPipe"}, - {0xFBFA697D,WrapI_IUUUUU, "sceKernelReceiveMsgPipeCB"}, - {0xDF52098F,WrapI_IUUUU, "sceKernelTryReceiveMsgPipe"}, - {0x349B864D,WrapI_IUU, "sceKernelCancelMsgPipe"}, - {0x33BE4024,WrapI_IU, "sceKernelReferMsgPipeStatus"}, + {0x7C0DC2A0,WrapI_CIUUU, "sceKernelCreateMsgPipe"}, + {0xF0B7DA1C,WrapI_I, "sceKernelDeleteMsgPipe"}, + {0x876DBFAD,WrapI_IUUUUU, "sceKernelSendMsgPipe"}, + {0x7C41F2C2,WrapI_IUUUUU, "sceKernelSendMsgPipeCB"}, + {0x884C9F90,WrapI_IUUUU, "sceKernelTrySendMsgPipe"}, + {0x74829B76,WrapI_IUUUUU, "sceKernelReceiveMsgPipe"}, + {0xFBFA697D,WrapI_IUUUUU, "sceKernelReceiveMsgPipeCB"}, + {0xDF52098F,WrapI_IUUUU, "sceKernelTryReceiveMsgPipe"}, + {0x349B864D,WrapI_IUU, "sceKernelCancelMsgPipe"}, + {0x33BE4024,WrapI_IU, "sceKernelReferMsgPipeStatus"}, - {0x56C039B5,WrapI_CIUUU,"sceKernelCreateVpl"}, - {0x89B3D48C,WrapI_I,"sceKernelDeleteVpl"}, - {0xBED27435,WrapI_IUUU,"sceKernelAllocateVpl"}, - {0xEC0A693F,WrapI_IUUU,"sceKernelAllocateVplCB"}, - {0xAF36D708,WrapI_IUU,"sceKernelTryAllocateVpl"}, - {0xB736E9FF,WrapI_IU,"sceKernelFreeVpl"}, - {0x1D371B8A,WrapI_IU,"sceKernelCancelVpl"}, - {0x39810265,WrapI_IU,"sceKernelReferVplStatus"}, + {0x56C039B5,WrapI_CIUUU, "sceKernelCreateVpl"}, + {0x89B3D48C,WrapI_I, "sceKernelDeleteVpl"}, + {0xBED27435,WrapI_IUUU, "sceKernelAllocateVpl", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xEC0A693F,WrapI_IUUU, "sceKernelAllocateVplCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xAF36D708,WrapI_IUU, "sceKernelTryAllocateVpl"}, + {0xB736E9FF,WrapI_IU, "sceKernelFreeVpl"}, + {0x1D371B8A,WrapI_IU, "sceKernelCancelVpl"}, + {0x39810265,WrapI_IU, "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"}, + {0xED1410E0,WrapI_I, "sceKernelDeleteFpl"}, + {0xD979E9BF,WrapI_IUU, "sceKernelAllocateFpl", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xE7282CB6,WrapI_IUU, "sceKernelAllocateFplCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x623AE665,WrapI_IU, "sceKernelTryAllocateFpl"}, + {0xF6414A71,WrapI_IU, "sceKernelFreeFpl"}, + {0xA8AA591F,WrapI_IU, "sceKernelCancelFpl"}, + {0xD8199E4C,WrapI_IU, "sceKernelReferFplStatus"}, {0x20fff560,WrapU_CU,"sceKernelCreateVTimer"}, {0x328F9E52,WrapU_U,"sceKernelDeleteVTimer"}, @@ -820,6 +838,13 @@ const HLEFunction ThreadManForUser[] = // {0x6E9EA350, _sceKernelReturnFromCallback,"_sceKernelReturnFromCallback"}, }; +const HLEFunction ThreadManForKernel[] = +{ + {0xceadeb47, WrapI_U, "ThreadManForKernel_ceadeb47"}, + {0x446d8de6, WrapI_CUUIUU, "ThreadManForKernel_446d8de6"},//Not sure right + {0xf475845d, &WrapI_IIU, "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); + +} \ No newline at end of file diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index d47b71d6dc..fe8f3dbe32 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -557,5 +557,6 @@ extern KernelStats kernelStats; extern u32 registeredExitCbId; void Register_ThreadManForUser(); +void Register_ThreadManForKernel(); void Register_LoadExecForUser(); void Register_UtilsForKernel(); diff --git a/Core/HLE/sceKernelEventFlag.cpp b/Core/HLE/sceKernelEventFlag.cpp index fc36df8f95..a281879d9a 100644 --- a/Core/HLE/sceKernelEventFlag.cpp +++ b/Core/HLE/sceKernelEventFlag.cpp @@ -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; } } diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index a85c0f3375..e9af59d11f 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -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"}, {0xDC692EE3,WrapI_UI, "sceKernelTryLockLwMutex"}, {0x37431849,WrapI_UI, "sceKernelTryLockLwMutex_600"}, - {0xbea46419,WrapI_UIU, "sceKernelLockLwMutex", HLE_NOT_DISPATCH_SUSPENDED}, - {0x1FC64E09,WrapI_UIU, "sceKernelLockLwMutexCB", HLE_NOT_DISPATCH_SUSPENDED}, + {0xbea46419,WrapI_UIU, "sceKernelLockLwMutex", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0x1FC64E09,WrapI_UIU, "sceKernelLockLwMutexCB", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0x15b6446b,WrapI_UI, "sceKernelUnlockLwMutex"}, {0xc1734599,WrapI_UU, "sceKernelReferLwMutexStatus"}, {0x293b45b8,WrapI_V, "sceKernelGetThreadId"}, diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 6321420931..86bc38fe7c 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -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); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index e1a6571ca6..195e18de95 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -17,16 +17,17 @@ #include #include -#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 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(id, error); + FPL *fpl = kernelObjects.Get(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(id)); + return kernelObjects.Destroy(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(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(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(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(id, error); + FPL *fpl = kernelObjects.Get(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(id, error); + FPL *fpl = kernelObjects.Get(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(id, error); + FPL *fpl = kernelObjects.Get(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(id, error); + FPL *fpl = kernelObjects.Get(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(id, error); + FPL *fpl = kernelObjects.Get(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(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(uid, error); if (tls) diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h index b2524ecee6..d9ab052f46 100644 --- a/Core/HLE/sceKernelMemory.h +++ b/Core/HLE/sceKernelMemory.h @@ -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(); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 1816d66ad5..0d272a36cc 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -17,33 +17,34 @@ #include #include +#include #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 + void RebuildImpExpList(const std::vector &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 waitingThreads; + std::vector exportedFuncs; + std::vector importedFuncs; + std::vector exportedVars; + std::vector importedVars; + std::set impExpModuleNames; + u32 memoryBlockAddr; u32 memoryBlockSize; bool isFake; @@ -263,8 +374,7 @@ struct SceKernelSMOption { // STATE BEGIN static int actionAfterModule; -static std::vector unresolvedVars; -static std::vector exportedVars; +static std::set 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 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(*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(*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(*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(*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(*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(*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->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->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->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(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"}, {0xb7f46618,&WrapU_UUU,"sceKernelLoadModuleByID"}, - {0x50F0C1EC,&WrapV_UUUUU,"sceKernelStartModule"}, + {0x50F0C1EC,&WrapV_UUUUU,"sceKernelStartModule", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0xD675EBB8,&sceKernelExitGame,"sceKernelSelfStopUnloadModule"}, //HACK - {0xd1ff982a,&WrapU_UUUUU,"sceKernelStopModule"}, + {0xd1ff982a,&WrapU_UUUUU,"sceKernelStopModule", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, {0x2e0911aa,WrapU_U,"sceKernelUnloadModule"}, {0x710F61B5,0,"sceKernelLoadModuleMs"}, {0xF9275D98,0,"sceKernelLoadModuleBufferUsbWlan"}, ///??? @@ -1519,7 +1797,20 @@ const HLEFunction ModuleMgrForUser[] = }; +const HLEFunction ModuleMgrForKernel[] = +{ + {0x50f0c1ec,&WrapV_UUUUU, "ModuleMgrForKernel_50f0c1ec"},//Not sure right + {0x977de386, &WrapU_CUU, "ModuleMgrForKernel_977de386"},//Not sure right + {0xa1a78c58, &WrapU_CUU, "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); + +}; diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index f6288fb278..caa74f8413 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -29,3 +29,4 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str void __KernelReturnFromModuleFunc(); void Register_ModuleMgrForUser(); +void Register_ModuleMgrForKernel(); \ No newline at end of file diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index b07e17f6f8..36434606e3 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -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 &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(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(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(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(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(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(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(uid, error); if (!m) { ERROR_LOG(HLE, "sceKernelTryReceiveMsgPipe(%i) - ERROR %08x", uid, error); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 7e901017e2..1b1ebcb6d9 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -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(id, error); if (mutex) { + DEBUG_LOG(HLE, "sceKernelDeleteMutex(%i)", id); bool wokeThreads = false; std::vector::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(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(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) { diff --git a/Core/HLE/sceKernelMutex.h b/Core/HLE/sceKernelMutex.h index 9e7bf57973..69e63e0709 100644 --- a/Core/HLE/sceKernelMutex.h +++ b/Core/HLE/sceKernelMutex.h @@ -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); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index a107e4fc42..d085acca3a 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -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; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index b438d9a5b8..4ec222173d 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -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 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 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(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(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) { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 147677ce1e..aece5716d7 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -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 }; diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index c9f1457f69..e89463bf69 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -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"}, - {0x89360950, WrapI_CU, "sceNetEtherNtostr"}, - {0x0bf0a3ae, 0, "sceNetGetLocalEtherAddr"}, - {0xd27961c9, 0, "sceNetEtherStrton"}, - {0x50647530, 0, "sceNetFreeThreadinfo"}, + {0x89360950, WrapI_UU, "sceNetEtherNtostr"}, + {0xd27961c9, WrapI_UU, "sceNetEtherStrton"}, + {0x0bf0a3ae, 0, "sceNetGetLocalEtherAddr"}, + {0x50647530, 0, "sceNetFreeThreadinfo"}, {0xcc393e48, WrapI_U, "sceNetGetMallocStat"}, {0xad6844c6, 0, "sceNetThreadAbort"}, }; diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index caa3692cba..c619574b23 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -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 +#include #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 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,"scePowerUnregitserCallback"}, {0x843FBF43,WrapU_U,"scePowerSetCpuClockFrequency"}, {0xB8D7B3FB,WrapU_U,"scePowerSetBusClockFrequency"}, - {0xFEE03A2F,WrapU_V,"scePowerGetCpuClockFrequency"}, - {0x478FE6F5,WrapU_V,"scePowerGetBusClockFrequency"}, + {0xFEE03A2F,WrapU_V,"scePowerGetCpuClockFrequency"}, + {0x478FE6F5,WrapU_V,"scePowerGetBusClockFrequency"}, {0xFDB5BFE9,WrapU_V,"scePowerGetCpuClockFrequencyInt"}, {0xBD681969,WrapU_V,"scePowerGetBusClockFrequencyInt"}, {0xB1A52C83,WrapF_V,"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,"scePowerVolatileMemLock", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, + {0xfa97a599,&WrapI_IUU,"scePowerVolatileMemTryLock"}, + {0xb3edd801,&WrapI_I,"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"}, + {0xa14f40b2,&WrapI_IUU,"sceKernelVolatileMemTryLock"}, {0xa569e425,&WrapI_I,"sceKernelVolatileMemUnlock"}, - {0x3e0271d3,&WrapI_III,"sceKernelVolatileMemLock"}, //when "acquiring mem pool" (fired up) + {0x3e0271d3,&WrapI_IUU,"sceKernelVolatileMemLock", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED}, //when "acquiring mem pool" (fired up) }; diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index d4833be54b..61487737aa 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -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; diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index e9a0913078..a954d57327 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -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? diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 7db6eac04f..05a613e629 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -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"}, @@ -564,10 +649,10 @@ const HLEFunction sceUtility[] = {0xA5DA2406, &WrapU_UU, "sceUtilityGetSystemParamInt"}, - {0xc492f751, 0, "sceUtilityGameSharingInitStart"}, - {0xefc6f80f, 0, "sceUtilityGameSharingShutdownStart"}, - {0x7853182d, 0, "sceUtilityGameSharingUpdate"}, - {0x946963f3, 0, "sceUtilityGameSharingGetStatus"}, + {0xc492f751, &WrapI_U, "sceUtilityGameSharingInitStart"}, + {0xefc6f80f, &WrapI_V, "sceUtilityGameSharingShutdownStart"}, + {0x7853182d, &WrapI_I, "sceUtilityGameSharingUpdate"}, + {0x946963f3, &WrapI_V, "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"}, diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 9fe36d2e41..0570d84a9f 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -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++) { diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index 2f03387d8b..968da5ad10 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -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) { diff --git a/Core/Host.h b/Core/Host.h index ca327aeff8..f13f378a5a 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -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. diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index f573b53dcb..b85789fa58 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -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: diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 7d7bd78084..5e94c93235 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -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) diff --git a/Core/MIPS/ARM/ArmCompBranch.cpp b/Core/MIPS/ARM/ArmCompBranch.cpp index 69e6252283..8f446f22ce 100644 --- a/Core/MIPS/ARM/ArmCompBranch.cpp +++ b/Core/MIPS/ARM/ArmCompBranch.cpp @@ -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(); diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 0fc048e2b9..cf211cb1d6 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -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) { diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index 7855d1408a..7d6bc2ea1f 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -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; } diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 27e7c419ae..f92fb4cfea 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -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; diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 9ff285102a..42e2da00c1 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -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) diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 73bca7f25a..2379dd9254 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -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 diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index e51b93861c..29f12d24cb 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -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 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, 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); diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index f37fd3bdd7..c7bd5288f0 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -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 *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_; diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index 4114a08a0c..8569132bcb 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -44,5 +44,4 @@ namespace MIPSComp { extern Jit *jit; -extern const float cst_constants[32]; } diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index f20a76219a..0e39e686ba 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -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::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() diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 5ac5a7c99f..07eebbca10 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -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]; diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 63e8300b2e..c6d5dff6c4 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -16,186 +16,135 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#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 GetInputRegs(u32 op) + std::vector GetInputRegs(MIPSOpcode op) { - std::vector vec; - u32 info = MIPSGetInfo(op); + std::vector 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 GetOutputRegs(u32 op) + std::vector GetOutputRegs(MIPSOpcode op) { - std::vector vec; - u32 info = MIPSGetInfo(op); + std::vector 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; } diff --git a/Core/MIPS/MIPSAnalyst.h b/Core/MIPS/MIPSAnalyst.h index 7167e8287a..d68a30bc21 100644 --- a/Core/MIPS/MIPSAnalyst.h +++ b/Core/MIPS/MIPSAnalyst.h @@ -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 GetInputRegs(u32 op); - std::vector GetOutputRegs(u32 op); + std::vector GetInputRegs(MIPSOpcode op); + std::vector 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; diff --git a/Core/MIPS/MIPSAsm.cpp b/Core/MIPS/MIPSAsm.cpp index 595e01ea0b..45b6ab78d8 100644 --- a/Core/MIPS/MIPSAsm.cpp +++ b/Core/MIPS/MIPSAsm.cpp @@ -2,10 +2,27 @@ #include "stdafx.h" #endif #include "MIPSAsm.h" +#include 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; diff --git a/Core/MIPS/MIPSAsm.h b/Core/MIPS/MIPSAsm.h index 9c851c06b4..90a945031e 100644 --- a/Core/MIPS/MIPSAsm.h +++ b/Core/MIPS/MIPSAsm.h @@ -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(); + } \ No newline at end of file diff --git a/Core/MIPS/MIPSAsmTables.h b/Core/MIPS/MIPSAsmTables.h index 0f37ff6d9d..bf44def7a1 100644 --- a/Core/MIPS/MIPSAsmTables.h +++ b/Core/MIPS/MIPSAsmTables.h @@ -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; diff --git a/Core/MIPS/MIPSCodeUtils.cpp b/Core/MIPS/MIPSCodeUtils.cpp index 43a112a166..49a42e4fa4 100644 --- a/Core/MIPS/MIPSCodeUtils.cpp +++ b/Core/MIPS/MIPSCodeUtils.cpp @@ -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); } } diff --git a/Core/MIPS/MIPSCodeUtils.h b/Core/MIPS/MIPSCodeUtils.h index 018b9f0071..e356f3bf75 100644 --- a/Core/MIPS/MIPSCodeUtils.h +++ b/Core/MIPS/MIPSCodeUtils.h @@ -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); } diff --git a/Core/MIPS/MIPSDebugInterface.cpp b/Core/MIPS/MIPSDebugInterface.cpp index 0524565388..ea55ab2ced 100644 --- a/Core/MIPS/MIPSDebugInterface.cpp +++ b/Core/MIPS/MIPSDebugInterface.cpp @@ -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); diff --git a/Core/MIPS/MIPSDebugInterface.h b/Core/MIPS/MIPSDebugInterface.h index 4168d66edc..26ee3e9d6f 100644 --- a/Core/MIPS/MIPSDebugInterface.h +++ b/Core/MIPS/MIPSDebugInterface.h @@ -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 diff --git a/Core/MIPS/MIPSDis.cpp b/Core/MIPS/MIPSDis.cpp index 7aa2953b7b..fb7844faba 100644 --- a/Core/MIPS/MIPSDis.cpp +++ b/Core/MIPS/MIPSDis.cpp @@ -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); diff --git a/Core/MIPS/MIPSDis.h b/Core/MIPS/MIPSDis.h index e07351eec6..5a706f5919 100644 --- a/Core/MIPS/MIPSDis.h +++ b/Core/MIPS/MIPSDis.h @@ -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); } diff --git a/Core/MIPS/MIPSDisVFPU.cpp b/Core/MIPS/MIPSDisVFPU.cpp index 0d76e0d644..e76f7a49e6 100644 --- a/Core/MIPS/MIPSDisVFPU.cpp +++ b/Core/MIPS/MIPSDisVFPU.cpp @@ -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; diff --git a/Core/MIPS/MIPSDisVFPU.h b/Core/MIPS/MIPSDisVFPU.h index ebc21aa07f..dbb1aef3f0 100644 --- a/Core/MIPS/MIPSDisVFPU.h +++ b/Core/MIPS/MIPSDisVFPU.h @@ -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); } diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 47d22a5130..6483829456 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -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"); } diff --git a/Core/MIPS/MIPSInt.h b/Core/MIPS/MIPSInt.h index 7f7ad7d1c1..a685ab6a3e 100644 --- a/Core/MIPS/MIPSInt.h +++ b/Core/MIPS/MIPSInt.h @@ -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); } diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 0dccfd70b8..b91a5d582a 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -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"); diff --git a/Core/MIPS/MIPSIntVFPU.h b/Core/MIPS/MIPSIntVFPU.h index 8e45efc55b..c2899955ab 100644 --- a/Core/MIPS/MIPSIntVFPU.h +++ b/Core/MIPS/MIPSIntVFPU.h @@ -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); } \ No newline at end of file diff --git a/Core/MIPS/MIPSStackWalk.cpp b/Core/MIPS/MIPSStackWalk.cpp index d4a9ffcb4c..f520461e37 100644 --- a/Core/MIPS/MIPSStackWalk.cpp +++ b/Core/MIPS/MIPSStackWalk.cpp @@ -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) { diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 2c11791803..bd4c893059 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -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 diff --git a/Core/MIPS/MIPSTables.h b/Core/MIPS/MIPSTables.h index 439e9c9fc2..ed0fb24404 100644 --- a/Core/MIPS/MIPSTables.h +++ b/Core/MIPS/MIPSTables.h @@ -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(); diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index a192af8c95..b89e988e6d 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -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; diff --git a/Core/MIPS/MIPSVFPUUtils.h b/Core/MIPS/MIPSVFPUUtils.h index d44d2fdf20..68e4a75153 100644 --- a/Core/MIPS/MIPSVFPUUtils.h +++ b/Core/MIPS/MIPSVFPUUtils.h @@ -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); diff --git a/Core/MIPS/PPC/PpcJit.cpp b/Core/MIPS/PPC/PpcJit.cpp index 46b0c6c025..31b5c32804 100644 --- a/Core/MIPS/PPC/PpcJit.cpp +++ b/Core/MIPS/PPC/PpcJit.cpp @@ -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) diff --git a/Core/MIPS/PPC/PpcJit.h b/Core/MIPS/PPC/PpcJit.h index 3aa087e694..1eef944a82 100644 --- a/Core/MIPS/PPC/PpcJit.h +++ b/Core/MIPS/PPC/PpcJit.h @@ -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(); diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index 6553b3c8b3..d0e9e0ed9c 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -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 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) { diff --git a/Core/MIPS/x86/CompBranch.cpp b/Core/MIPS/x86/CompBranch.cpp index f03a4920ee..6d85407999 100644 --- a/Core/MIPS/x86/CompBranch.cpp +++ b/Core/MIPS/x86/CompBranch.cpp @@ -30,15 +30,16 @@ #include "Core/MIPS/x86/RegCache.h" #include "Core/MIPS/JitCommon/JitBlockCache.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 @@ -72,13 +73,13 @@ namespace MIPSComp static u32 intBranchExit; static u32 jitBranchExit; -static void JitBranchLog(u32 op, u32 pc) +static void JitBranchLog(MIPSOpcode op, u32 pc) { currentMIPS->pc = pc; currentMIPS->inDelaySlot = false; MIPSInterpretFunc func = MIPSGetInterpretFunc(op); - u32 info = MIPSGetInfo(op); + MIPSInfo info = MIPSGetInfo(op); func(op); // Branch taken, use nextPC. @@ -98,7 +99,7 @@ static void JitBranchLog(u32 op, u32 pc) currentMIPS->inDelaySlot = false; } -static void JitBranchLogMismatch(u32 op, u32 pc) +static void JitBranchLogMismatch(MIPSOpcode op, u32 pc) { char temp[256]; MIPSDisAsm(op, pc, temp, true); @@ -106,13 +107,13 @@ static void JitBranchLogMismatch(u32 op, u32 pc) host->SetDebugMode(true); } -void Jit::BranchLog(u32 op) +void Jit::BranchLog(MIPSOpcode op) { FlushAll(); - ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLog, 2), op, js.compilerPC); + ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLog, 2), op.encoding, js.compilerPC); } -void Jit::BranchLogExit(u32 op, u32 dest, bool useEAX) +void Jit::BranchLogExit(MIPSOpcode op, u32 dest, bool useEAX) { OpArg destArg = useEAX ? R(EAX) : Imm32(dest); @@ -120,7 +121,7 @@ void Jit::BranchLogExit(u32 op, u32 dest, bool useEAX) FixupBranch skip = J_CC(CC_E); MOV(32, M((void *) &jitBranchExit), destArg); - ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLogMismatch, 2), op, js.compilerPC); + ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLogMismatch, 2), op.encoding, js.compilerPC); // Restore EAX, we probably ruined it. if (useEAX) MOV(32, R(EAX), M((void *) &jitBranchExit)); @@ -128,7 +129,7 @@ void Jit::BranchLogExit(u32 op, u32 dest, bool useEAX) SetJumpTarget(skip); } -void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) +void Jit::BranchRSRTComp(MIPSOpcode op, Gen::CCFlags cc, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -136,15 +137,15 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) 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::Read_Instruction(js.compilerPC+4); + MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC+4); bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rt, rs); CONDITIONAL_NICE_DELAYSLOT; - if (jo.immBranches && gpr.IsImmediate(rs) && gpr.IsImmediate(rt)) + if (jo.immBranches && gpr.IsImmediate(rs) && gpr.IsImmediate(rt) && js.numInstructions < jo.continueMaxInstructions) { // The cc flags are opposites: when NOT to take the branch. bool skipBranch; @@ -170,6 +171,8 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) CompileDelaySlot(DELAYSLOT_NICE); // Account for the increment in the loop. js.compilerPC = targetAddr - 4; + // In case the delay slot was a break or something. + js.compiling = true; return; } @@ -184,7 +187,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) else { gpr.BindToRegister(rs, true, false); - CMP(32, gpr.R(rs), rt == 0 ? Imm32(0) : gpr.R(rt)); + CMP(32, gpr.R(rs), rt == MIPS_REG_ZERO ? Imm32(0) : gpr.R(rt)); } Gen::FixupBranch ptr; @@ -216,6 +219,8 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) // Account for the delay slot. js.compilerPC += 4; RestoreState(state); + // In case the delay slot was a break or something. + js.compiling = true; } else { @@ -224,7 +229,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely) } } -void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely) +void Jit::BranchRSZeroComp(MIPSOpcode op, Gen::CCFlags cc, bool andLink, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -232,14 +237,14 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely) return; } int offset = _IMM16 << 2; - int rs = _RS; + MIPSGPReg rs = _RS; u32 targetAddr = js.compilerPC + offset + 4; - u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs); CONDITIONAL_NICE_DELAYSLOT; - if (jo.immBranches && gpr.IsImmediate(rs)) + if (jo.immBranches && gpr.IsImmediate(rs) && js.numInstructions < jo.continueMaxInstructions) { // The cc flags are opposites: when NOT to take the branch. bool skipBranch; @@ -271,6 +276,8 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely) } // Account for the increment in the loop. js.compilerPC = targetAddr - 4; + // In case the delay slot was a break or something. + js.compiling = true; return; } @@ -312,6 +319,8 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely) // Account for the delay slot. js.compilerPC += 4; RestoreState(state); + // In case the delay slot was a break or something. + js.compiling = true; } else { @@ -321,7 +330,7 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely) } -void Jit::Comp_RelBranch(u32 op) +void Jit::Comp_RelBranch(MIPSOpcode op) { switch (op>>26) { @@ -343,7 +352,7 @@ void Jit::Comp_RelBranch(u32 op) } } -void Jit::Comp_RelBranchRI(u32 op) +void Jit::Comp_RelBranchRI(MIPSOpcode op) { switch ((op >> 16) & 0x1F) { @@ -363,7 +372,7 @@ void Jit::Comp_RelBranchRI(u32 op) // If likely is set, discard the branch slot if NOT taken. -void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely) +void Jit::BranchFPFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -373,7 +382,7 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely) int offset = _IMM16 << 2; u32 targetAddr = js.compilerPC + offset + 4; - u32 delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); bool delaySlotIsNice = IsDelaySlotNiceFPU(op, delaySlotOp); CONDITIONAL_NICE_DELAYSLOT; if (!likely && delaySlotIsNice) @@ -410,6 +419,8 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely) // Account for the delay slot. js.compilerPC += 4; RestoreState(state); + // In case the delay slot was a break or something. + js.compiling = true; } else { @@ -419,7 +430,7 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely) } -void Jit::Comp_FPUBranch(u32 op) +void Jit::Comp_FPUBranch(MIPSOpcode op) { switch((op >> 16) & 0x1f) { @@ -434,7 +445,7 @@ void Jit::Comp_FPUBranch(u32 op) } // If likely is set, discard the branch slot if NOT taken. -void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely) +void Jit::BranchVFPUFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -444,7 +455,7 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely) int offset = _IMM16 << 2; u32 targetAddr = js.compilerPC + offset + 4; - u32 delaySlotOp = Memory::Read_Instruction(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. @@ -494,6 +505,8 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely) // Account for the delay slot. js.compilerPC += 4; RestoreState(state); + // In case the delay slot was a break or something. + js.compiling = true; } else { @@ -503,7 +516,7 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely) } -void Jit::Comp_VBranch(u32 op) +void Jit::Comp_VBranch(MIPSOpcode op) { switch ((op >> 16) & 3) { @@ -517,7 +530,7 @@ void Jit::Comp_VBranch(u32 op) } } -void Jit::Comp_Jump(u32 op) +void Jit::Comp_Jump(MIPSOpcode op) { CONDITIONAL_LOG; if (js.inDelaySlot) { @@ -554,16 +567,16 @@ void Jit::Comp_Jump(u32 op) static u32 savedPC; -void Jit::Comp_JumpReg(u32 op) +void Jit::Comp_JumpReg(MIPSOpcode op) { CONDITIONAL_LOG; 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::Read_Instruction(js.compilerPC + 4); + MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs); CONDITIONAL_NICE_DELAYSLOT; @@ -611,7 +624,7 @@ void Jit::Comp_JumpReg(u32 op) js.compiling = false; } -void Jit::Comp_Syscall(u32 op) +void Jit::Comp_Syscall(MIPSOpcode op) { FlushAll(); @@ -624,13 +637,13 @@ void Jit::Comp_Syscall(u32 op) if (op == GetSyscallOp("FakeSysCalls", NID_IDLE)) ABI_CallFunction((void *)GetFunc("FakeSysCalls", NID_IDLE)->func); else - ABI_CallFunctionC((void *)&CallSyscall, op); + ABI_CallFunctionC((void *)&CallSyscall, op.encoding); WriteSyscallExit(); js.compiling = false; } -void Jit::Comp_Break(u32 op) +void Jit::Comp_Break(MIPSOpcode op) { Comp_Generic(op); WriteSyscallExit(); diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 336c864565..39ce783d5b 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -15,21 +15,24 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "../MIPS.h" - -#include "../../Config.h" +#include "Core/Config.h" #include "Common/Common.h" -#include "Jit.h" -#include "RegCache.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSCodeUtils.h" +#include "Core/MIPS/x86/Jit.h" +#include "Core/MIPS/x86/RegCache.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. @@ -41,7 +44,7 @@ namespace MIPSComp { -void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters) +void Jit::CompFPTriArith(MIPSOpcode op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters) { int ft = _FT; int fs = _FS; @@ -72,7 +75,7 @@ void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), boo fpr.ReleaseSpillLocks(); } -void Jit::Comp_FPU3op(u32 op) +void Jit::Comp_FPU3op(MIPSOpcode op) { CONDITIONAL_DISABLE; switch (op & 0x3f) @@ -89,12 +92,12 @@ void Jit::Comp_FPU3op(u32 op) static u32 MEMORY_ALIGNED16(ssLoadStoreTemp); -void Jit::Comp_FPULS(u32 op) +void Jit::Comp_FPULS(MIPSOpcode op) { CONDITIONAL_DISABLE; - s32 offset = (s16)(op&0xFFFF); + s32 offset = _IMM16; int ft = _FT; - int rs = _RS; + MIPSGPReg rs = _RS; switch(op >> 26) { @@ -171,7 +174,7 @@ void Jit::CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN) } } -void Jit::Comp_FPUComp(u32 op) +void Jit::Comp_FPUComp(MIPSOpcode op) { CONDITIONAL_DISABLE; @@ -225,7 +228,7 @@ void Jit::Comp_FPUComp(u32 op) } } -void Jit::Comp_FPU2op(u32 op) { +void Jit::Comp_FPU2op(MIPSOpcode op) { CONDITIONAL_DISABLE; int fs = _FS; @@ -290,17 +293,17 @@ 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) { case 0: // R(rt) = FI(fs); break; //mfc1 - if (rt != 0) + if (rt != MIPS_REG_ZERO) { // Cross move! slightly tricky fpr.StoreFromRegister(fs); diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index 6469aebea4..204252f705 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -15,22 +15,25 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "../../MemMap.h" -#include "../MIPSAnalyst.h" -#include "../../Config.h" - -#include "Jit.h" -#include "RegCache.h" +#include "Core/MemMap.h" +#include "Core/MIPS/MIPSAnalyst.h" +#include "Core/Config.h" +#include "Core/MIPS/MIPSCodeUtils.h" +#include "Core/MIPS/x86/Jit.h" +#include "Core/MIPS/x86/RegCache.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. @@ -41,12 +44,12 @@ namespace MIPSComp { - void Jit::CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc) + void Jit::CompITypeMemRead(MIPSOpcode op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc) { CONDITIONAL_DISABLE; - int offset = (signed short)(op&0xFFFF); - int rt = _RT; - int rs = _RS; + int offset = _IMM16; + MIPSGPReg rt = _RT; + MIPSGPReg rs = _RS; gpr.Lock(rt, rs); gpr.BindToRegister(rt, rt == rs, true); @@ -62,12 +65,12 @@ namespace MIPSComp gpr.UnlockAll(); } - void Jit::CompITypeMemWrite(u32 op, u32 bits, void *safeFunc) + void Jit::CompITypeMemWrite(MIPSOpcode op, u32 bits, void *safeFunc) { CONDITIONAL_DISABLE; - int offset = (signed short)(op&0xFFFF); - int rt = _RT; - int rs = _RS; + int offset = _IMM16; + MIPSGPReg rt = _RT; + MIPSGPReg rs = _RS; gpr.Lock(rt, rs); gpr.BindToRegister(rt, true, false); @@ -102,13 +105,13 @@ namespace MIPSComp gpr.UnlockAll(); } - void Jit::CompITypeMemUnpairedLR(u32 op, bool isStore) + void Jit::CompITypeMemUnpairedLR(MIPSOpcode op, bool isStore) { CONDITIONAL_DISABLE; int o = op>>26; - int offset = (signed short)(op&0xFFFF); - int rt = _RT; - int rs = _RS; + int offset = _IMM16; + MIPSGPReg rt = _RT; + MIPSGPReg rs = _RS; X64Reg shiftReg = ECX; gpr.FlushLockX(ECX, EDX); @@ -159,11 +162,11 @@ namespace MIPSComp gpr.UnlockAllX(); } - void Jit::CompITypeMemUnpairedLRInner(u32 op, X64Reg shiftReg) + void Jit::CompITypeMemUnpairedLRInner(MIPSOpcode op, X64Reg shiftReg) { CONDITIONAL_DISABLE; int o = op>>26; - int rt = _RT; + MIPSGPReg rt = _RT; // Make sure we have the shift for the target in ECX. if (shiftReg != ECX) @@ -251,14 +254,14 @@ namespace MIPSComp } } - void Jit::Comp_ITypeMem(u32 op) + void Jit::Comp_ITypeMem(MIPSOpcode op) { CONDITIONAL_DISABLE; - int offset = (signed short)(op&0xFFFF); - int rt = _RT; - int rs = _RS; + int offset = _IMM16; + 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; } @@ -299,9 +302,9 @@ namespace MIPSComp case 34: //lwl { - u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4); // Looking for lwr rd, offset-3(rs) which makes a pair. - u32 desiredOp = ((op + (4 << 26)) & 0xFFFF0000) + (offset - 3); + u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3); if (!js.inDelaySlot && nextOp == desiredOp) { EatInstruction(nextOp); @@ -315,9 +318,9 @@ namespace MIPSComp case 38: //lwr { - u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4); // Looking for lwl rd, offset+3(rs) which makes a pair. - u32 desiredOp = ((op - (4 << 26)) & 0xFFFF0000) + (offset + 3); + u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3); if (!js.inDelaySlot && nextOp == desiredOp) { EatInstruction(nextOp); @@ -331,9 +334,9 @@ namespace MIPSComp case 42: //swl { - u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4); // Looking for swr rd, offset-3(rs) which makes a pair. - u32 desiredOp = ((op + (4 << 26)) & 0xFFFF0000) + (offset - 3); + u32 desiredOp = ((op & 0xFFFF0000) + (4 << 26)) + (offset - 3); if (!js.inDelaySlot && nextOp == desiredOp) { EatInstruction(nextOp); @@ -347,9 +350,9 @@ namespace MIPSComp case 46: //swr { - u32 nextOp = Memory::Read_Instruction(js.compilerPC + 4); + MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4); // Looking for swl rd, offset+3(rs) which makes a pair. - u32 desiredOp = ((op - (4 << 26)) & 0xFFFF0000) + (offset + 3); + u32 desiredOp = ((op & 0xFFFF0000) - (4 << 26)) + (offset + 3); if (!js.inDelaySlot && nextOp == desiredOp) { EatInstruction(nextOp); diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index dc598ddec4..e08a855d5a 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -24,10 +24,10 @@ #include "Core/Config.h" #include "Core/Reporting.h" #include "Core/MIPS/MIPSAnalyst.h" - +#include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPSVFPUUtils.h" -#include "Jit.h" -#include "RegCache.h" +#include "Core/MIPS/x86/Jit.h" +#include "Core/MIPS/x86/RegCache.h" // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. @@ -38,14 +38,17 @@ #define DISABLE { fpr.ReleaseSpillLocks(); 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) using namespace Gen; @@ -61,7 +64,7 @@ const u32 MEMORY_ALIGNED16( noSignMask[4] ) = {0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFF const u32 MEMORY_ALIGNED16( signBitLower[4] ) = {0x80000000, 0, 0, 0}; const float MEMORY_ALIGNED16( oneOneOneOne[4] ) = {1.0f, 1.0f, 1.0f, 1.0f}; -void Jit::Comp_VPFX(u32 op) +void Jit::Comp_VPFX(MIPSOpcode op) { CONDITIONAL_DISABLE; int data = op & 0xFFFFF; @@ -198,12 +201,12 @@ bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] static u32 MEMORY_ALIGNED16(ssLoadStoreTemp); -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; switch (op >> 26) { @@ -262,13 +265,13 @@ void Jit::Comp_SV(u32 op) { } } -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; switch (op >> 26) { @@ -412,7 +415,7 @@ void Jit::Comp_SVQ(u32 op) } } -void Jit::Comp_VVectorInit(u32 op) { +void Jit::Comp_VVectorInit(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -445,7 +448,7 @@ void Jit::Comp_VVectorInit(u32 op) { -void Jit::Comp_VIdt(u32 op) { +void Jit::Comp_VIdt(MIPSOpcode op) { CONDITIONAL_DISABLE; int vd = _VD; @@ -477,7 +480,7 @@ void Jit::Comp_VIdt(u32 op) { } -void Jit::Comp_VDot(u32 op) { +void Jit::Comp_VDot(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -521,7 +524,7 @@ void Jit::Comp_VDot(u32 op) { } -void Jit::Comp_VHdp(u32 op) { +void Jit::Comp_VHdp(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -568,7 +571,7 @@ void Jit::Comp_VHdp(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_VCrossQuat(u32 op) { +void Jit::Comp_VCrossQuat(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -676,7 +679,7 @@ void Jit::Comp_VCrossQuat(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vcmov(u32 op) { +void Jit::Comp_Vcmov(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -722,7 +725,7 @@ void Jit::Comp_Vcmov(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_VecDo3(u32 op) { +void Jit::Comp_VecDo3(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -861,7 +864,7 @@ void Jit::Comp_VecDo3(u32 op) { static float ssCompareTemp; -void Jit::Comp_Vcmp(u32 op) { +void Jit::Comp_Vcmp(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1009,11 +1012,11 @@ void Jit::Comp_Vcmp(u32 op) { gpr.UnlockAllX(); } -void Jit::Comp_Vsge(u32 op) { +void Jit::Comp_Vsge(MIPSOpcode op) { DISABLE; } -void Jit::Comp_Vslt(u32 op) { +void Jit::Comp_Vslt(MIPSOpcode op) { DISABLE; } @@ -1030,7 +1033,7 @@ extern const float mulTableVi2f[32] = { 1.0f/(1UL<<28),1.0f/(1UL<<29),1.0f/(1UL<<30),1.0f/(1UL<<31), }; -void Jit::Comp_Vi2f(u32 op) { +void Jit::Comp_Vi2f(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1096,7 +1099,7 @@ static const float half = 0.5f; static double maxIntAsDouble = (double)0x7fffffff; // that's not equal to 0x80000000 static double minIntAsDouble = (double)(int)0x80000000; -void Jit::Comp_Vf2i(u32 op) { +void Jit::Comp_Vf2i(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) DISABLE; @@ -1165,7 +1168,7 @@ void Jit::Comp_Vf2i(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vcst(u32 op) { +void Jit::Comp_Vcst(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1189,7 +1192,7 @@ void Jit::Comp_Vcst(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_VV2Op(u32 op) { +void Jit::Comp_VV2Op(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1313,16 +1316,16 @@ void Jit::Comp_VV2Op(u32 op) { fpr.ReleaseSpillLocks(); } -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 // rt = 0, imm = 255 appears to be used as a CPU interlock by some games. - if (rt != 0) { + if (rt != MIPS_REG_ZERO) { if (imm < 128) { //R(rt) = VI(imm); fpr.StoreFromRegisterV(imm); gpr.BindToRegister(rt, false, true); @@ -1368,7 +1371,7 @@ void Jit::Comp_Mftv(u32 op) { } } -void Jit::Comp_Vmtvc(u32 op) { +void Jit::Comp_Vmtvc(MIPSOpcode op) { CONDITIONAL_DISABLE; int vs = _VS; int imm = op & 0xFF; @@ -1387,7 +1390,7 @@ void Jit::Comp_Vmtvc(u32 op) { } } -void Jit::Comp_VMatrixInit(u32 op) { +void Jit::Comp_VMatrixInit(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1430,7 +1433,7 @@ void Jit::Comp_VMatrixInit(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vmmov(u32 op) { +void Jit::Comp_Vmmov(MIPSOpcode op) { CONDITIONAL_DISABLE; // TODO: This probably ignores prefixes? @@ -1472,7 +1475,7 @@ void Jit::Comp_Vmmov(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_VScl(u32 op) { +void Jit::Comp_VScl(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1523,7 +1526,7 @@ void Jit::Comp_VScl(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vmmul(u32 op) { +void Jit::Comp_Vmmul(MIPSOpcode op) { CONDITIONAL_DISABLE; // TODO: This probably ignores prefixes? @@ -1587,7 +1590,7 @@ void Jit::Comp_Vmmul(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vmscl(u32 op) { +void Jit::Comp_Vmscl(MIPSOpcode op) { CONDITIONAL_DISABLE; // TODO: This probably ignores prefixes? @@ -1632,7 +1635,7 @@ void Jit::Comp_Vmscl(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vtfm(u32 op) { +void Jit::Comp_Vtfm(MIPSOpcode op) { CONDITIONAL_DISABLE; // TODO: This probably ignores prefixes? Or maybe uses D? @@ -1689,27 +1692,27 @@ void Jit::Comp_Vtfm(u32 op) { fpr.ReleaseSpillLocks(); } -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_Vhoriz(u32 op) { +void Jit::Comp_Vhoriz(MIPSOpcode op) { DISABLE; } -void Jit::Comp_Viim(u32 op) { +void Jit::Comp_Viim(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1729,7 +1732,7 @@ void Jit::Comp_Viim(u32 op) { fpr.ReleaseSpillLocks(); } -void Jit::Comp_Vfim(u32 op) { +void Jit::Comp_Vfim(MIPSOpcode op) { CONDITIONAL_DISABLE; if (js.HasUnknownPrefix()) @@ -1769,7 +1772,7 @@ void SinCosNegSin(float angle) { sincostemp[1] = cosf(angle); } // Very heavily used by FF:CC -void Jit::Comp_VRot(u32 op) { +void Jit::Comp_VRot(MIPSOpcode op) { // DISABLE; CONDITIONAL_DISABLE; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index c73e6a5691..c6e550b4fa 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -97,7 +97,7 @@ u32 JitBreakpoint() return 1; } -static void JitLogMiss(u32 op) +static void JitLogMiss(MIPSOpcode op) { if (USE_JIT_MISSMAP) notJitOps[MIPSGetName(op)]++; @@ -188,10 +188,9 @@ void Jit::ClearCache() ClearCodeSpace(); } -void Jit::ClearCacheAt(u32 em_address) +void Jit::ClearCacheAt(u32 em_address, int length) { - // TODO: Properly. - ClearCache(); + blocks.InvalidateICache(em_address, length); } void Jit::CompileDelaySlot(int flags, RegCacheState *state) @@ -205,7 +204,7 @@ void Jit::CompileDelaySlot(int flags, RegCacheState *state) SAVE_FLAGS; // preserve flag around the delay slot! js.inDelaySlot = true; - u32 op = Memory::Read_Instruction(addr); + MIPSOpcode op = Memory::Read_Instruction(addr); MIPSCompileOp(op); js.inDelaySlot = false; @@ -223,13 +222,13 @@ void Jit::CompileDelaySlot(int flags, RegCacheState *state) void Jit::CompileAt(u32 addr) { CheckJitBreakpoint(addr, 0); - 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."); @@ -292,8 +291,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) b->normalEntry = GetCodePtr(); - // TODO: this needs work - MIPSAnalyst::AnalysisResults analysis; // = MIPSAnalyst::Analyze(em_address); + MIPSAnalyst::AnalysisResults analysis = MIPSAnalyst::Analyze(em_address); gpr.Start(mips_, analysis); fpr.Start(mips_, analysis); @@ -303,7 +301,7 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) // Jit breakpoints are quite fast, so let's do them in release too. CheckJitBreakpoint(js.compilerPC, 0); - u32 inst = Memory::Read_Instruction(js.compilerPC); + MIPSOpcode inst = Memory::Read_Instruction(js.compilerPC); js.downcountAmount += MIPSGetInstructionCycleEstimate(inst); MIPSCompileOp(inst); @@ -329,6 +327,14 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) js.compilerPC += 4; js.numInstructions++; + + // Safety check, in case we get a bunch of really large jit ops without a lot of branching. + if (GetSpaceLeft() < 0x800) + { + FlushAll(); + WriteExit(js.compilerPC, js.nextExit++); + js.compiling = false; + } } b->codeSize = (u32)(GetCodePtr() - b->normalEntry); @@ -338,13 +344,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"); } -void Jit::Comp_Generic(u32 op) +void Jit::Comp_Generic(MIPSOpcode op) { FlushAll(); MIPSInterpretFunc func = MIPSGetInterpretFunc(op); @@ -354,14 +360,14 @@ void Jit::Comp_Generic(u32 op) { MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); if (USE_JIT_MISSMAP) - ABI_CallFunctionC((void *)&JitLogMiss, op); + ABI_CallFunctionC((void *)&JitLogMiss, op.encoding); else - ABI_CallFunctionC((void *)func, op); + ABI_CallFunctionC((void *)func, op.encoding); } else - ERROR_LOG_REPORT(JIT, "Trying to compile instruction that can't be interpreted"); + ERROR_LOG_REPORT(JIT, "Trying to compile instruction %08x that can't be interpreted", op.encoding); - 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(). @@ -496,7 +502,7 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) return false; } -Jit::JitSafeMem::JitSafeMem(Jit *jit, int raddr, s32 offset, u32 alignMask) +Jit::JitSafeMem::JitSafeMem(Jit *jit, MIPSGPReg raddr, s32 offset, u32 alignMask) : jit_(jit), raddr_(raddr), offset_(offset), needsCheck_(false), needsSkip_(false), alignMask_(alignMask) { // This makes it more instructions, so let's play it safe and say we need a far jump. @@ -868,6 +874,6 @@ void Jit::CallProtectedFunction(void *func, const OpArg &arg1, const u32 arg2, c ABI_CallFunction((void *)thunks.GetLoadRegsFunction()); } -void Jit::Comp_DoNothing(u32 op) { } +void Jit::Comp_DoNothing(MIPSOpcode op) { } } // namespace diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 64546ecc68..596b083919 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -41,11 +41,11 @@ struct JitOptions JitOptions() { enableBlocklink = true; - // Seems to hurt performance? + // WARNING: These options don't work properly with cache clearing. + // Need to find a smart way to handle before enabling. immBranches = false; - // Seems to hurt performance also? continueBranches = false; - continueMaxInstructions = 100; + continueMaxInstructions = 300; } bool enableBlocklink; @@ -176,7 +176,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); @@ -184,70 +184,70 @@ public: const u8 *DoJit(u32 em_address, JitBlock *b); void CompileAt(u32 addr); - void Comp_RunBlock(u32 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_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); - void Comp_DoNothing(u32 op); + void Comp_DoNothing(MIPSOpcode op); void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz); void ApplyPrefixD(const u8 *vregs, VectorSize sz); @@ -268,7 +268,7 @@ public: AsmRoutineManager &Asm() { return asm_; } void ClearCache(); - void ClearCacheAt(u32 em_address); + void ClearCacheAt(u32 em_address, int length = 4); private: void GetStateAndFlushAll(RegCacheState &state); void RestoreState(const RegCacheState state); @@ -281,7 +281,7 @@ private: void CompileDelaySlot(int flags, RegCacheState &state) { CompileDelaySlot(flags, &state); } - void EatInstruction(u32 op); + void EatInstruction(MIPSOpcode op); void WriteExit(u32 destination, int exit_num); void WriteExitDestInEAX(); @@ -290,24 +290,24 @@ private: bool CheckJitBreakpoint(u32 addr, int downcountOffset); // Utility compilation functions - void BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely); - void BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely); - void BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool andLink, bool likely); - void BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely); - void BranchLog(u32 op); - void BranchLogExit(u32 op, u32 dest, bool useEAX); + void BranchFPFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely); + void BranchVFPUFlag(MIPSOpcode op, Gen::CCFlags cc, bool likely); + void BranchRSZeroComp(MIPSOpcode op, Gen::CCFlags cc, bool andLink, bool likely); + void BranchRSRTComp(MIPSOpcode op, Gen::CCFlags cc, bool likely); + void BranchLog(MIPSOpcode op); + void BranchLogExit(MIPSOpcode op, u32 dest, bool useEAX); // Utilities to reduce duplicated code - void CompImmLogic(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &)); - void CompTriArith(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &), u32 (*doImm)(const u32, const u32)); - void CompShiftImm(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); - void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); - void CompITypeMemRead(u32 op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc); - void CompITypeMemWrite(u32 op, u32 bits, void *safeFunc); - void CompITypeMemUnpairedLR(u32 op, bool isStore); - void CompITypeMemUnpairedLRInner(u32 op, X64Reg shiftReg); + void CompImmLogic(MIPSOpcode op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &)); + void CompTriArith(MIPSOpcode op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &), u32 (*doImm)(const u32, const u32)); + void CompShiftImm(MIPSOpcode op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); + void CompShiftVar(MIPSOpcode op, void (XEmitter::*shift)(int, OpArg, OpArg), u32 (*doImm)(const u32, const u32)); + void CompITypeMemRead(MIPSOpcode op, u32 bits, void (XEmitter::*mov)(int, int, X64Reg, OpArg), void *safeFunc); + void CompITypeMemWrite(MIPSOpcode op, u32 bits, void *safeFunc); + void CompITypeMemUnpairedLR(MIPSOpcode op, bool isStore); + void CompITypeMemUnpairedLRInner(MIPSOpcode op, X64Reg shiftReg); - void CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters); + void CompFPTriArith(MIPSOpcode op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters); void CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN = false); void CallProtectedFunction(void *func, const OpArg &arg1); @@ -341,7 +341,7 @@ private: class JitSafeMem { public: - JitSafeMem(Jit *jit, int raddr, s32 offset, u32 alignMask = 0xFFFFFFFF); + JitSafeMem(Jit *jit, MIPSGPReg raddr, s32 offset, u32 alignMask = 0xFFFFFFFF); // Emit code necessary for a memory write, returns true if MOV to dest is needed. bool PrepareWrite(OpArg &dest, int size); @@ -379,7 +379,7 @@ private: bool ImmValid(); Jit *jit_; - int raddr_; + MIPSGPReg raddr_; s32 offset_; int size_; bool needsCheck_; @@ -395,7 +395,7 @@ private: friend class JitSafeMem; }; -typedef void (Jit::*MIPSCompileFunc)(u32 opcode); +typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode); } // namespace MIPSComp diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp index aa96e2f002..a031ed130f 100644 --- a/Core/MIPS/x86/RegCache.cpp +++ b/Core/MIPS/x86/RegCache.cpp @@ -57,11 +57,12 @@ void GPRRegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { xregs[i].allocLocked = false; } for (int i = 0; i < NUM_MIPS_GPRS; i++) { - regs[i].location = GetDefaultLocation(i); + const MIPSGPReg r = MIPSGPReg(i); + regs[i].location = GetDefaultLocation(r); regs[i].away = false; regs[i].locked = false; } - + // todo: sort to find the most popular regs /* int maxPreload = 2; @@ -81,11 +82,11 @@ void GPRRegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { // these are MIPS reg indices -void GPRRegCache::Lock(int p1, int p2, int p3, int p4) { +void GPRRegCache::Lock(MIPSGPReg p1, MIPSGPReg p2, MIPSGPReg p3, MIPSGPReg p4) { regs[p1].locked = true; - if (p2 != 0xFF) regs[p2].locked = true; - if (p3 != 0xFF) regs[p3].locked = true; - if (p4 != 0xFF) regs[p4].locked = true; + if (p2 != MIPS_REG_INVALID) regs[p2].locked = true; + if (p3 != MIPS_REG_INVALID) regs[p3].locked = true; + if (p4 != MIPS_REG_INVALID) regs[p4].locked = true; } // these are x64 reg indices @@ -129,7 +130,7 @@ X64Reg GPRRegCache::GetFreeXReg() X64Reg xr = (X64Reg)aOrder[i]; if (xregs[xr].allocLocked) continue; - int preg = xregs[xr].mipsReg; + MIPSGPReg preg = xregs[xr].mipsReg; if (!regs[preg].locked) { StoreFromRegister(preg); @@ -151,12 +152,13 @@ void GPRRegCache::FlushR(X64Reg reg) int GPRRegCache::SanityCheck() const { for (int i = 0; i < NUM_MIPS_GPRS; i++) { + const MIPSGPReg r = MIPSGPReg(i); if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { Gen::X64Reg simple = regs[i].location.GetSimpleReg(); if (xregs[simple].allocLocked) return 1; - if (xregs[simple].mipsReg != i) + if (xregs[simple].mipsReg != r) return 2; } else if (regs[i].location.IsImm()) @@ -166,21 +168,21 @@ int GPRRegCache::SanityCheck() const { return 0; } -void GPRRegCache::DiscardRegContentsIfCached(int preg) { +void GPRRegCache::DiscardRegContentsIfCached(MIPSGPReg preg) { if (regs[preg].away && regs[preg].location.IsSimpleReg()) { X64Reg xr = regs[preg].location.GetSimpleReg(); xregs[xr].free = true; xregs[xr].dirty = false; - xregs[xr].mipsReg = -1; + xregs[xr].mipsReg = MIPS_REG_INVALID; regs[preg].away = false; regs[preg].location = GetDefaultLocation(preg); } } -void GPRRegCache::SetImmediate32(int preg, u32 immValue) { +void GPRRegCache::SetImmediate32(MIPSGPReg preg, u32 immValue) { // ZERO is always zero. Let's just make sure. - if (preg == 0) + if (preg == MIPS_REG_ZERO) immValue = 0; DiscardRegContentsIfCached(preg); @@ -188,17 +190,17 @@ void GPRRegCache::SetImmediate32(int preg, u32 immValue) { regs[preg].location = Imm32(immValue); } -bool GPRRegCache::IsImmediate(int preg) const { +bool GPRRegCache::IsImmediate(MIPSGPReg preg) const { // Always say yes for ZERO, even if it's in a temp reg. - if (preg == 0) + if (preg == MIPS_REG_ZERO) return true; return regs[preg].location.IsImm(); } -u32 GPRRegCache::GetImmediate32(int preg) const { +u32 GPRRegCache::GetImmediate32(MIPSGPReg preg) const { _dbg_assert_msg_(JIT, IsImmediate(preg), "Reg %d must be an immediate.", preg); // Always 0 for ZERO. - if (preg == 0) + if (preg == MIPS_REG_ZERO) return 0; return regs[preg].location.GetImmValue(); } @@ -209,12 +211,12 @@ const int *GPRRegCache::GetAllocationOrder(int &count) { } -OpArg GPRRegCache::GetDefaultLocation(int reg) const { +OpArg GPRRegCache::GetDefaultLocation(MIPSGPReg reg) const { return M(&mips->r[reg]); } -void GPRRegCache::KillImmediate(int preg, bool doLoad, bool makeDirty) { +void GPRRegCache::KillImmediate(MIPSGPReg preg, bool doLoad, bool makeDirty) { if (regs[preg].away) { if (regs[preg].location.IsImm()) BindToRegister(preg, doLoad, makeDirty); @@ -223,7 +225,7 @@ void GPRRegCache::KillImmediate(int preg, bool doLoad, bool makeDirty) { } } -void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty) { +void GPRRegCache::BindToRegister(MIPSGPReg i, bool doLoad, bool makeDirty) { if (!regs[i].away && regs[i].location.IsImm()) PanicAlert("Bad immediate"); @@ -237,13 +239,13 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty) { OpArg newloc = ::Gen::R(xr); if (doLoad) { // Force ZERO to be 0. - if (i == 0) + if (i == MIPS_REG_ZERO) emit->MOV(32, newloc, Imm32(0)); else emit->MOV(32, newloc, regs[i].location); } for (int j = 0; j < 32; j++) { - if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr) { + if (i != MIPSGPReg(j) && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr) { ERROR_LOG(JIT, "BindToRegister: Strange condition"); Crash(); } @@ -260,13 +262,13 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty) { } } -void GPRRegCache::StoreFromRegister(int i) { +void GPRRegCache::StoreFromRegister(MIPSGPReg i) { if (regs[i].away) { bool doStore; if (regs[i].location.IsSimpleReg()) { X64Reg xr = RX(i); xregs[xr].free = true; - xregs[xr].mipsReg = -1; + xregs[xr].mipsReg = MIPS_REG_INVALID; doStore = xregs[xr].dirty; xregs[xr].dirty = false; } else { @@ -275,7 +277,7 @@ void GPRRegCache::StoreFromRegister(int i) { } OpArg newLoc = GetDefaultLocation(i); // But never store to ZERO. - if (doStore && i != 0) + if (doStore && i != MIPS_REG_ZERO) emit->MOV(32, newLoc, regs[i].location); regs[i].location = newLoc; regs[i].away = false; @@ -288,17 +290,18 @@ void GPRRegCache::Flush() { PanicAlert("Someone forgot to unlock X64 reg %i.", i); } for (int i = 0; i < NUM_MIPS_GPRS; i++) { + const MIPSGPReg r = MIPSGPReg(i); if (regs[i].locked) { PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); } if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { - X64Reg xr = RX(i); - StoreFromRegister(i); + X64Reg xr = RX(r); + StoreFromRegister(r); xregs[xr].dirty = false; } else if (regs[i].location.IsImm()) { - StoreFromRegister(i); + StoreFromRegister(r); } else { _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc); } diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h index 5bea7d12d3..6b3c8ead27 100644 --- a/Core/MIPS/x86/RegCache.h +++ b/Core/MIPS/x86/RegCache.h @@ -17,8 +17,9 @@ #pragma once -#include "x64Emitter.h" -#include "../MIPSAnalyst.h" +#include "Common/x64Emitter.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" using namespace Gen; @@ -38,7 +39,7 @@ struct MIPSCachedReg { }; struct X64CachedReg { - int mipsReg; + MIPSGPReg mipsReg; bool dirty; bool free; bool allocLocked; @@ -56,7 +57,7 @@ public: ~GPRRegCache() {} void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats); - void DiscardRegContentsIfCached(int preg); + void DiscardRegContentsIfCached(MIPSGPReg preg); void SetEmitter(XEmitter *emitter) {emit = emitter;} void FlushR(X64Reg reg); @@ -71,30 +72,30 @@ public: void Flush(); void FlushBeforeCall(); int SanityCheck() const; - void KillImmediate(int preg, bool doLoad, bool makeDirty); + void KillImmediate(MIPSGPReg preg, bool doLoad, bool makeDirty); - void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(int preg); + void BindToRegister(MIPSGPReg preg, bool doLoad = true, bool makeDirty = true); + void StoreFromRegister(MIPSGPReg preg); - const OpArg &R(int preg) const {return regs[preg].location;} - X64Reg RX(int preg) const + const OpArg &R(MIPSGPReg preg) const {return regs[preg].location;} + X64Reg RX(MIPSGPReg preg) const { if (regs[preg].away && regs[preg].location.IsSimpleReg()) return regs[preg].location.GetSimpleReg(); PanicAlert("Not so simple - %i", preg); return (X64Reg)-1; } - OpArg GetDefaultLocation(int reg) const; + OpArg GetDefaultLocation(MIPSGPReg reg) const; // Register locking. - void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff); + void Lock(MIPSGPReg p1, MIPSGPReg p2 = MIPS_REG_INVALID, MIPSGPReg p3 = MIPS_REG_INVALID, MIPSGPReg p4 = MIPS_REG_INVALID); void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff); void UnlockAll(); void UnlockAllX(); - void SetImmediate32(int preg, u32 immValue); - bool IsImmediate(int preg) const; - u32 GetImmediate32(int preg) const; + void SetImmediate32(MIPSGPReg preg, u32 immValue); + bool IsImmediate(MIPSGPReg preg) const; + u32 GetImmediate32(MIPSGPReg preg) const; void GetState(GPRRegCacheState &state) const; void RestoreState(const GPRRegCacheState state); diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 02aa55fef6..3fd60a8d35 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -122,9 +122,9 @@ void Clear() memset(m_pVRAM, 0, VRAM_SIZE); } -u32 Read_Instruction(u32 address) +Opcode Read_Instruction(u32 address) { - u32 inst = Read_U32(address); + Opcode inst = Opcode(Read_U32(address)); if (MIPS_IS_EMUHACK(inst) && MIPSComp::jit) { JitBlockCache *bc = MIPSComp::jit->GetBlockCache(); @@ -139,16 +139,16 @@ u32 Read_Instruction(u32 address) } } -u32 Read_Opcode_JIT(u32 address) +Opcode Read_Opcode_JIT(u32 address) { return Read_Instruction(address); } // WARNING! No checks! // We assume that _Address is cached -void Write_Opcode_JIT(const u32 _Address, const u32 _Value) +void Write_Opcode_JIT(const u32 _Address, const Opcode _Value) { - Memory::WriteUnchecked_U32(_Value, _Address); + Memory::WriteUnchecked_U32(_Value.encoding, _Address); } void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) diff --git a/Core/MemMap.h b/Core/MemMap.h index ad2e76a483..417f0e12f5 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -97,13 +97,40 @@ void Shutdown(); void DoState(PointerWrap &p); void Clear(); +struct Opcode { + Opcode() { + encoding = 0; + } + + explicit Opcode(u32 v) : encoding (v) { + } + + u32 operator & (const u32 &arg) const { + return encoding & arg; + } + + u32 operator >> (const u32 &arg) const { + return encoding >> arg; + } + + bool operator == (const u32 &arg) const { + return encoding == arg; + } + + bool operator != (const u32 &arg) const { + return encoding != arg; + } + + u32 encoding; +}; + // used by JIT to read instructions -u32 Read_Opcode_JIT(const u32 _Address); +Opcode Read_Opcode_JIT(const u32 _Address); // used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode -void Write_Opcode_JIT(const u32 _Address, const u32 _Value); +void Write_Opcode_JIT(const u32 _Address, const Opcode _Value); // this is used by Debugger a lot. // For now, just reads from memory! -u32 Read_Instruction(const u32 _Address); +Opcode Read_Instruction(const u32 _Address); // For use by emulator diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 28829f88b7..17cebe9179 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -236,9 +236,18 @@ namespace Reporting return 0; } + bool IsSupported() + { + // Disabled when using certain hacks, because they make for poor reports. + // TODO: Numbers to avoid dependency on GLES code. + if (g_Config.iRenderingMode == 2 || g_Config.iRenderingMode == 3) + return false; + return true; + } + bool IsEnabled() { - if (g_Config.sReportHost.empty()) + if (g_Config.sReportHost.empty() || !IsSupported()) return false; // Disabled by default for now. if (g_Config.sReportHost.compare("default") == 0) @@ -246,6 +255,21 @@ namespace Reporting return true; } + void Enable(bool flag, std::string host) + { + if (IsSupported() && IsEnabled() != flag) + { + // "" means explicitly disabled. Don't ever turn on by default. + // "default" means it's okay to turn it on by default. + g_Config.sReportHost = flag ? host : ""; + } + } + + void EnableDefault() + { + g_Config.sReportHost = "default"; + } + void ReportMessage(const char *message, ...) { if (!IsEnabled() || CheckSpamLimited()) diff --git a/Core/Reporting.h b/Core/Reporting.h index 27d8a37414..d8ccf87912 100644 --- a/Core/Reporting.h +++ b/Core/Reporting.h @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/CommonTypes.h" +#include #define ERROR_LOG_REPORT(t,...) { ERROR_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } #define WARN_LOG_REPORT(t,...) { WARN_LOG(t, __VA_ARGS__); Reporting::ReportMessage(__VA_ARGS__); } @@ -34,6 +35,18 @@ namespace Reporting { + // Returns whether or not the reporting system is currently enabled. bool IsEnabled(); + + // Returns whether the reporting system can be enabled (based on system or settings.) + bool IsSupported(); + + // Set the current enabled state of the reporting system and desired reporting server host. + void Enable(bool flag, std::string host); + + // Use the default reporting setting (per compiled settings) of host and enabled state. + void EnableDefault(); + + // Report a message string, using the format string as a key. void ReportMessage(const char *message, ...); } \ No newline at end of file diff --git a/Core/System.cpp b/Core/System.cpp index 075225ffcc..e545fbf22e 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -22,6 +22,7 @@ #include "native/thread/thread.h" #include "native/thread/threadutil.h" #include "native/base/mutex.h" +#include "util/text/utf8.h" #include "Core/MemMap.h" @@ -324,13 +325,16 @@ CoreParameter &PSP_CoreParameter() { void GetSysDirectories(std::string &memstickpath, std::string &flash0path) { #ifdef _WIN32 - char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT]; + wchar_t path_buffer[_MAX_PATH]; + char drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT]; char memstickpath_buf[_MAX_PATH]; char flash0path_buf[_MAX_PATH]; - GetModuleFileName(NULL,path_buffer,sizeof(path_buffer)); + GetModuleFileName(NULL, path_buffer, sizeof(path_buffer)); - _splitpath_s(path_buffer, drive, dir, file, ext ); + std::string path = ConvertWStringToUTF8(path_buffer); + + _splitpath_s(path.c_str(), drive, dir, file, ext ); // Mount a couple of filesystems sprintf(memstickpath_buf, "%s%smemstick\\", drive, dir); diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 947e0e7944..e3c077dd68 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -39,25 +39,58 @@ // GL_NV_shader_framebuffer_fetch looks interesting.... + +// Dest factors where it's safe to eliminate the alpha test under certain conditions +const bool safeDestFactors[16] = { + true, // GE_DSTBLEND_SRCCOLOR, + true, // GE_DSTBLEND_INVSRCCOLOR, + false, // GE_DSTBLEND_SRCALPHA, + true, // GE_DSTBLEND_INVSRCALPHA, + true, // GE_DSTBLEND_DSTALPHA, + true, // GE_DSTBLEND_INVDSTALPHA, + false, // GE_DSTBLEND_DOUBLESRCALPHA, + false, // GE_DSTBLEND_DOUBLEINVSRCALPHA, + true, // GE_DSTBLEND_DOUBLEDSTALPHA, + true, // GE_DSTBLEND_DOUBLEINVDSTALPHA, + true, //GE_DSTBLEND_FIXB, +}; + + static bool IsAlphaTestTriviallyTrue() { GEComparison alphaTestFunc = gstate.getAlphaTestFunction(); int alphaTestRef = gstate.getAlphaTestRef(); int alphaTestMask = gstate.getAlphaTestMask(); switch (alphaTestFunc) { + case GE_COMP_NEVER: + return false; + case GE_COMP_ALWAYS: return true; + case GE_COMP_GEQUAL: return alphaTestRef == 0; - - // This breaks the trees in MotoGP, for example. - // case GE_COMP_GREATER: - //if (alphaTestRef == 0 && (gstate.isAlphaBlendEnabled() & 1) && gstate.getBlendFuncA() == GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncB() == GE_SRCBLEND_INVSRCALPHA) - // return true; + + // Non-zero check. If we have no depth testing (and thus no depth writing), and an alpha func that will result in no change if zero alpha, get rid of the alpha test. + // Speeds up Lumines by a LOT on PowerVR. + case GE_COMP_NOTEQUAL: + case GE_COMP_GREATER: + { + bool depthTest = gstate.isDepthTestEnabled(); + bool stencilTest = gstate.isStencilTestEnabled(); + GEBlendSrcFactor src = gstate.getBlendFuncA(); + GEBlendDstFactor dst = gstate.getBlendFuncB(); + if (!stencilTest && !depthTest && alphaTestRef == 0 && gstate.isAlphaBlendEnabled() && src == GE_SRCBLEND_SRCALPHA && safeDestFactors[(int)dst]) + return true; + return false; + } case GE_COMP_LEQUAL: return alphaTestRef == 255; + case GE_COMP_EQUAL: + case GE_COMP_LESS: + return false; default: return false; } @@ -66,8 +99,15 @@ static bool IsAlphaTestTriviallyTrue() { static bool IsColorTestTriviallyTrue() { GEComparison colorTestFunc = gstate.getColorTestFunction(); switch (colorTestFunc) { + case GE_COMP_NEVER: + return false; + case GE_COMP_ALWAYS: return true; + + case GE_COMP_EQUAL: + case GE_COMP_NOTEQUAL: + return false; default: return false; } @@ -141,6 +181,11 @@ void ComputeFragmentShaderID(FragmentShaderID *id) { id->d[0] |= (doTextureProjection & 1) << 16; id->d[0] |= (enableColorDoubling & 1) << 17; id->d[0] |= (enableAlphaDoubling & 1) << 18; + + if (enableAlphaTest) + gpuStats.numAlphaTestedDraws++; + else + gpuStats.numNonAlphaTestedDraws++; } } @@ -205,7 +250,7 @@ void GenerateFragmentShader(char *buffer) { if (enableAlphaTest) { if (gstate_c.gpuVendor == GPU_VENDOR_POWERVR) - WRITE(p, "float roundTo255th(in float x) { float y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); + WRITE(p, "float roundTo255th(in mediump float x) { mediump float y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); else WRITE(p, "float roundAndScaleTo255f(in float x) { return floor(x * 255.0 + 0.5); }\n"); } @@ -280,10 +325,13 @@ void GenerateFragmentShader(char *buffer) { GEComparison alphaTestFunc = gstate.getAlphaTestFunction(); const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; // never/always don't make sense if (alphaTestFuncs[alphaTestFunc][0] != '#') { - if (gstate_c.gpuVendor == GPU_VENDOR_POWERVR) - WRITE(p, " if (roundTo255th(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); - else + if (gstate_c.gpuVendor == GPU_VENDOR_POWERVR) { + // Work around bad PVR driver problem where equality check + discard just doesn't work. + if (alphaTestFunc != 3) + WRITE(p, " if (roundTo255th(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + } else { WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + } } } diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 8af1994c49..c0e2cf8ee3 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -372,7 +372,7 @@ VirtualFramebuffer *FramebufferManager::GetDisplayFBO() { VirtualFramebuffer *v = vfbs_[i]; if (MaskedEqual(v->fb_address, displayFramebufPtr_) && v->format == displayFormat_ && v->width >= 480) { // Could check w too but whatever - if (match == NULL || match->last_frame_used < v->last_frame_used) { + if (match == NULL || match->last_frame_render < v->last_frame_render) { match = v; } } @@ -395,38 +395,42 @@ VirtualFramebuffer *FramebufferManager::GetDisplayFBO() { } // Heuristics to figure out the size of FBO to create. -void GuessDrawingSize(int &drawing_width, int &drawing_height) { +void DrawingSize(int &drawing_width, int &drawing_height) { int default_width = 480; int default_height = 272; int viewport_width = (int) gstate.getViewportX1(); int viewport_height = (int) gstate.getViewportY1(); - int region_width = (gstate.getRegionX2() + 1) ; - int region_height = (gstate.getRegionY2() + 1) ; + int region_width = gstate.getRegionX2() + 1; + int region_height = gstate.getRegionY2() + 1; + int scissor_width = gstate.getScissorX2() + 1; + int scissor_height = gstate.getScissorY2() + 1; int fb_width = gstate.fbwidth & 0x3C0; - DEBUG_LOG(HLE,"viewport : %ix%i, region : %ix%i, stride: %i", viewport_width,viewport_height, region_width, region_height, fb_width); + DEBUG_LOG(HLE,"viewport : %ix%i, region : %ix%i , scissor: %ix%i, stride: %i, %i", viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_width, gstate.isModeThrough()); - // In case viewport return as 0x0 like FF Type-0 + // Viewport may return 0x0 for example FF Type-0 and we set it to 480x272 if (viewport_width <= 1 && viewport_height <=1) { - drawing_width = default_width; - drawing_height = default_height; - } + viewport_width = default_width; + viewport_height = default_height; + } - if (fb_width < 512) { - if (fb_width != viewport_width) { + if (fb_width > 0 && fb_width < 512) { + // Correct scissor size has to be used to render like character shadow in Mortal Kombat . + if (fb_width == scissor_width && region_width != scissor_width) { + drawing_width = scissor_width; + drawing_height = scissor_height; + } else { drawing_width = viewport_width; drawing_height = viewport_height; - } else { - drawing_width = region_width; - drawing_height = region_height; } } else { - if (fb_width != region_width) { - drawing_width = default_width; - drawing_height = default_height; - } else { + // Correct region size has to be used when fb_width equals to region_width for exmaple GTA/Midnight Club/MSG Peace Maker . + if (fb_width == region_width && region_width != scissor_width) { drawing_width = region_width; drawing_height = region_height; + } else { + drawing_width = default_width; + drawing_height = default_height; } } } @@ -453,7 +457,7 @@ void FramebufferManager::DestroyFramebuf(VirtualFramebuffer *v) { void FramebufferManager::SetRenderFrameBuffer() { if (!gstate_c.framebufChanged && currentRenderVfb_) { - currentRenderVfb_->last_frame_used = gpuStats.numFlips; + currentRenderVfb_->last_frame_render = gpuStats.numFlips; currentRenderVfb_->dirtyAfterDisplay = true; if (!gstate_c.skipDrawReason) currentRenderVfb_->reallyDirtyAfterDisplay = true; @@ -475,10 +479,10 @@ void FramebufferManager::SetRenderFrameBuffer() { // As there are no clear "framebuffer width" and "framebuffer height" registers, // we need to infer the size of the current framebuffer somehow. Let's try the viewport. - GEBufferFormat fmt = static_cast(gstate.framebufpixformat & 3); + GEBufferFormat fmt = gstate.FrameBufFormat(); int drawing_width, drawing_height; - GuessDrawingSize(drawing_width, drawing_height); + DrawingSize(drawing_width, drawing_height); int buffer_width = drawing_width; int buffer_height = drawing_height; @@ -566,7 +570,7 @@ void FramebufferManager::SetRenderFrameBuffer() { textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); - vfb->last_frame_used = gpuStats.numFlips; + vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed = gpuStats.numFlips; vfbs_.push_back(vfb); ClearBuffer(); @@ -589,7 +593,7 @@ void FramebufferManager::SetRenderFrameBuffer() { DEBUG_LOG(HLE, "Switching render target to FBO for %08x: %i x %i x %i ", vfb->fb_address, vfb->width, vfb->height, vfb->format); vfb->usageFlags |= FB_USAGE_RENDERTARGET; gstate_c.textureChanged = true; - vfb->last_frame_used = gpuStats.numFlips; + vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) @@ -633,13 +637,13 @@ void FramebufferManager::SetRenderFrameBuffer() { // to it. This broke stuff before, so now it only clears on the first use of an // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. - if (vfb->last_frame_used != gpuStats.numFlips) { + if (vfb->last_frame_render != gpuStats.numFlips) { ClearBuffer(); } #endif currentRenderVfb_ = vfb; } else { - vfb->last_frame_used = gpuStats.numFlips; + vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) @@ -781,14 +785,14 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s return; } - nvfb->last_frame_used = gpuStats.numFlips; + nvfb->last_frame_render = gpuStats.numFlips; bvfbs_.push_back(nvfb); fbo_bind_as_render_target(nvfb->fbo); ClearBuffer(); glEnable(GL_DITHER); } else { nvfb->usageFlags |= FB_USAGE_RENDERTARGET; - nvfb->last_frame_used = gpuStats.numFlips; + nvfb->last_frame_render = gpuStats.numFlips; nvfb->dirtyAfterDisplay = true; #ifdef USING_GLES2 @@ -798,7 +802,7 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s // to it. This broke stuff before, so now it only clears on the first use of an // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. - if (nvfb->last_frame_used != gpuStats.numFlips) { + if (nvfb->last_frame_render != gpuStats.numFlips) { ClearBuffer(); } #endif @@ -1194,7 +1198,7 @@ void FramebufferManager::DecimateFBOs() { #endif for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - int age = frameLastFramebufUsed - vfb->last_frame_used; + int age = frameLastFramebufUsed - std::max(vfb->last_frame_render, vfb->last_frame_used); if(useMem && age == 0 && !vfb->memoryUpdated) { ReadFramebufferToMemory(vfb); @@ -1214,7 +1218,7 @@ void FramebufferManager::DecimateFBOs() { // Do the same for ReadFramebuffersToMemory's VFBs for (size_t i = 0; i < bvfbs_.size(); ++i) { VirtualFramebuffer *vfb = bvfbs_[i]; - int age = frameLastFramebufUsed - vfb->last_frame_used; + int age = frameLastFramebufUsed - vfb->last_frame_render; if (age > FBO_OLD_AGE) { INFO_LOG(HLE, "Decimating FBO for %08x (%i x %i x %i), age %i", vfb->fb_address, vfb->width, vfb->height, vfb->format, age) DestroyFramebuf(vfb); diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index f7d0243dd4..a8649d81ed 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -61,6 +61,7 @@ enum { struct VirtualFramebuffer { int last_frame_used; + int last_frame_render; bool memoryUpdated; u32 fb_address; diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 2f9391eecb..17bfec1340 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -116,7 +116,6 @@ static const CommandTableEntry commandTable[] = { {GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE}, {GE_CMD_TEXFUNC, FLAG_FLUSHBEFOREONCHANGE}, {GE_CMD_COLORTEST, FLAG_FLUSHBEFOREONCHANGE}, - {GE_CMD_ALPHATEST, FLAG_FLUSHBEFOREONCHANGE}, {GE_CMD_ALPHATESTENABLE, FLAG_FLUSHBEFOREONCHANGE}, {GE_CMD_COLORTESTENABLE, FLAG_FLUSHBEFOREONCHANGE}, {GE_CMD_COLORTESTMASK, FLAG_FLUSHBEFOREONCHANGE}, @@ -140,6 +139,7 @@ static const CommandTableEntry commandTable[] = { {GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE}, // Uniform changes + {GE_CMD_ALPHATEST, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE}, {GE_CMD_COLORREF, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE}, {GE_CMD_TEXENVCOLOR, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE}, @@ -444,8 +444,8 @@ void GLES_GPU::InitClear() { } void GLES_GPU::InitClearInternal() { - bool useBufferedRendering = g_Config.iRenderingMode != 0 ? 1 : 0; - if (!useBufferedRendering) { + bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE; + if (useNonBufferedRendering) { glstate.depthWrite.set(GL_TRUE); glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearColor(0,0,0,1); @@ -644,10 +644,16 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization. u32 count = data & 0xFFFF; - u32 prim = data >> 16; + GEPrimitiveType prim = static_cast(data >> 16); // Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though. - if ((prim == GE_PRIM_LINE_STRIP || prim == GE_PRIM_LINES) && (gstate.antiAliasEnable & 1)) + + // Discard AA lines in DOA + if ((prim == GE_PRIM_LINE_STRIP) && gstate.isAntiAliasEnabled()) + break; + + // Discard AA lines in Summon Night 5 + if ((prim == GE_PRIM_LINES) && gstate.isAntiAliasEnabled() && gstate.isSkinningEnabled()) break; // This also make skipping drawing very effective. @@ -662,7 +668,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { } if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); break; } @@ -672,12 +678,18 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { void *inds = 0; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); break; } inds = Memory::GetPointer(gstate_c.indexAddr); } +#ifndef USING_GLES2 + if (prim > GE_PRIM_RECTANGLES) { + ERROR_LOG_REPORT_ONCE(reportPrim, G3D, "Unexpected prim type: %d", prim); + } +#endif + int bytesRead; transformDraw_.SubmitPrim(verts, inds, prim, count, gstate.vertType, -1, &bytesRead); @@ -702,9 +714,29 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { // The arrow and other rotary items in Puzbob are bezier patches, strangely enough. case GE_CMD_BEZIER: { + void *control_points = Memory::GetPointer(gstate_c.vertexAddr); + void *indices = NULL; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { + if (!Memory::IsValidAddress(gstate_c.indexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + break; + } + indices = Memory::GetPointer(gstate_c.indexAddr); + } + + if (gstate.getPatchPrimitiveType() != GE_PATCHPRIM_TRIANGLES) { + ERROR_LOG_REPORT(G3D, "Unsupported patch primitive %x", gstate.getPatchPrimitiveType()); + break; + } + + // TODO: Get rid of this old horror... int bz_ucount = data & 0xFF; int bz_vcount = (data >> 8) & 0xFF; transformDraw_.DrawBezier(bz_ucount, bz_vcount); + + // And instead use this. + // GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); + // transformDraw_.SubmitBezier(control_points, indices, sp_ucount, sp_vcount, patchPrim, gstate.vertType); } break; @@ -714,14 +746,14 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); break; } indices = Memory::GetPointer(gstate_c.indexAddr); } if (gstate.getPatchPrimitiveType() != GE_PATCHPRIM_TRIANGLES) { - ERROR_LOG(G3D, "Unsupported patch primitive %x", gstate.patchprimitive&3); + ERROR_LOG_REPORT(G3D, "Unsupported patch primitive %x", gstate.getPatchPrimitiveType()); break; } @@ -729,7 +761,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { int sp_vcount = (data >> 8) & 0xFF; int sp_utype = (data >> 16) & 0x3; int sp_vtype = (data >> 18) & 0x3; - int patchPrim = gstate.patchprimitive & 3; + GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); transformDraw_.SubmitSpline(control_points, indices, sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, gstate.vertType); } break; @@ -1106,11 +1138,11 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { shaderManager_->DirtyUniform(DIRTY_COLORMASK); break; -#ifndef USING_GLES2 case GE_CMD_ALPHATEST: +#ifndef USING_GLES2 if (((data >> 16) & 0xFF) != 0xFF && (data & 7) > 1) WARN_LOG_REPORT_ONCE(alphatestmask, HLE, "Unsupported alphatest mask: %02x", (data >> 16) & 0xFF); - break; + // Intentional fallthrough. #endif case GE_CMD_COLORREF: @@ -1300,22 +1332,22 @@ void GLES_GPU::DoBlockTransfer() { // // etc.... - u32 srcBasePtr = (gstate.transfersrc & 0xFFFFF0) | ((gstate.transfersrcw & 0xFF0000) << 8); - u32 srcStride = gstate.transfersrcw & 0x3F8; + u32 srcBasePtr = gstate.getTransferSrcAddress(); + u32 srcStride = gstate.getTransferSrcStride(); - u32 dstBasePtr = (gstate.transferdst & 0xFFFFF0) | ((gstate.transferdstw & 0xFF0000) << 8); - u32 dstStride = gstate.transferdstw & 0x3F8; + u32 dstBasePtr = gstate.getTransferDstAddress(); + u32 dstStride = gstate.getTransferDstStride(); - int srcX = gstate.transfersrcpos & 0x3FF; - int srcY = (gstate.transfersrcpos >> 10) & 0x3FF; + int srcX = gstate.getTransferSrcX(); + int srcY = gstate.getTransferSrcY(); - int dstX = gstate.transferdstpos & 0x3FF; - int dstY = (gstate.transferdstpos >> 10) & 0x3FF; + int dstX = gstate.getTransferDstX(); + int dstY = gstate.getTransferDstY(); - int width = (gstate.transfersize & 0x3FF) + 1; - int height = ((gstate.transfersize >> 10) & 0x3FF) + 1; + int width = gstate.getTransferWidth(); + int height = gstate.getTransferHeight(); - int bpp = (gstate.transferstart & 1) ? 4 : 2; + int bpp = gstate.getTransferBpp(); DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); @@ -1329,7 +1361,6 @@ void GLES_GPU::DoBlockTransfer() { // TODO: Notify all overlapping FBOs that they need to reload. textureCache_.Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT); - // A few games use this INSTEAD of actually drawing the video image to the screen, they just blast it to // the backbuffer. Detect this and have the framebuffermanager draw the pixels. diff --git a/GPU/GLES/IndexGenerator.cpp b/GPU/GLES/IndexGenerator.cpp index 46a645a6a2..acb9672aae 100644 --- a/GPU/GLES/IndexGenerator.cpp +++ b/GPU/GLES/IndexGenerator.cpp @@ -29,7 +29,7 @@ static const u8 indexedPrimitiveType[7] = { }; void IndexGenerator::Reset() { - prim_ = -1; + prim_ = GE_PRIM_INVALID; count_ = 0; index_ = 0; seenPrims_ = 0; diff --git a/GPU/GLES/IndexGenerator.h b/GPU/GLES/IndexGenerator.h index 832bc01a75..2817991f8c 100644 --- a/GPU/GLES/IndexGenerator.h +++ b/GPU/GLES/IndexGenerator.h @@ -29,7 +29,7 @@ public: void Reset(); static bool PrimCompatible(int prim1, int prim2); bool PrimCompatible(int prim); - int Prim() const { return prim_; } + GEPrimitiveType Prim() const { return prim_; } void AddPrim(int prim, int vertexCount); void TranslatePrim(int prim, int numInds, const u8 *inds, int indexOffset); @@ -93,7 +93,7 @@ private: int index_; int count_; int pureCount_; - int prim_; + GEPrimitiveType prim_; int seenPrims_; }; diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index 37b5b7d0a8..8cc0a37b00 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -25,6 +25,8 @@ #include + +#include "base/logging.h" #include "math/lin/matrix4x4.h" #include "Core/Reporting.h" @@ -38,7 +40,7 @@ Shader::Shader(const char *code, uint32_t shaderType, bool useHWTransform) : failed_(false), useHWTransform_(useHWTransform) { source_ = code; #ifdef SHADERLOG - OutputDebugString(code); + OutputDebugStringUTF8(code); #endif shader = glCreateShader(shaderType); glShaderSource(shader, 1, &code, 0); @@ -56,7 +58,7 @@ Shader::Shader(const char *code, uint32_t shaderType, bool useHWTransform) : fai ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code); Reporting::ReportMessage("Error in shader compilation: info: %s / code: %s", infoLog, (const char *)code); #ifdef SHADERLOG - OutputDebugString(infoLog); + OutputDebugStringUTF8(infoLog); #endif failed_ = true; shader = 0; @@ -89,9 +91,9 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, bool useHWTransform) ERROR_LOG(G3D, "VS:\n%s", vs->source().c_str()); ERROR_LOG(G3D, "FS:\n%s", fs->source().c_str()); #ifdef SHADERLOG - OutputDebugString(buf); - OutputDebugString(vs->source().c_str()); - OutputDebugString(fs->source().c_str()); + OutputDebugStringUTF8(buf); + OutputDebugStringUTF8(vs->source().c_str()); + OutputDebugStringUTF8(fs->source().c_str()); #endif delete [] buf; // we're dead! } @@ -113,7 +115,7 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, bool useHWTransform) u_view = glGetUniformLocation(program, "u_view"); u_world = glGetUniformLocation(program, "u_world"); u_texmtx = glGetUniformLocation(program, "u_texmtx"); - if (gstate.getWeightMask() != 0) + if (gstate.getWeightMask() != GE_VTYPE_WEIGHT_NONE) numBones = TranslateNumBones(gstate.getNumBoneWeights()); else numBones = 0; @@ -338,7 +340,7 @@ void LinkedShader::updateUniforms() { // Not sure what GE_TEXMAP_UNKNOWN is, but seen in Riviera. Treating the same as GE_TEXMAP_TEXTURE_COORDS works. if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN) { static const float rescale[4] = {1.0f, 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; - float factor = rescale[(gstate.vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT]; + float factor = rescale[gstate.getTexCoordMask() >> GE_VTYPE_TC_SHIFT]; uvscaleoff[0] = gstate_c.uv.uScale * factor * widthFactor; uvscaleoff[1] = gstate_c.uv.vScale * factor * heightFactor; uvscaleoff[2] = gstate_c.uv.uOff * widthFactor; diff --git a/GPU/GLES/Spline.cpp b/GPU/GLES/Spline.cpp index 83c1614072..279482e382 100644 --- a/GPU/GLES/Spline.cpp +++ b/GPU/GLES/Spline.cpp @@ -20,7 +20,10 @@ // Just to get something on the screen, we'll just not subdivide correctly. void TransformDrawEngine::DrawBezier(int ucount, int vcount) { - u16 indices[3 * 3 * 6]; + if ((ucount - 1) % 3 != 0 || (vcount - 1) % 3 != 0) + ERROR_LOG_REPORT(HLE,"Unsupported bezier parameters ucount=%i, vcount=%i", ucount, vcount); + + u16 *indices = new u16[ucount * vcount * 6]; static bool reported = false; if (!reported) { @@ -31,14 +34,14 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { // if (gstate.patchprimitive) // Generate indices for a rectangular mesh. int c = 0; - for (int y = 0; y < 3; y++) { - for (int x = 0; x < 3; x++) { - indices[c++] = y * 4 + x; - indices[c++] = y * 4 + x + 1; - indices[c++] = (y + 1) * 4 + x + 1; - indices[c++] = (y + 1) * 4 + x + 1; - indices[c++] = (y + 1) * 4 + x; - indices[c++] = y * 4 + x; + for (int y = 0; y < ucount; y++) { + for (int x = 0; x < vcount - 1; x++) { + indices[c++] = y * (vcount - 1)+ x; + indices[c++] = y * (vcount - 1) + x + 1; + indices[c++] = (y + 1) * (vcount - 1) + x + 1; + indices[c++] = (y + 1) * (vcount - 1) + x + 1; + indices[c++] = (y + 1) * (vcount - 1) + x; + indices[c++] = y * (vcount - 1) + x; } } @@ -57,7 +60,7 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { } } - if (!(gstate.vertType & GE_VTYPE_TC_MASK)) { + if (!gstate.getTexCoordMask()) { VertexDecoder *dec = GetVertexDecoder(gstate.vertType); dec->SetVertexType(gstate.vertType); u32 newVertType = dec->InjectUVs(decoded2, Memory::GetPointer(gstate_c.vertexAddr), customUV, 16); @@ -66,6 +69,8 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { SubmitPrim(Memory::GetPointer(gstate_c.vertexAddr), &indices[0], GE_PRIM_TRIANGLES, c, gstate.vertType, GE_VTYPE_IDX_16BIT, 0); } Flush(); // as our vertex storage here is temporary, it will only survive one draw. + + delete [] indices; } @@ -77,10 +82,13 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { #define END_OPEN_V 8 // We decode all vertices into a common format for easy interpolation and stuff. -// Not fast but this spline stuff is rarely used for time critical things, strangely enough. +// Not fast but can be optimized later. struct HWSplinePatch { u8 *points[16]; int type; + + // We need to generate both UVs and normals later... + // float u0, v0, u1, v1; }; void CopyTriangle(u8 *&dest, u8 *v1, u8 *v2, u8 * v3, int vertexSize) { @@ -92,8 +100,7 @@ void CopyTriangle(u8 *&dest, u8 *v1, u8 *v2, u8 * v3, int vertexSize) { dest += vertexSize; } -void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type) -{ +void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, u32 vertex_type) { Flush(); if (prim_type != GE_PATCHPRIM_TRIANGLES) { @@ -102,12 +109,11 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int } // We're not actually going to decode, only reshuffle. - VertexDecoder vdecoder; - vdecoder.SetVertexType(vertex_type); + VertexDecoder *vdecoder = GetVertexDecoder(vertex_type); - int undecodedVertexSize = vdecoder.VertexSize(); + int undecodedVertexSize = vdecoder->VertexSize(); - const DecVtxFormat& vtxfmt = vdecoder.GetDecVtxFmt(); + const DecVtxFormat& vtxfmt = vdecoder->GetDecVtxFmt(); u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; @@ -133,7 +139,7 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int else patch.points[point] = (u8 *)control_points + undecodedVertexSize * idx; } - patch.type = (type_u | (type_v<<2)); + patch.type = (type_u | (type_v << 2)); if (patch_u != 0) patch.type &= ~START_OPEN_U; if (patch_v != 0) patch.type &= ~START_OPEN_V; if (patch_u != num_patches_u-1) patch.type &= ~END_OPEN_U; @@ -163,12 +169,10 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int u8 *v2 = patch.points[point_index+4]; u8 *v3 = patch.points[point_index+5]; - // TODO: Insert UVs where applicable. Actually subdivide. - CopyTriangle(dest, v0, v1, v2, undecodedVertexSize); - CopyTriangle(dest, v2, v1, v0, undecodedVertexSize); - CopyTriangle(dest, v2, v1, v3, undecodedVertexSize); - CopyTriangle(dest, v3, v1, v2, undecodedVertexSize); - count += 12; + // TODO: Insert UVs and normals if not present. + CopyTriangle(dest, v0, v2, v1, undecodedVertexSize); + CopyTriangle(dest, v1, v2, v3, undecodedVertexSize); + count += 6; } } } @@ -178,4 +182,18 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int SubmitPrim(decoded2, 0, GE_PRIM_TRIANGLES, count, vertTypeWithoutIndex, GE_VTYPE_IDX_NONE, 0); Flush(); -} \ No newline at end of file +} + +// TODO +void TransformDrawEngine::SubmitBezier(void* control_points, void* indices, int count_u, int count_v, GEPatchPrimType prim_type, u32 vertex_type) { + if (prim_type != GE_PATCHPRIM_TRIANGLES) { + // Only triangles supported! + return; + } + + // We're not actually going to decode, only reshuffle. + VertexDecoder vdecoder; + vdecoder.SetVertexType(vertex_type); + + Flush(); +} diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 54ec9358eb..5ce63c09d8 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -217,14 +217,14 @@ void TransformDrawEngine::ApplyDrawState(int prim) { } // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. -#if 1 - // Fixes some Persona 2 issues, may be correct? (that is, don't change dest alpha at all if blending) - // If this doesn't break anything else, it's likely to be right. - // I guess an alternative solution would be to simply disable alpha writes if alpha blending is enabled. - glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ONE); -#else - glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, glBlendFuncA, glBlendFuncB); -#endif + if (!gstate.isStencilTestEnabled()) { + // Fixes some Persona 2 issues, may be correct? (that is, don't change dest alpha at all if blending) + // If this doesn't break anything else, it's likely to be right. + // I guess an alternative solution would be to simply disable alpha writes if alpha blending is enabled. + glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, glBlendFuncB); + } else { + glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, glBlendFuncA, glBlendFuncB); + } glstate.blendEquation.set(eqLookup[blendFuncEq]); } @@ -266,7 +266,7 @@ void TransformDrawEngine::ApplyDrawState(int prim) { #if !defined(USING_GLES2) // Logic Ops - if (gstate.isLogicOpEnabled() && !gstate.isAlphaBlendEnabled()) { + if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { glstate.colorLogicOp.enable(); glstate.logicOp.set(logicOps[gstate.getLogicOp()]); } else @@ -330,7 +330,7 @@ void TransformDrawEngine::ApplyDrawState(int prim) { renderHeightFactor = renderHeight / 272.0f; } - bool throughmode = (gstate.vertType & GE_VTYPE_THROUGH_MASK) != 0; + bool throughmode = gstate.isModeThrough(); // Scissor int scissorX1 = gstate.getScissorX1(); diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 3a7b55ab4c..8ff6605b8b 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -175,8 +175,12 @@ void TextureCache::ClearNextFrame() { template inline void AttachFramebufferValid(T &entry, VirtualFramebuffer *framebuffer) { - entry->framebuffer = framebuffer; - entry->invalidHint = 0; + const bool hasInvalidFramebuffer = entry->framebuffer == 0 || entry->invalidHint == -1; + const bool hasOlderFramebuffer = entry->framebuffer->last_frame_render < framebuffer->last_frame_render; + if (hasInvalidFramebuffer || hasOlderFramebuffer) { + entry->framebuffer = framebuffer; + entry->invalidHint = 0; + } } template @@ -191,10 +195,11 @@ inline void TextureCache::AttachFramebuffer(TexCacheEntry *entry, u32 address, V // If they match exactly, it's non-CLUT and from the top left. if (exactMatch) { DEBUG_LOG(HLE, "Render to texture detected at %08x!", address); - if (!entry->framebuffer) { + if (!entry->framebuffer || entry->invalidHint == -1) { if (entry->format != framebuffer->format) { WARN_LOG_REPORT_ONCE(diffFormat1, HLE, "Render to texture with different formats %d != %d", entry->format, framebuffer->format); // If it already has one, let's hope that one is correct. + // Affected game list : Kurohyou 2, Evangelion Jo AttachFramebufferInvalid(entry, framebuffer); } else { AttachFramebufferValid(entry, framebuffer); @@ -212,10 +217,12 @@ inline void TextureCache::AttachFramebuffer(TexCacheEntry *entry, u32 address, V if (framebuffer->format != entry->format) { WARN_LOG_REPORT_ONCE(diffFormat2, HLE, "Render to texture with different formats %d != %d at %08x", entry->format, framebuffer->format, address); // TODO: Use an FBO to translate the palette? + // Affected game List : DBZ VS Tag , 3rd birthday AttachFramebufferValid(entry, framebuffer); } else if ((entry->addr - address) / entry->bufw < framebuffer->height) { WARN_LOG_REPORT_ONCE(subarea, HLE, "Render to area containing texture at %08x", address); // TODO: Keep track of the y offset. + // Affected game List : God of War Ghost of Sparta , Tactic Orge , Sword Art Online AttachFramebufferValid(entry, framebuffer); } } @@ -241,12 +248,17 @@ void TextureCache::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffe switch (msg) { case NOTIFY_FB_CREATED: case NOTIFY_FB_UPDATED: + // Ensure it's in the framebuffer cache. + if (std::find(fbCache_.begin(), fbCache_.end(), framebuffer) == fbCache_.end()) { + fbCache_.push_back(framebuffer); + } for (auto it = cache.lower_bound(cacheKey), end = cache.upper_bound(cacheKeyEnd); it != end; ++it) { AttachFramebuffer(&it->second, address | 0x04000000, framebuffer, it->first == cacheKey); } break; case NOTIFY_FB_DESTROYED: + fbCache_.erase(std::remove(fbCache_.begin(), fbCache_.end(), framebuffer), fbCache_.end()); for (auto it = cache.lower_bound(cacheKey), end = cache.upper_bound(cacheKeyEnd); it != end; ++it) { DetachFramebuffer(&it->second, address | 0x04000000, framebuffer); } @@ -254,13 +266,6 @@ void TextureCache::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffe } } -static u32 GetClutIndex(u32 index) { - const u32 clutBase = gstate.getClutIndexStartPos(); - const u32 clutMask = gstate.getClutIndexMask(); - const u8 clutShift = gstate.getClutIndexShift(); - return ((index >> clutShift) & clutMask) | clutBase; -} - void *TextureCache::UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u32 level) { const u32 rowWidth = (bytesPerPixel > 0) ? (bufw * bytesPerPixel) : (bufw / 2); const u32 pitch = rowWidth / 4; @@ -346,7 +351,7 @@ inline void DeIndexTexture(ClutT *dest, const IndexT *indexed, int length, const } } else { for (int i = 0; i < length; ++i) { - *dest++ = clut[GetClutIndex(*indexed++)]; + *dest++ = clut[gstate.transformClutIndex(*indexed++)]; } } } @@ -371,8 +376,8 @@ inline void DeIndexTexture4(ClutT *dest, const u8 *indexed, int length, const Cl } else { for (int i = 0; i < length; i += 2) { u8 index = *indexed++; - dest[i + 0] = clut[GetClutIndex((index >> 0) & 0xf)]; - dest[i + 1] = clut[GetClutIndex((index >> 4) & 0xf)]; + dest[i + 0] = clut[gstate.transformClutIndex((index >> 0) & 0xf)]; + dest[i + 1] = clut[gstate.transformClutIndex((index >> 4) & 0xf)]; } } } @@ -424,7 +429,7 @@ void *TextureCache::readIndexedTex(int level, u32 texaddr, int bytesPerIndex, GL tmpTexBuf16.resize(std::max(bufw, w) * h); tmpTexBufRearrange.resize(std::max(bufw, w) * h); const u16 *clut = GetCurrentClut(); - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { switch (bytesPerIndex) { case 1: DeIndexTexture(tmpTexBuf16.data(), texaddr, length, clut); @@ -464,7 +469,7 @@ void *TextureCache::readIndexedTex(int level, u32 texaddr, int bytesPerIndex, GL tmpTexBuf32.resize(std::max(bufw, w) * h); tmpTexBufRearrange.resize(std::max(bufw, w) * h); const u32 *clut = GetCurrentClut(); - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { switch (bytesPerIndex) { case 1: DeIndexTexture(tmpTexBuf32.data(), texaddr, length, clut); @@ -550,8 +555,8 @@ static const GLuint MagFiltGL[2] = { void TextureCache::UpdateSamplingParams(TexCacheEntry &entry, bool force) { int minFilt = gstate.texfilter & 0x7; int magFilt = (gstate.texfilter>>8) & 1; - bool sClamp = gstate.texwrap & 1; - bool tClamp = (gstate.texwrap>>8) & 1; + bool sClamp = gstate.isTexCoordClampedS(); + bool tClamp = gstate.isTexCoordClampedT(); bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001 || (gstate.texlevel & 0xFFFFFF) == 0x100001 ; // Fix texlevel at 0 @@ -873,8 +878,8 @@ inline bool TextureCache::TexCacheEntry::Matches(u16 dim2, u8 format2, int maxLe } void TextureCache::LoadClut() { - u32 clutAddr = ((gstate.clutaddr & 0xFFFFFF) | ((gstate.clutaddrupper << 8) & 0x0F000000)); - clutTotalBytes_ = (gstate.loadclut & 0x3f) * 32; + u32 clutAddr = gstate.getClutAddress(); + clutTotalBytes_ = gstate.getClutLoadBytes(); if (Memory::IsValidAddress(clutAddr)) { Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, clutTotalBytes_); } else { @@ -976,6 +981,34 @@ bool SetDebugTexture() { } #endif +void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) +{ + entry->framebuffer->usageFlags |= FB_USAGE_TEXTURE; + bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + if (useBufferedRendering) { + // For now, let's not bind FBOs that we know are off (invalidHint will be -1.) + // But let's still not use random memory. + if (entry->framebuffer->fbo && entry->invalidHint != -1) { + fbo_bind_color_as_texture(entry->framebuffer->fbo, 0); + // Keep the framebuffer alive. + // TODO: Dangerous if it sets a new one? + entry->framebuffer->last_frame_used = gpuStats.numFlips; + } else { + glBindTexture(GL_TEXTURE_2D, 0); + gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; + } + UpdateSamplingParams(*entry, false); + gstate_c.curTextureWidth = entry->framebuffer->width; + gstate_c.curTextureHeight = entry->framebuffer->height; + gstate_c.flipTexture = true; + gstate_c.textureFullAlpha = entry->framebuffer->format == GE_FORMAT_565; + } else { + if (entry->framebuffer->fbo) + entry->framebuffer->fbo = 0; + glBindTexture(GL_TEXTURE_2D, 0); + } +} + void TextureCache::SetTexture() { #ifdef DEBUG_TEXTURES if (SetDebugTexture()) { @@ -1026,33 +1059,14 @@ void TextureCache::SetTexture() { TexCacheEntry *entry = NULL; gstate_c.flipTexture = false; gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; - bool useBufferedRendering = g_Config.iRenderingMode != 0 ? 1 : 0; + bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; bool replaceImages = false; if (iter != cache.end()) { entry = &iter->second; // Check for FBO - slow! if (entry->framebuffer) { - entry->framebuffer->usageFlags |= FB_USAGE_TEXTURE; - if (useBufferedRendering) { - // For now, let's not bind FBOs that we know are off (invalidHint will be -1.) - // But let's still not use random memory. - if (entry->framebuffer->fbo && entry->invalidHint != -1) { - fbo_bind_color_as_texture(entry->framebuffer->fbo, 0); - } else { - glBindTexture(GL_TEXTURE_2D, 0); - gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - } - UpdateSamplingParams(*entry, false); - gstate_c.curTextureWidth = entry->framebuffer->width; - gstate_c.curTextureHeight = entry->framebuffer->height; - gstate_c.flipTexture = true; - gstate_c.textureFullAlpha = entry->framebuffer->format == GE_FORMAT_565; - } else { - if (entry->framebuffer->fbo) - entry->framebuffer->fbo = 0; - glBindTexture(GL_TEXTURE_2D, 0); - } + SetTextureFramebuffer(entry); lastBoundTexture = -1; entry->lastFrame = gpuStats.numFlips; return; @@ -1198,6 +1212,31 @@ void TextureCache::SetTexture() { gstate_c.curTextureWidth = w; gstate_c.curTextureHeight = h; + // Before we go reading the texture from memory, let's check for render-to-texture. + for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { + auto framebuffer = fbCache_[i]; + // This is a rough heuristic, because sometimes our framebuffers are too tall. + static const u32 MAX_SUBAREA_Y_OFFSET = 32; + + // Must be in VRAM so | 0x04000000 it is. + const u64 cacheKeyStart = (u64)(framebuffer->fb_address | 0x04000000) << 32; + // If it has a clut, those are the low 32 bits, so it'll be inside this range. + // Also, if it's a subsample of the buffer, it'll also be within the FBO. + const u64 cacheKeyEnd = cacheKeyStart + ((u64)(framebuffer->fb_stride * MAX_SUBAREA_Y_OFFSET) << 32); + + if (cachekey >= cacheKeyStart && cachekey < cacheKeyEnd) { + AttachFramebuffer(entry, framebuffer->fb_address, framebuffer, cachekey == cacheKeyStart); + } + } + + // If we ended up with a framebuffer, attach it - no texture decoding needed. + if (entry->framebuffer) { + SetTextureFramebuffer(entry); + lastBoundTexture = -1; + entry->lastFrame = gpuStats.numFlips; + return; + } + if (!replaceImages) { glGenTextures(1, &entry->texture); } @@ -1213,8 +1252,9 @@ void TextureCache::SetTexture() { break; } } - if (g_Config.bMipMap) { -#ifdef USING_GLES2 + + if (g_Config.bMipMap) { + // GLES2 doesn't have support for a "Max lod" which is critical as PSP games often // don't specify mips all the way down. As a result, we either need to manually generate // the bottom few levels or rely on OpenGL's autogen mipmaps instead, which might not @@ -1226,13 +1266,13 @@ void TextureCache::SetTexture() { LoadTextureLevel(*entry, 0, replaceImages); if (maxLevel > 0) glGenerateMipmap(GL_TEXTURE_2D); -#else + /* for (int i = 0; i <= maxLevel; i++) { LoadTextureLevel(*entry, i, replaceImages); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxLevel); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel); -#endif + */ } else { LoadTextureLevel(*entry, 0, replaceImages); #ifndef USING_GLES2 @@ -1285,7 +1325,7 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c tmpTexBufRearrange.resize(std::max(bufw, w) * h); const u16 *clut = GetCurrentClut() + clutSharingOffset; texByteAlign = 2; - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { if (clutAlphaLinear_ && mipmapShareClut) { DeIndexTexture4Optimal(tmpTexBuf16.data(), texaddr, bufw * h, clutAlphaLinearColor_); } else { @@ -1309,7 +1349,7 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c tmpTexBuf32.resize(std::max(bufw, w) * h); tmpTexBufRearrange.resize(std::max(bufw, w) * h); const u32 *clut = GetCurrentClut() + clutSharingOffset; - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { DeIndexTexture4(tmpTexBuf32.data(), texaddr, bufw * h, clut); finalBuf = tmpTexBuf32.data(); } else { @@ -1366,7 +1406,7 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c dstFmt = GL_UNSIGNED_SHORT_5_6_5; texByteAlign = 2; - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { int len = std::max(bufw, w) * h; tmpTexBuf16.resize(len); tmpTexBufRearrange.resize(len); @@ -1383,7 +1423,7 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c if (bufw < 4) bufw = 4; dstFmt = GL_UNSIGNED_BYTE; - if (!(gstate.texmode & 1)) { + if (!gstate.isTextureSwizzled()) { // Special case: if we don't need to deal with packing, we don't need to copy. if (w == bufw) { finalBuf = Memory::GetPointer(texaddr); diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index e771f0a3ca..bf7e58c573 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -126,12 +126,14 @@ private: void UpdateCurrentClut(); void AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, bool exactMatch); void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer); + void SetTextureFramebuffer(TexCacheEntry *entry); TexCacheEntry *GetEntryAt(u32 texaddr); typedef std::map TexCache; TexCache cache; TexCache secondCache; + std::vector fbCache_; bool clearCacheNextFrame_; bool lowMemoryMode_; diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index cac49d7f9d..4f0b0ddbb8 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -65,7 +65,7 @@ inline float clamp(float in, float min, float max) { TransformDrawEngine::TransformDrawEngine() : collectedVerts(0), - prevPrim_(-1), + prevPrim_(GE_PRIM_INVALID), dec_(0), lastVType_(-1), curVbo_(0), @@ -150,7 +150,7 @@ private: }; Lighter::Lighter() { - doShadeMapping_ = (gstate.texmapmode & 0x3) == 2; + doShadeMapping_ = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP; materialEmissive.GetFromRGB(gstate.materialemissive); materialEmissive.a = 0.0f; globalAmbient.GetFromRGB(gstate.ambientcolor); @@ -604,7 +604,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( source = Vec3f(norm).Normalized(); } else { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); - source = Vec3f::AssignToAll(0.0f); + source = Vec3f(0.0f, 0.0f, 1.0f); } break; case GE_PROJMAP_NORMAL: // Use non-normalized normal as source! @@ -612,7 +612,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( source = Vec3f(norm); } else { ERROR_LOG_REPORT(G3D, "Normal projection mapping without normal?"); - source = Vec3f::AssignToAll(0.0f); + source = Vec3f(0.0f, 0.0f, 1.0f); } break; } @@ -677,16 +677,17 @@ void TransformDrawEngine::SoftwareTransformAndDraw( ((clearColor & 0xFF0000) >> 16) / 255.0f, ((clearColor & 0xFF000000) >> 24) / 255.0f, }; - int target = 0; - if ((gstate.clearmode >> 8) & 3) target |= GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - if ((gstate.clearmode >> 10) & 1) target |= GL_DEPTH_BUFFER_BIT; - bool colorMask = (gstate.clearmode >> 8) & 1; - bool alphaMask = (gstate.clearmode >> 9) & 1; + bool colorMask = gstate.isClearModeColorMask(); + bool alphaMask = gstate.isClearModeAlphaMask(); glstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask); glstate.stencilTest.set(false); glstate.scissorTest.set(false); - bool depthMask = (gstate.clearmode >> 10) & 1; + bool depthMask = gstate.isClearModeDepthMask(); + + int target = 0; + if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + if (depthMask) target |= GL_DEPTH_BUFFER_BIT; glClearColor(col[0], col[1], col[2], col[3]); #ifdef USING_GLES2 @@ -829,7 +830,7 @@ int TransformDrawEngine::EstimatePerVertexCost() { return cost; } -void TransformDrawEngine::SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertType, int forceIndexType, int *bytesRead) { +void TransformDrawEngine::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int forceIndexType, int *bytesRead) { if (vertexCount == 0) return; // we ignore zero-sized draw calls. @@ -1030,7 +1031,7 @@ void TransformDrawEngine::DoFlush() { // This is not done on every drawcall, we should collect vertex data // until critical state changes. That's when we draw (flush). - int prim = prevPrim_; + GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); LinkedShader *program = shaderManager_->ApplyShader(prim); @@ -1138,7 +1139,7 @@ void TransformDrawEngine::DoFlush() { vbo = vai->vbo; ebo = vai->ebo; vertexCount = vai->numVerts; - prim = vai->prim; + prim = static_cast(vai->prim); break; } @@ -1157,7 +1158,7 @@ void TransformDrawEngine::DoFlush() { if (ebo) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); vertexCount = vai->numVerts; - prim = vai->prim; + prim = static_cast(vai->prim); break; } @@ -1218,5 +1219,5 @@ rotateVBO: indexGen.Reset(); collectedVerts = 0; numDrawCalls = 0; - prevPrim_ = -1; + prevPrim_ = GE_PRIM_INVALID; } diff --git a/GPU/GLES/TransformPipeline.h b/GPU/GLES/TransformPipeline.h index 7fea4f640d..306559ab44 100644 --- a/GPU/GLES/TransformPipeline.h +++ b/GPU/GLES/TransformPipeline.h @@ -56,7 +56,7 @@ public: vbo = 0; ebo = 0; numDCs = 0; - prim = -1; + prim = GE_PRIM_INVALID; numDraws = 0; numFrames = 0; lastFrame = gpuStats.numFlips; @@ -96,9 +96,12 @@ class TransformDrawEngine : public GfxResourceHolder { public: TransformDrawEngine(); virtual ~TransformDrawEngine(); - void SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertexType, int forceIndexType, int *bytesRead); + void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertexType, int forceIndexType, int *bytesRead); + void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, u32 vertex_type); + void SubmitBezier(void* control_points, void* indices, int count_u, int count_v, GEPatchPrimType prim_type, u32 vertex_type); + + // legacy void DrawBezier(int ucount, int vcount); - void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type); void DecodeVerts(); void SetShaderManager(ShaderManager *shaderManager) { @@ -157,7 +160,7 @@ private: // Vertex collector state IndexGenerator indexGen; int collectedVerts; - int prevPrim_; + GEPrimitiveType prevPrim_; // Cached vertex decoders std::map decoderMap_; diff --git a/GPU/GLES/VertexDecoder.cpp b/GPU/GLES/VertexDecoder.cpp index e912b19b11..5dc5bbcd76 100644 --- a/GPU/GLES/VertexDecoder.cpp +++ b/GPU/GLES/VertexDecoder.cpp @@ -336,7 +336,7 @@ void VertexDecoder::Step_NormalS8() const { s8 *normal = (s8 *)(decoded_ + decFmt.nrmoff); u8 xorval = 0; - if (gstate.reversenormals & 1) + if (gstate.areNormalsReversed()) xorval = 0xFF; // Using xor instead of - to handle -128 const s8 *sv = (const s8*)(ptr_ + nrmoff); for (int j = 0; j < 3; j++) @@ -348,7 +348,7 @@ void VertexDecoder::Step_NormalS16() const { s16 *normal = (s16 *)(decoded_ + decFmt.nrmoff); u16 xorval = 0; - if (gstate.reversenormals & 1) + if (gstate.areNormalsReversed()) xorval = 0xFFFF; const s16 *sv = (const s16*)(ptr_ + nrmoff); for (int j = 0; j < 3; j++) @@ -360,7 +360,7 @@ void VertexDecoder::Step_NormalFloat() const { float *normal = (float *)(decoded_ + decFmt.nrmoff); float multiplier = 1.0f; - if (gstate.reversenormals & 1) + if (gstate.areNormalsReversed()) multiplier = -multiplier; const float *fv = (const float*)(ptr_ + nrmoff); for (int j = 0; j < 3; j++) @@ -374,7 +374,7 @@ void VertexDecoder::Step_NormalS8Morph() const for (int n = 0; n < morphcount; n++) { float multiplier = gstate_c.morphWeights[n]; - if (gstate.reversenormals & 1) { + if (gstate.areNormalsReversed()) { multiplier = -multiplier; } const s8 *bv = (const s8*)(ptr_ + onesize_*n + nrmoff); @@ -391,7 +391,7 @@ void VertexDecoder::Step_NormalS16Morph() const for (int n = 0; n < morphcount; n++) { float multiplier = gstate_c.morphWeights[n]; - if (gstate.reversenormals & 1) { + if (gstate.areNormalsReversed()) { multiplier = -multiplier; } const s16 *sv = (const s16 *)(ptr_ + onesize_*n + nrmoff); @@ -408,7 +408,7 @@ void VertexDecoder::Step_NormalFloatMorph() const for (int n = 0; n < morphcount; n++) { float multiplier = gstate_c.morphWeights[n]; - if (gstate.reversenormals & 1) { + if (gstate.areNormalsReversed()) { multiplier = -multiplier; } const float *fv = (const float*)(ptr_ + onesize_*n + nrmoff); @@ -736,7 +736,7 @@ void VertexDecoder::SetVertexType(u32 fmt) { decOff += DecFmtSize(decFmt.nrmfmt); } - //if (pos) - there's always a position + if (pos) // there's always a position { size = align(size, posalign[pos]); posoff = size; @@ -764,7 +764,9 @@ void VertexDecoder::SetVertexType(u32 fmt) { } decFmt.posoff = decOff; decOff += DecFmtSize(decFmt.posfmt); - } + } else + ERROR_LOG_REPORT(G3D, "Vertices without position found") + decFmt.stride = decOff; size = align(size, biggest); diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index d7b155046c..b327ae35b4 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -60,7 +60,7 @@ void ComputeVertexShaderID(VertexShaderID *id, int prim, bool useHWTransform) { bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0; bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0; - bool hasBones = gstate.getWeightMask() != 0; + bool hasBones = gstate.getWeightMask() != GE_VTYPE_WEIGHT_NONE; bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear(); bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); @@ -229,14 +229,13 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { WRITE(p, "uniform vec3 u_lightpos%i;\n", i); } if (doLight[i] == LIGHT_FULL) { - // These are needed for the full thing - WRITE(p, "uniform mediump vec3 u_lightdir%i;\n", i); GELightType type = gstate.getLightType(i); if (type != GE_LIGHTTYPE_DIRECTIONAL) WRITE(p, "uniform mediump vec3 u_lightatt%i;\n", i); if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { + WRITE(p, "uniform mediump vec3 u_lightdir%i;\n", i); WRITE(p, "uniform mediump float u_lightangle%i;\n", i); WRITE(p, "uniform mediump float u_lightspotCoef%i;\n", i); } @@ -449,6 +448,10 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { if (poweredDiffuse) { WRITE(p, " mediump float dot%i = pow(dot(toLight, worldnormal), u_matspecular.a);\n", i); + // Ugly NaN check. pow(0.0, 0.0) may be undefined, but PSP seems to treat it as 1.0. + // Seen in Tales of the World: Radiant Mythology (#2424.) + WRITE(p, " if (!(dot%i < 1.0) && !(dot%i > 0.0))\n", i, i); + WRITE(p, " dot%i = 1.0;\n", i); } else { WRITE(p, " mediump float dot%i = dot(toLight, worldnormal);\n", i); } diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index b0bb844084..b52a49b484 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -26,26 +26,26 @@ StaticLibrary true - MultiByte + Unicode false StaticLibrary true - MultiByte + Unicode false StaticLibrary false false - MultiByte + Unicode StaticLibrary false false - MultiByte + Unicode diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d2b5f2bd75..16541e302e 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -11,6 +11,7 @@ #include "Core/Host.h" #include "Core/Reporting.h" #include "Core/HLE/sceKernelMemory.h" +#include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceGe.h" GPUCommon::GPUCommon() : @@ -60,7 +61,13 @@ u32 GPUCommon::DrawSync(int mode) { return SCE_KERNEL_ERROR_INVALID_MODE; if (mode == 0) { - // TODO: What if dispatch / interrupts disabled? + if (!__KernelIsDispatchEnabled()) { + return SCE_KERNEL_ERROR_CAN_NOT_WAIT; + } + if (__IsInInterrupt()) { + return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; + } + if (drawCompleteTicks > CoreTiming::GetTicks()) { __GeWaitCurrentThread(WAITTYPE_GEDRAWSYNC, 1, "GeDrawSync"); } else { @@ -137,6 +144,13 @@ int GPUCommon::ListSync(int listid, int mode) { } } + if (!__KernelIsDispatchEnabled()) { + return SCE_KERNEL_ERROR_CAN_NOT_WAIT; + } + if (__IsInInterrupt()) { + return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; + } + if (dl.waitTicks > CoreTiming::GetTicks()) { __GeWaitCurrentThread(WAITTYPE_GELISTSYNC, listid, "GeListSync"); } @@ -173,13 +187,13 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) { // return 0x80000021; //} } - if (dls[i].state == PSP_GE_DL_STATE_NONE) + if (dls[i].state == PSP_GE_DL_STATE_NONE && !dls[i].pendingInterrupt) { // Prefer a list that isn't used id = i; break; } - if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && dls[i].waitTicks < currentTicks) + if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && !dls[i].pendingInterrupt && dls[i].waitTicks < currentTicks) { id = i; } @@ -566,7 +580,7 @@ void GPUCommon::ProcessEvent(GPUEvent ev) { break; default: - ERROR_LOG(G3D, "Unexpected GPU event type: %d", (int)ev); + ERROR_LOG_REPORT(G3D, "Unexpected GPU event type: %d", (int)ev); } } @@ -590,9 +604,10 @@ void GPUCommon::ProcessDLQueueInternal() { cyclesExecuted = 0; UpdateTickEstimate(std::max(busyTicks, startingTicks + cyclesExecuted)); + // Seems to be correct behaviour to process the list anyway? if (startingTicks < busyTicks) { DEBUG_LOG(HLE, "Can't execute a list yet, still busy for %lld ticks", busyTicks - startingTicks); - return; + //return; } for (int listIndex = GetNextListIndex(); listIndex != -1; listIndex = GetNextListIndex()) { @@ -791,8 +806,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { } // TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe? if (currentList->interruptsEnabled && trigger) { - if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) + if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; UpdateState(GPUSTATE_INTERRUPT); + } } } break; @@ -800,8 +817,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { switch (currentList->signal) { case PSP_GE_SIGNAL_HANDLER_PAUSE: if (currentList->interruptsEnabled) { - if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) + if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; UpdateState(GPUSTATE_INTERRUPT); + } } break; @@ -814,7 +833,9 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) { currentList->subIntrToken = prev & 0xFFFF; currentList->state = PSP_GE_DL_STATE_COMPLETED; UpdateState(GPUSTATE_DONE); - if (!currentList->interruptsEnabled || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + if (currentList->interruptsEnabled && __GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) { + currentList->pendingInterrupt = true; + } else { currentList->waitTicks = startingTicks + cyclesExecuted; busyTicks = std::max(busyTicks, currentList->waitTicks); __GeTriggerSync(WAITTYPE_GELISTSYNC, currentList->id, currentList->waitTicks); @@ -852,8 +873,6 @@ void GPUCommon::DoState(PointerWrap &p) { currentList = &dls[currentID]; } p.Do(interruptRunning); - u32 prev; // TODO: kill. just didn't want to break states right now... - p.Do(prev); p.Do(gpuState); p.Do(isbreak); p.Do(drawCompleteTicks); @@ -870,6 +889,7 @@ void GPUCommon::InterruptEnd(int listid) { isbreak = false; DisplayList &dl = dls[listid]; + dl.pendingInterrupt = false; // TODO: Unless the signal handler could change it? if (dl.state == PSP_GE_DL_STATE_COMPLETED || dl.state == PSP_GE_DL_STATE_NONE) { dl.waitTicks = 0; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 0776279bfb..5089423b69 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -129,6 +129,7 @@ struct DisplayList bool interrupted; u64 waitTicks; bool interruptsEnabled; + bool pendingInterrupt; }; enum GPUInvalidationType { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index f63424d31a..a595d61f2d 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -225,15 +225,19 @@ struct GPUgstate bool isClearModeDepthWriteEnabled() const { return (clearmode&0x400) != 0; } bool isClearModeColorMask() const { return (clearmode&0x100) != 0; } bool isClearModeAlphaMask() const { return (clearmode&0x200) != 0; } + bool isClearModeDepthMask() const { return (clearmode&0x400) != 0; } u32 getClearModeColorMask() const { return ((clearmode&0x100) ? 0xFFFFFF : 0) | ((clearmode&0x200) ? 0xFF000000 : 0); } // TODO: Different convention than getColorMask, confusing! // Blend - int getBlendFuncA() const { return blend & 0xF; } + GEBlendSrcFactor getBlendFuncA() const { return (GEBlendSrcFactor)(blend & 0xF); } u32 getFixA() const { return blendfixa & 0xFFFFFF; } u32 getFixB() const { return blendfixb & 0xFFFFFF; } - int getBlendFuncB() const { return (blend >> 4) & 0xF; } + GEBlendDstFactor getBlendFuncB() const { return (GEBlendDstFactor)((blend >> 4) & 0xF); } int getBlendEq() const { return (blend >> 8) & 0x7; } bool isAlphaBlendEnabled() const { return alphaBlendEnable & 1; } + + // AntiAlias + bool isAntiAliasEnabled() const { return antiAliasEnable & 1; } // Dither bool isDitherEnabled() const { return ditherEnable & 1; } @@ -283,11 +287,15 @@ struct GPUgstate int getTextureEnvColR() const { return texenvcolor&0xFF; } int getTextureEnvColG() const { return (texenvcolor>>8)&0xFF; } int getTextureEnvColB() const { return (texenvcolor>>16)&0xFF; } + u32 getClutAddress() const { return (clutaddr & 0x00FFFFFF) | ((clutaddrupper << 8) & 0x0F000000); } + int getClutLoadBytes() const { return (loadclut & 0x3F) * 32; } GEPaletteFormat getClutPaletteFormat() { return static_cast(clutformat & 3); } int getClutIndexShift() const { return (clutformat >> 2) & 0x1F; } int getClutIndexMask() const { return (clutformat >> 8) & 0xFF; } int getClutIndexStartPos() const { return ((clutformat >> 16) & 0x1F) << 4; } + int transformClutIndex(int index) const { return ((index >> getClutIndexShift()) & getClutIndexMask()) | getClutIndexStartPos(); } bool isClutIndexSimple() const { return (clutformat & ~3) == 0xC500FF00; } // Meaning, no special mask, shift, or start pos. + bool isTextureSwizzled() const { return texmode & 1; } // Lighting bool isLightingEnabled() const { return lightingEnable & 1; } @@ -352,9 +360,24 @@ struct GPUgstate int getWeightMask() const { return vertType & GE_VTYPE_WEIGHT_MASK; } int getNumBoneWeights() const { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); } bool isSkinningEnabled() const { return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); } + int getTexCoordMask() const { return vertType & GE_VTYPE_TC_MASK; } + bool areNormalsReversed() const { return reversenormals & 1; } GEPatchPrimType getPatchPrimitiveType() const { return static_cast(patchprimitive & 3); } + // Transfers + u32 getTransferSrcAddress() const { return (transfersrc & 0xFFFFF0) | ((transfersrcw & 0xFF0000) << 8); } + u32 getTransferSrcStride() const { return transfersrcw & 0x3F8; } + int getTransferSrcX() const { return (transfersrcpos >> 0) & 0x3FF; } + int getTransferSrcY() const { return (transfersrcpos >> 10) & 0x3FF; } + u32 getTransferDstAddress() const { return (transferdst & 0xFFFFF0) | ((transferdstw & 0xFF0000) << 8); } + u32 getTransferDstStride() const { return transferdstw & 0x3F8; } + int getTransferDstX() const { return (transferdstpos >> 0) & 0x3FF; } + int getTransferDstY() const { return (transferdstpos >> 10) & 0x3FF; } + int getTransferWidth() const { return ((transfersize >> 0) & 0x3FF) + 1; } + int getTransferHeight() const { return ((transfersize >> 10) & 0x3FF) + 1; } + int getTransferBpp() const { return (transferstart & 1) ? 4 : 2; } + // Real data in the context ends here }; @@ -429,6 +452,8 @@ struct GPUStatistics { numShaderSwitches = 0; numFlushes = 0; numTexturesDecoded = 0; + numAlphaTestedDraws = 0; + numNonAlphaTestedDraws = 0; msProcessingDisplayLists = 0; vertexGPUCycles = 0; otherGPUCycles = 0; @@ -452,6 +477,9 @@ struct GPUStatistics { int otherGPUCycles; int gpuCommandsAtCallLevel[4]; + int numAlphaTestedDraws; + int numNonAlphaTestedDraws; + // Total statistics, updated by the GPU core in UpdateStats int numVBlanks; int numFlips; diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index e7e34f7864..8c4b92aeeb 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -437,7 +437,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { case GE_CMD_TRANSFERSRC: { - sprintf(buffer, "Block transfer src: %06x", data); + if (data & 0xF) + sprintf(buffer, "Block transfer src: %06x (extra: %x)", data & ~0xF, data & 0xF); + else + sprintf(buffer, "Block transfer src: %06x", data); // Nothing to do, the next one prints } break; @@ -445,7 +448,7 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { case GE_CMD_TRANSFERSRCW: { u32 xferSrc = (gstate.transfersrc & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferSrcW = gstate.transfersrcw & 1023; + u32 xferSrcW = data & 0x3FF; if (data & ~0xFF03FF) sprintf(buffer, "Block transfer src: %08x W: %i (extra %x)", xferSrc, xferSrcW, data); else @@ -456,14 +459,17 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { case GE_CMD_TRANSFERDST: { // Nothing to do, the next one prints - sprintf(buffer, "Block transfer dst: %06x", data); + if (data & 0xF) + sprintf(buffer, "Block transfer dst: %06x (extra: %x)", data & ~0xF, data & 0xF); + else + sprintf(buffer, "Block transfer dst: %06x", data); } break; case GE_CMD_TRANSFERDSTW: { u32 xferDst = (gstate.transferdst & 0x00FFFFFF) | ((data & 0xFF0000) << 8); - u32 xferDstW = gstate.transferdstw & 1023; + u32 xferDstW = data & 0x3FF; if (data & ~0xFF03FF) sprintf(buffer, "Block transfer dest: %08x W: %i (extra %x)", xferDst, xferDstW, data); else @@ -505,10 +511,10 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) { } case GE_CMD_TRANSFERSTART: // Orphis calls this TRXKICK - if (data) - sprintf(buffer, "Block transfer start: %x", data); + if (data & ~1) + sprintf(buffer, "Block transfer start: %d (extra %x)", data & 1, data & ~1); else - sprintf(buffer, "Block transfer start"); + sprintf(buffer, "Block transfer start: %d", data); break; case GE_CMD_TEXSIZE0: diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 3543ad37b1..58c02dbe66 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -265,7 +265,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_LOADCLUT: // This could be used to "dirty" textures with clut. { - u32 clutAddr = ((gstate.clutaddrupper & 0xFF0000)<<8) | (gstate.clutaddr & 0xFFFFFF); + u32 clutAddr = gstate.getClutAddress(); if (clutAddr) { DEBUG_LOG(G3D,"DL Clut load: %08x", clutAddr); @@ -282,8 +282,8 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_TRANSFERSRCW: { - u32 xferSrc = gstate.transfersrc | ((data&0xFF0000)<<8); - u32 xferSrcW = gstate.transfersrcw & 1023; + u32 xferSrc = (gstate.transfersrc & 0x00FFFFFF) | ((data & 0xFF0000) << 8); + u32 xferSrcW = data & 0x3FF; DEBUG_LOG(G3D,"Block Transfer Src: %08x W: %i", xferSrc, xferSrcW); break; } @@ -291,8 +291,8 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_TRANSFERDSTW: { - u32 xferDst= gstate.transferdst | ((data&0xFF0000)<<8); - u32 xferDstW = gstate.transferdstw & 1023; + u32 xferDst = (gstate.transferdst & 0x00FFFFFF) | ((data & 0xFF0000) << 8); + u32 xferDstW = data & 0x3FF; DEBUG_LOG(G3D,"Block Transfer Dest: %08x W: %i", xferDst, xferDstW); break; } diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 62a9137d12..d571ebb84c 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -15,11 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "../../Core/MemMap.h" -#include "../GPUState.h" +#include "Core/MemMap.h" +#include "Core/Reporting.h" +#include "GPU/GPUState.h" -#include "Rasterizer.h" -#include "Colors.h" +#include "GPU/Software/Rasterizer.h" +#include "GPU/Software/Colors.h" extern u8* fb; extern u8* depthbuf; @@ -46,7 +47,7 @@ static inline int orient2dIncY(int dX01) static inline int GetPixelDataOffset(unsigned int texel_size_bits, unsigned int row_pitch_bits, unsigned int u, unsigned int v) { - if (!(gstate.texmode & 1)) + if (!gstate.isTextureSwizzled()) return v * row_pitch_bits *texel_size_bits/8 / 8 + u * texel_size_bits / 8; int tile_size_bits = 32; @@ -72,31 +73,24 @@ static inline u32 LookupColor(unsigned int index, unsigned int level) // TODO: No idea if these bswaps are correct switch (gstate.getClutPaletteFormat()) { - case GE_TFMT_5650: - return DecodeRGB565(reinterpret_cast(clut)[index + clutSharingOffset]); + case GE_TFMT_5650: + return DecodeRGB565(reinterpret_cast(clut)[index + clutSharingOffset]); - case GE_TFMT_5551: - return DecodeRGBA5551(reinterpret_cast(clut)[index + clutSharingOffset]); + case GE_TFMT_5551: + return DecodeRGBA5551(reinterpret_cast(clut)[index + clutSharingOffset]); - case GE_TFMT_4444: - return DecodeRGBA4444(reinterpret_cast(clut)[index + clutSharingOffset]); + case GE_TFMT_4444: + return DecodeRGBA4444(reinterpret_cast(clut)[index + clutSharingOffset]); - case GE_TFMT_8888: - return DecodeRGBA8888(clut[index + clutSharingOffset]); + case GE_TFMT_8888: + return DecodeRGBA8888(clut[index + clutSharingOffset]); - default: - ERROR_LOG(G3D, "Unsupported palette format: %x", gstate.getClutPaletteFormat()); - return 0; + default: + ERROR_LOG_REPORT(G3D, "Software: Unsupported palette format: %x", gstate.getClutPaletteFormat()); + return 0; } } -static inline u32 GetClutIndex(u32 index) { - const u32 clutBase = gstate.getClutIndexStartPos(); - const u32 clutMask = gstate.getClutIndexMask(); - const u8 clutShift = gstate.getClutIndexShift(); - return ((index >> clutShift) & clutMask) | clutBase; -} - static inline void GetTexelCoordinates(int level, float s, float t, unsigned int& u, unsigned int& v) { s *= getFloat24(gstate.texscaleu); @@ -130,31 +124,41 @@ static inline void GetTexelCoordinates(int level, float s, float t, unsigned int static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const VertexData& v2, int w0, int w1, int w2, float& s, float& t) { - if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN || gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP) { - // TODO: What happens if vertex has no texture coordinates? - // Note that for environment mapping, texture coordinates have been calculated during lighting - float q0 = 1.f / v0.clippos.w; - float q1 = 1.f / v1.clippos.w; - float q2 = 1.f / v2.clippos.w; - float q = q0 * w0 + q1 * w1 + q2 * w2; - s = (v0.texturecoords.s() * q0 * w0 + v1.texturecoords.s() * q1 * w1 + v2.texturecoords.s() * q2 * w2) / q; - t = (v0.texturecoords.t() * q0 * w0 + v1.texturecoords.t() * q1 * w1 + v2.texturecoords.t() * q2 * w2) / q; - } else if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) { - // projection mapping, TODO: Move this code to TransformUnit! - Vec3 source; - if (gstate.getUVProjMode() == GE_PROJMAP_POSITION) { - source = ((v0.modelpos * w0 + v1.modelpos * w1 + v2.modelpos * w2) / (w0+w1+w2)); - } else { - ERROR_LOG(G3D, "Unsupported UV projection mode %x", gstate.getUVProjMode()); + switch (gstate.getUVGenMode()) { + case GE_TEXMAP_TEXTURE_COORDS: + case GE_TEXMAP_UNKNOWN: + case GE_TEXMAP_ENVIRONMENT_MAP: + { + // TODO: What happens if vertex has no texture coordinates? + // Note that for environment mapping, texture coordinates have been calculated during lighting + float q0 = 1.f / v0.clippos.w; + float q1 = 1.f / v1.clippos.w; + float q2 = 1.f / v2.clippos.w; + float q = q0 * w0 + q1 * w1 + q2 * w2; + s = (v0.texturecoords.s() * q0 * w0 + v1.texturecoords.s() * q1 * w1 + v2.texturecoords.s() * q2 * w2) / q; + t = (v0.texturecoords.t() * q0 * w0 + v1.texturecoords.t() * q1 * w1 + v2.texturecoords.t() * q2 * w2) / q; } + break; + case GE_TEXMAP_TEXTURE_MATRIX: + { + // projection mapping, TODO: Move this code to TransformUnit! + Vec3 source; + if (gstate.getUVProjMode() == GE_PROJMAP_POSITION) { + source = ((v0.modelpos * w0 + v1.modelpos * w1 + v2.modelpos * w2) / (w0+w1+w2)); + } else { + ERROR_LOG_REPORT(G3D, "Software: Unsupported UV projection mode %x", gstate.getUVProjMode()); + } - Mat3x3 tgen(gstate.tgenMatrix); - Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); - s = stq.x/stq.z; - t = stq.y/stq.z; - } else { - ERROR_LOG(G3D, "Unsupported texture mapping mode %x!", gstate.getUVGenMode()); - } + Mat3x3 tgen(gstate.tgenMatrix); + Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); + s = stq.x/stq.z; + t = stq.y/stq.z; + } + break; + default: + ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode()); + break; + } } static inline u32 SampleNearest(int level, unsigned int u, unsigned int v) @@ -168,44 +172,49 @@ static inline u32 SampleNearest(int level, unsigned int u, unsigned int v) // TODO: Should probably check if textures are aligned properly... - if (texfmt == GE_TFMT_4444) { + switch (texfmt) { + case GE_TFMT_4444: srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGBA4444(*(u16*)srcptr); - } else if (texfmt == GE_TFMT_5551) { + + case GE_TFMT_5551: srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGBA5551(*(u16*)srcptr); - } else if (texfmt == GE_TFMT_5650) { + + case GE_TFMT_5650: srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGB565(*(u16*)srcptr); - } else if (texfmt == GE_TFMT_8888) { + + case GE_TFMT_8888: srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); return DecodeRGBA8888(*(u32*)srcptr); - } else if (texfmt == GE_TFMT_CLUT32) { - srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); - u32 val = srcptr[0] + (srcptr[1] << 8) + (srcptr[2] << 16) + (srcptr[3] << 24); - - return LookupColor(GetClutIndex(val), level); - } else if (texfmt == GE_TFMT_CLUT16) { - srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); - - u16 val = srcptr[0] + (srcptr[1] << 8); - - return LookupColor(GetClutIndex(val), level); - } else if (texfmt == GE_TFMT_CLUT8) { - srcptr += GetPixelDataOffset(8, texbufwidth*8, u, v); - - u8 val = *srcptr; - - return LookupColor(GetClutIndex(val), level); - } else if (texfmt == GE_TFMT_CLUT4) { - srcptr += GetPixelDataOffset(4, texbufwidth*8, u, v); - - u8 val = (u & 1) ? (srcptr[0] >> 4) : (srcptr[0] & 0xF); - - return LookupColor(GetClutIndex(val), level); - } else { - ERROR_LOG(G3D, "Unsupported texture format: %x", texfmt); + case GE_TFMT_CLUT32: + { + srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); + u32 val = srcptr[0] + (srcptr[1] << 8) + (srcptr[2] << 16) + (srcptr[3] << 24); + return LookupColor(gstate.transformClutIndex(val), level); + } + case GE_TFMT_CLUT16: + { + srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); + u16 val = srcptr[0] + (srcptr[1] << 8); + return LookupColor(gstate.transformClutIndex(val), level); + } + case GE_TFMT_CLUT8: + { + srcptr += GetPixelDataOffset(8, texbufwidth*8, u, v); + u8 val = *srcptr; + return LookupColor(gstate.transformClutIndex(val), level); + } + case GE_TFMT_CLUT4: + { + srcptr += GetPixelDataOffset(4, texbufwidth*8, u, v); + u8 val = (u & 1) ? (srcptr[0] >> 4) : (srcptr[0] & 0xF); + return LookupColor(gstate.transformClutIndex(val), level); + } + default: + ERROR_LOG_REPORT(G3D, "Software: Unsupported texture format: %x", texfmt); return 0; } } @@ -404,7 +413,7 @@ static inline Vec4 GetTextureFunctionOutput(const Vec3& prim_color_rgb Vec3 out_rgb; int out_a; - bool rgba = (gstate.texfunc & 0x100) != 0; + bool rgba = gstate.isTextureAlphaUsed(); switch (gstate.getTextureFunction()) { case GE_TEXFUNC_MODULATE: @@ -444,7 +453,9 @@ static inline Vec4 GetTextureFunctionOutput(const Vec3& prim_color_rgb break; default: - ERROR_LOG(G3D, "Unknown texture function %x", gstate.getTextureFunction()); + ERROR_LOG_REPORT(G3D, "Software: Unknown texture function %x", gstate.getTextureFunction()); + out_rgb = Vec3::AssignToAll(0); + out_a = 0; } return Vec4(out_rgb.r(), out_rgb.g(), out_rgb.b(), out_a); @@ -452,10 +463,10 @@ static inline Vec4 GetTextureFunctionOutput(const Vec3& prim_color_rgb static inline bool ColorTestPassed(Vec3 color) { - u32 mask = gstate.colormask&0xFFFFFF; - color = Vec3::FromRGB(color.ToRGB() & mask); - Vec3 ref = Vec3::FromRGB(gstate.colorref & mask); - switch (gstate.colortest & 0x3) { + const u32 mask = gstate.getColorTestMask(); + const u32 c = color.ToRGB() & mask; + const u32 ref = gstate.getColorTestRef() & mask; + switch (gstate.getColorTestFunction()) { case GE_COMP_NEVER: return false; @@ -463,21 +474,21 @@ static inline bool ColorTestPassed(Vec3 color) return true; case GE_COMP_EQUAL: - return (color.r() == ref.r() && color.g() == ref.g() && color.b() == ref.b()); + return c == ref; case GE_COMP_NOTEQUAL: - return (color.r() != ref.r() || color.g() != ref.g() || color.b() != ref.b()); + return c != ref; } return true; } static inline bool AlphaTestPassed(int alpha) { - u8 mask = (gstate.alphatest >> 16) & 0xFF; - u8 ref = (gstate.alphatest >> 8) & mask; + const u8 mask = gstate.getAlphaTestMask() & 0xFF; + const u8 ref = gstate.getAlphaTestRef() & mask; alpha &= mask; - switch (gstate.alphatest & 0x7) { + switch (gstate.getAlphaTestFunction()) { case GE_COMP_NEVER: return false; @@ -543,7 +554,7 @@ static inline Vec3 GetSourceFactor(int source_a, const Vec4& dst) return Vec4::FromRGBA(gstate.getFixA()).rgb(); default: - ERROR_LOG(G3D, "Unknown source factor %x", gstate.getBlendFuncA()); + ERROR_LOG_REPORT(G3D, "Software: Unknown source factor %x", gstate.getBlendFuncA()); return Vec3(); } } @@ -585,7 +596,7 @@ static inline Vec3 GetDestFactor(const Vec3& source_rgb, int source_a, return Vec4::FromRGBA(gstate.getFixB()).rgb(); default: - ERROR_LOG(G3D, "Unknown dest factor %x", gstate.getBlendFuncB()); + ERROR_LOG_REPORT(G3D, "Software: Unknown dest factor %x", gstate.getBlendFuncB()); return Vec3(); } } @@ -621,7 +632,7 @@ static inline Vec3 AlphaBlendingResult(const Vec3& source_rgb, int sou ::abs(source_rgb.b() - dst.b())); default: - ERROR_LOG(G3D, "Unknown blend function %x", gstate.getBlendEq()); + ERROR_LOG_REPORT(G3D, "Software: Unknown blend function %x", gstate.getBlendEq()); return Vec3(); } } @@ -726,7 +737,8 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& // TODO: Fogging // TODO: Is that the correct way to interpolate? - u16 z = (u16)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) / (w0+w1+w2)); + // Without the (u32), this causes an ICE in some versions of gcc. + u16 z = (u16)(u32)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) / (w0+w1+w2)); // Depth range test if (!gstate.isModeThrough()) @@ -750,7 +762,8 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& } // TODO: Is it safe to ignore gstate.isDepthTestEnabled() when clear mode is enabled? - if ((gstate.isDepthTestEnabled() && !gstate.isModeThrough()) || gstate.isModeClear()) { + // TODO: Verify that through mode does not disable depth testing + if (gstate.isDepthTestEnabled() || gstate.isModeClear()) { // TODO: Verify that stencil op indeed needs to be applied here even if stencil testing is disabled if (!DepthTestPassed(p.x, p.y, z)) { ApplyStencilOp(gstate.getStencilOpZFail(), p.x, p.y); diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 756fbad877..3a46ab4d39 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -192,7 +192,7 @@ void CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int dstwidth break; default: - ERROR_LOG_REPORT(G3D, "Unexpected framebuffer format: %d", gstate.FrameBufFormat()); + ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", gstate.FrameBufFormat()); } } @@ -304,12 +304,12 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) }; if (type != GE_PRIM_TRIANGLES && type != GE_PRIM_TRIANGLE_STRIP && type != GE_PRIM_TRIANGLE_FAN && type != GE_PRIM_RECTANGLES) { - ERROR_LOG(G3D, "DL DrawPrim type: %s count: %i vaddr= %08x, iaddr= %08x", type<7 ? types[type] : "INVALID", count, gstate_c.vertexAddr, gstate_c.indexAddr); + ERROR_LOG_REPORT(G3D, "Software: DL DrawPrim type: %s count: %i vaddr= %08x, iaddr= %08x", type<7 ? types[type] : "INVALID", count, gstate_c.vertexAddr, gstate_c.indexAddr); break; } if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(G3D, "Software: Bad vertex address %08x!", gstate_c.vertexAddr); break; } @@ -317,7 +317,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(G3D, "Software: Bad index address %08x!", gstate_c.indexAddr); break; } indices = Memory::GetPointer(gstate_c.indexAddr); @@ -344,7 +344,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) int sp_vtype = (data >> 18) & 0x3; if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { - ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + ERROR_LOG_REPORT(G3D, "Software: Bad vertex address %08x!", gstate_c.vertexAddr); break; } @@ -352,18 +352,18 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { - ERROR_LOG(G3D, "Bad index address %08x!", gstate_c.indexAddr); + ERROR_LOG_REPORT(G3D, "Software: Bad index address %08x!", gstate_c.indexAddr); break; } indices = Memory::GetPointer(gstate_c.indexAddr); } if (gstate.getPatchPrimitiveType() != GE_PATCHPRIM_TRIANGLES) { - ERROR_LOG(G3D, "Unsupported patch primitive %x", gstate.patchprimitive&3); + ERROR_LOG_REPORT(G3D, "Software: Unsupported patch primitive %x", gstate.patchprimitive&3); break; } - TransformUnit::SubmitSpline(control_points, indices, sp_ucount, sp_vcount, sp_utype, sp_vtype, gstate.patchprimitive&3, gstate.vertType); + TransformUnit::SubmitSpline(control_points, indices, sp_ucount, sp_vcount, sp_utype, sp_vtype, gstate.getPatchPrimitiveType(), gstate.vertType); DEBUG_LOG(G3D,"DL DRAW SPLINE: %i x %i, %i x %i", sp_ucount, sp_vcount, sp_utype, sp_vtype); } break; @@ -528,14 +528,14 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_LOADCLUT: { - u32 clutAddr = ((gstate.clutaddr & 0xFFFFF0) | ((gstate.clutaddrupper << 8) & 0xFF000000)); - u32 clutTotalBytes_ = (gstate.loadclut & 0x3f) * 32; + u32 clutAddr = gstate.getClutAddress(); + u32 clutTotalBytes = gstate.getClutLoadBytes(); if (Memory::IsValidAddress(clutAddr)) { - Memory::Memcpy(clut, clutAddr, clutTotalBytes_); + Memory::MemcpyUnchecked(clut, clutAddr, clutTotalBytes); } else { // TODO: Does this make any sense? - memset(clut, 0xFF, clutTotalBytes_); + memset(clut, 0xFF, clutTotalBytes); } if (clutAddr) @@ -549,67 +549,36 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) } break; -//case GE_CMD_TRANSFERSRC: - + // Don't need to do anything, just state for transferstart. + case GE_CMD_TRANSFERSRC: case GE_CMD_TRANSFERSRCW: - { - u32 xferSrc = gstate.transfersrc | ((data&0xFF0000)<<8); - u32 xferSrcW = gstate.transfersrcw & 1023; - DEBUG_LOG(G3D,"Block Transfer Src: %08x W: %i", xferSrc, xferSrcW); - break; - } -// case GE_CMD_TRANSFERDST: - + case GE_CMD_TRANSFERDST: case GE_CMD_TRANSFERDSTW: - { - u32 xferDst= gstate.transferdst | ((data&0xFF0000)<<8); - u32 xferDstW = gstate.transferdstw & 1023; - DEBUG_LOG(G3D,"Block Transfer Dest: %08x W: %i", xferDst, xferDstW); - break; - } - case GE_CMD_TRANSFERSRCPOS: - { - u32 x = (data & 1023)+1; - u32 y = ((data>>10) & 1023)+1; - DEBUG_LOG(G3D, "DL Block Transfer Src Rect TL: %i, %i", x, y); - break; - } - case GE_CMD_TRANSFERDSTPOS: - { - u32 x = (data & 1023)+1; - u32 y = ((data>>10) & 1023)+1; - DEBUG_LOG(G3D, "DL Block Transfer Dest Rect TL: %i, %i", x, y); - break; - } - case GE_CMD_TRANSFERSIZE: - { - u32 w = (data & 1023)+1; - u32 h = ((data>>10) & 1023)+1; - DEBUG_LOG(G3D, "DL Block Transfer Rect Size: %i x %i", w, h); - break; - } + break; case GE_CMD_TRANSFERSTART: { - u32 srcBasePtr = (gstate.transfersrc & 0xFFFFF0) | ((gstate.transfersrcw & 0xFF0000) << 8); - u32 srcStride = gstate.transfersrcw & 0x3F8; + u32 srcBasePtr = gstate.getTransferSrcAddress(); + u32 srcStride = gstate.getTransferSrcStride(); - u32 dstBasePtr = (gstate.transferdst & 0xFFFFF0) | ((gstate.transferdstw & 0xFF0000) << 8); - u32 dstStride = gstate.transferdstw & 0x3F8; + u32 dstBasePtr = gstate.getTransferDstAddress(); + u32 dstStride = gstate.getTransferDstStride(); - int srcX = gstate.transfersrcpos & 0x3FF; - int srcY = (gstate.transfersrcpos >> 10) & 0x3FF; + int srcX = gstate.getTransferSrcX(); + int srcY = gstate.getTransferSrcY(); - int dstX = gstate.transferdstpos & 0x3FF; - int dstY = (gstate.transferdstpos >> 10) & 0x3FF; + int dstX = gstate.getTransferDstX(); + int dstY = gstate.getTransferDstY(); - int width = (gstate.transfersize & 0x3FF) + 1; - int height = ((gstate.transfersize >> 10) & 0x3FF) + 1; + int width = gstate.getTransferWidth(); + int height = gstate.getTransferHeight(); - int bpp = (gstate.transferstart & 1) ? 4 : 2; + int bpp = gstate.getTransferBpp(); + + DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY); for (int y = 0; y < height; y++) { const u8 *src = Memory::GetPointer(srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp); @@ -617,7 +586,6 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) memcpy(dst, src, width * bpp); } - DEBUG_LOG(G3D, "DL Texture Transfer Start: PixFormat %i", data); break; } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index b76d8fc10c..8069bba8fe 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -102,7 +102,7 @@ static VertexData ReadVertex(VertexReader& vreader) float pos[3]; vreader.ReadPos(pos); - if (!gstate.isModeClear() && gstate.textureMapEnable && vreader.hasUV()) { + if (!gstate.isModeClear() && gstate.isTextureMapEnabled() && vreader.hasUV()) { float uv[2]; vreader.ReadUV(uv); vertex.texturecoords = Vec2(uv[0], uv[1]); @@ -113,7 +113,7 @@ static VertexData ReadVertex(VertexReader& vreader) vreader.ReadNrm(normal); vertex.normal = Vec3(normal[0], normal[1], normal[2]); - if (gstate.reversenormals & 1) + if (gstate.areNormalsReversed()) vertex.normal = -vertex.normal; } @@ -186,7 +186,7 @@ struct SplinePatch { int type; }; -void TransformUnit::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type) +void TransformUnit::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, u32 vertex_type) { VertexDecoder vdecoder; vdecoder.SetVertexType(vertex_type); diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h index 32ee05ee40..b36cfb49c0 100644 --- a/GPU/Software/TransformUnit.h +++ b/GPU/Software/TransformUnit.h @@ -115,6 +115,6 @@ public: static DrawingCoords ScreenToDrawing(const ScreenCoords& coords); static ScreenCoords DrawingToScreen(const DrawingCoords& coords); - static void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, u32 prim_type, u32 vertex_type); + static void SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, u32 vertex_type); static void SubmitPrimitive(void* vertices, void* indices, u32 prim_type, int vertex_count, u32 vertex_type); }; diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index f1dbbf4d6f..34da5d23ef 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -476,13 +476,15 @@ enum GETexProjMapMode enum GEPrimitiveType { - GE_PRIM_POINTS=0, - GE_PRIM_LINES=1, - GE_PRIM_LINE_STRIP=2, - GE_PRIM_TRIANGLES=3, - GE_PRIM_TRIANGLE_STRIP=4, - GE_PRIM_TRIANGLE_FAN=5, - GE_PRIM_RECTANGLES=6, + GE_PRIM_POINTS = 0, + GE_PRIM_LINES = 1, + GE_PRIM_LINE_STRIP = 2, + GE_PRIM_TRIANGLES = 3, + GE_PRIM_TRIANGLE_STRIP = 4, + GE_PRIM_TRIANGLE_FAN = 5, + GE_PRIM_RECTANGLES = 6, + GE_PRIM_KEEP_PREVIOUS = 7, + GE_PRIM_INVALID = -1, }; enum GELogicOp diff --git a/Qt/PPSSPP.pro b/Qt/PPSSPP.pro index 71c5041689..a430d4f93d 100755 --- a/Qt/PPSSPP.pro +++ b/Qt/PPSSPP.pro @@ -4,6 +4,7 @@ QT += core gui opengl CONFIG += mobility MOBILITY += multimedia win32: QT += multimedia +greaterThan(QT_MAJOR_VERSION,4): QT += widgets VERSION = 0.9.1 include(Settings.pri) diff --git a/Qt/QtHost.cpp b/Qt/QtHost.cpp index d79a17142f..c1ca575fd6 100644 --- a/Qt/QtHost.cpp +++ b/Qt/QtHost.cpp @@ -20,6 +20,8 @@ #include "GPU/ge_constants.h" #include "EmuThread.h" +static UI::Theme ui_theme; + const char *stateToLoad = NULL; std::string boot_filename = ""; @@ -357,6 +359,30 @@ void NativeInitGraphics() theme.checkOn = I_CHECKEDBOX; theme.checkOff = I_SQUARE; + ui_theme.uiFont = UBUNTU24; + ui_theme.uiFontSmall = UBUNTU24; + ui_theme.uiFontSmaller = UBUNTU24; + ui_theme.checkOn = I_CHECKEDBOX; + ui_theme.checkOff = I_SQUARE; + ui_theme.whiteImage = I_SOLIDWHITE; + ui_theme.sliderKnob = I_CIRCLE; + ui_theme.dropShadow4Grid = I_DROP_SHADOW; + + ui_theme.itemStyle.background = UI::Drawable(0x55000000); + ui_theme.itemStyle.fgColor = 0xFFFFFFFF; + ui_theme.itemFocusedStyle.background = UI::Drawable(0xFFedc24c); + ui_theme.itemDownStyle.background = UI::Drawable(0xFFbd9939); + ui_theme.itemDownStyle.fgColor = 0xFFFFFFFF; + ui_theme.itemDisabledStyle.background = UI::Drawable(0x55E0D4AF); + ui_theme.itemDisabledStyle.fgColor = 0xFFcccccc; + + ui_theme.buttonStyle = ui_theme.itemStyle; + ui_theme.buttonFocusedStyle = ui_theme.itemFocusedStyle; + ui_theme.buttonDownStyle = ui_theme.itemDownStyle; + ui_theme.buttonDisabledStyle = ui_theme.itemDisabledStyle; + + ui_theme.popupTitle.fgColor = 0xFFE3BE59; + ui_draw2d.Init(); ui_draw2d_front.Init(); @@ -370,6 +396,7 @@ void NativeInitGraphics() uiTexture->Bind(0); uiContext = new UIContext(); + uiContext->theme = &ui_theme; uiContext->Init(UIShader_Get(), UIShader_GetPlain(), uiTexture, &ui_draw2d, &ui_draw2d_front); screenManager->setUIContext(uiContext); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 69ad930890..d25f3dccf6 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -66,7 +66,6 @@ private: ControlMapper::ControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), action_(NONE), pspKey_(pspKey), keyName_(keyName), scrm_(scrm), refresh_(false) { - Refresh(); } @@ -79,12 +78,33 @@ void ControlMapper::Update(const InputState &input) { void ControlMapper::Refresh() { Clear(); + I18NCategory *c = GetI18NCategory("MappableControls"); + + std::map keyImages; + keyImages["Circle"] = I_CIRCLE; + keyImages["Cross"] = I_CROSS; + keyImages["Square"] = I_SQUARE; + keyImages["Triangle"] = I_TRIANGLE; + keyImages["Start"] = I_START; + keyImages["Select"] = I_SELECT; + keyImages["L"] = I_L; + keyImages["R"] = I_R; using namespace UI; LinearLayout *root = Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); - - root->Add(new Choice(keyName_, new LinearLayoutParams(200, WRAP_CONTENT)))->OnClick.Handle(this, &ControlMapper::OnReplaceAll); + + auto iter = keyImages.find(keyName_); + // First, look among images. + if (iter != keyImages.end()) { + root->Add(new Choice(iter->second, new LinearLayoutParams(200, WRAP_CONTENT)))->OnClick.Handle(this, &ControlMapper::OnReplaceAll); + } else { + // No image? Let's translate. + Choice *choice = new Choice(c->T(keyName_.c_str()), new LinearLayoutParams(200, WRAP_CONTENT)); + choice->SetCentered(true); + root->Add(choice)->OnClick.Handle(this, &ControlMapper::OnReplaceAll); + } + LinearLayout *rightColumn = root->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); rightColumn->SetSpacing(2.0f); std::vector mappings; diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 71cdf38baf..67e7a5cf4c 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -35,7 +35,7 @@ #include "UI/MiscScreens.h" #include "UI/CwCheatScreen.h" -bool enableAll = false; +static bool enableAll = false; static std::vector cheatList; extern void DrawBackground(float alpha); static CWCheatEngine *cheatEngine2; @@ -55,11 +55,11 @@ std::vector CwCheatScreen::CreateCodeList() { formattedList.push_back(cheatList[i].substr(4)); enableCheat[j++] = false; } - } delete cheatEngine2; return formattedList; } + void CwCheatScreen::CreateViews() { using namespace UI; std::vector formattedList; @@ -72,7 +72,7 @@ void CwCheatScreen::CreateViews() { leftColumn->Add(new ItemHeader(k->T("Options"))); leftColumn->Add(new Choice(k->T("Back")))->OnClick.Handle(this, &CwCheatScreen::OnBack); //leftColumn->Add(new Choice(k->T("Add Cheat")))->OnClick.Handle(this, &CwCheatScreen::OnAddCheat); - leftColumn->Add(new Choice(k->T("Import from cheat.db")))->OnClick.Handle(this, &CwCheatScreen::OnImportCheat); + leftColumn->Add(new Choice(k->T("Import Cheats")))->OnClick.Handle(this, &CwCheatScreen::OnImportCheat); leftColumn->Add(new Choice(k->T("Enable/Disable All")))->OnClick.Handle(this, &CwCheatScreen::OnEnableAll); @@ -88,14 +88,14 @@ void CwCheatScreen::CreateViews() { for (size_t i = 0; i < formattedList.size(); i++) { name = formattedList[i].c_str(); rightColumn->Add(new CheatCheckBox(&enableCheat[i], k->T(name), "" ))->OnClick.Handle(this, &CwCheatScreen::OnCheckBox); - } - + } } + UI::EventReturn CwCheatScreen::OnBack(UI::EventParams ¶ms) { screenManager()->finishDialog(this, DR_OK); os.open(activeCheatFile.c_str()); - for (int j = 0; j < cheatList.size(); j++) { + for (int j = 0; j < (int)cheatList.size(); j++) { os << cheatList[j]; if (j < cheatList.size() - 1) { os << "\n"; @@ -105,14 +105,21 @@ UI::EventReturn CwCheatScreen::OnBack(UI::EventParams ¶ms) g_Config.bReloadCheats = true; return UI::EVENT_DONE; } + UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) { std::vector temp = cheatList; enableAll = !enableAll; os.open(activeCheatFile.c_str()); +<<<<<<< HEAD for (int j = 0; j < cheatList.size(); j++) { if (enableAll == 1 && cheatList[j].substr(0, 3) == "_C0"){ cheatList[j].replace(0, 3, "_C1"); +======= + for (size_t j = 0; j < temp.size(); j++) { + if (enableAll == 1 && temp[j].substr(0, 3) == "_C0"){ + temp[j].replace(0,3,"_C1"); +>>>>>>> upstream2/master } else if (enableAll == 0 && cheatList[j].substr(0, 3) == "_C1") { @@ -124,9 +131,15 @@ UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) for (int y = 0; y < 128; y++) { enableCheat[y] = enableAll; } +<<<<<<< HEAD for (int i = 0; i < cheatList.size(); i++) { os << cheatList[i]; if (i < cheatList.size() - 1) { +======= + for (int i = 0; i < (int)temp.size(); i++) { + os << temp[i]; + if (i < temp.size() - 1) { +>>>>>>> upstream2/master os << "\n"; } } @@ -160,9 +173,13 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) getline(is, line); title.push_back(line); getline(is, line); +<<<<<<< HEAD +======= + +>>>>>>> upstream2/master do { if (finished == false){ getline(is, line); @@ -170,7 +187,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) if (line.substr(0, 3) == "_C0" || line.substr(0, 3) == "_C1") { //Test if cheat already exists in cheatList - for (int j = 0; j < formattedList.size(); j++) { + for (size_t j = 0; j < formattedList.size(); j++) { if (line.substr(4) == formattedList[j]) { finished = false; goto loop; @@ -193,6 +210,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) if (finished == true) break; } +<<<<<<< HEAD is.close(); std::string title2; is.open(activeCheatFile.c_str()); @@ -202,11 +220,13 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) if (title2.substr(0, 2) != "_S") { os << title[0] << "\n" << title[1]; } +======= +>>>>>>> upstream2/master if (newList.size() != 0) { os << "\n"; } - for (int i = 0; i < newList.size(); i++) { + for (int i = 0; i < (int)newList.size(); i++) { os << newList[i]; if (i < newList.size() - 1) { os << "\n"; @@ -218,38 +238,37 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) screenManager()->finishDialog(this, DR_OK); return UI::EVENT_DONE; } -UI::EventReturn CwCheatScreen::OnCheckBox(UI::EventParams ¶ms) { +UI::EventReturn CwCheatScreen::OnCheckBox(UI::EventParams ¶ms) { return UI::EVENT_DONE; } + void CwCheatScreen::processFileOn(std::string activatedCheat) { - - for (int i = 0; i < cheatList.size(); i++) { + for (size_t i = 0; i < cheatList.size(); i++) { if (cheatList[i].substr(4) == activatedCheat) { cheatList[i] = "_C1 " + activatedCheat; } } os.open(activeCheatFile.c_str()); - for (int j = 0; j < cheatList.size(); j++) { + for (size_t j = 0; j < cheatList.size(); j++) { os << cheatList[j]; if (j < cheatList.size() - 1) { os << "\n"; } } os.close(); - } + void CwCheatScreen::processFileOff(std::string deactivatedCheat) { - - for (int i = 0; i < cheatList.size(); i++) { + for (size_t i = 0; i < cheatList.size(); i++) { if (cheatList[i].substr(4) == deactivatedCheat) { cheatList[i] = "_C0 " + deactivatedCheat; } } os.open(activeCheatFile.c_str()); - for (int j = 0; j < cheatList.size(); j++) { + for (size_t j = 0; j < cheatList.size(); j++) { os << cheatList[j]; if (j < cheatList.size() - 1) { os << "\n"; @@ -270,6 +289,7 @@ void CheatCheckBox::Draw(UIContext &dc) { if (!IsEnabled()) style = dc.theme->itemDisabledStyle; - dc.Draw()->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.SetFontStyle(dc.theme->uiFont); + dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER); } \ No newline at end of file diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 0fe37b0f01..5883c2a768 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -20,10 +20,12 @@ #include "gfx_es2/glsl_program.h" #include "gfx_es2/gl_state.h" +#include "gfx_es2/draw_text.h" #include "gfx_es2/fbo.h" #include "input/input_state.h" #include "ui/ui.h" +#include "ui/ui_context.h" #include "i18n/i18n.h" #include "Common/KeyMap.h" @@ -497,8 +499,8 @@ void EmuScreen::render() { if (statbuf[4095]) ERROR_LOG(HLE, "Statbuf too big"); ui_draw2d.SetFontScale(.7f, .7f); - ui_draw2d.DrawText(UBUNTU24, statbuf, 11, 11, 0xc0000000); - ui_draw2d.DrawText(UBUNTU24, statbuf, 10, 10, 0xFFFFFFFF); + ui_draw2d.DrawText(UBUNTU24, statbuf, 11, 11, 0xc0000000, FLAG_DYNAMIC_ASCII); + ui_draw2d.DrawText(UBUNTU24, statbuf, 10, 10, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); ui_draw2d.SetFontScale(1.0f, 1.0f); } @@ -515,8 +517,8 @@ void EmuScreen::render() { sprintf(fpsbuf, "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / 60.0f * 100.0f); break; } ui_draw2d.SetFontScale(0.7f, 0.7f); - ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 8, 12, 0xc0000000, ALIGN_TOPRIGHT); - ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT); + ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 8, 12, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII); + ui_draw2d.DrawText(UBUNTU24, fpsbuf, dp_xres - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII); ui_draw2d.SetFontScale(1.0f, 1.0f); } diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 9fed86715d..6c3f53732d 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -29,6 +29,7 @@ #include "UI/GameInfoCache.h" #include "UI/MiscScreens.h" #include "UI/MainScreen.h" +#include "Core/Host.h" void GameScreen::CreateViews() { GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, true); @@ -66,6 +67,9 @@ void GameScreen::CreateViews() { rightColumnItems->Add(new Choice(ga->T("Game Settings")))->OnClick.Handle(this, &GameScreen::OnGameSettings); rightColumnItems->Add(new Choice(ga->T("Delete Save Data")))->OnClick.Handle(this, &GameScreen::OnDeleteSaveData); rightColumnItems->Add(new Choice(ga->T("Delete Game")))->OnClick.Handle(this, &GameScreen::OnDeleteGame); + if (host->CanCreateShortcut()) { + rightColumnItems->Add(new Choice(ga->T("Create Shortcut")))->OnClick.Handle(this, &GameScreen::OnCreateShortcut); + } UI::SetFocusedView(play); } @@ -103,7 +107,7 @@ void GameScreen::DrawBackground(UIContext &dc) { void GameScreen::update(InputState &input) { UIScreen::update(input); - I18NCategory *g = GetI18NCategory("General"); + I18NCategory *ga = GetI18NCategory("Game"); GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, true); if (tvTitle_) @@ -116,9 +120,9 @@ void GameScreen::update(InputState &input) { if (info->gameSize) { char temp[256]; - sprintf(temp, "%s: %1.1f %s", g->T("Game"), (float) (info->gameSize) / 1024.f / 1024.f, g->T("MB")); + sprintf(temp, "%s: %1.1f %s", ga->T("Game"), (float) (info->gameSize) / 1024.f / 1024.f, ga->T("MB")); tvGameSize_->SetText(temp); - sprintf(temp, "%s: %1.2f %s", g->T("SaveData"), (float) (info->saveDataSize) / 1024.f / 1024.f, g->T("MB")); + sprintf(temp, "%s: %1.2f %s", ga->T("SaveData"), (float) (info->saveDataSize) / 1024.f / 1024.f, ga->T("MB")); tvSaveDataSize_->SetText(temp); } } @@ -144,11 +148,11 @@ UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) { UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) { I18NCategory *d = GetI18NCategory("Dialog"); - I18NCategory *g = GetI18NCategory("General"); + I18NCategory *ga = GetI18NCategory("Game"); GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, true); if (info) { screenManager()->push( - new PromptScreen(d->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), g->T("Delete Savedata"), g->T("Cancel"), + new PromptScreen(d->T("DeleteConfirmAll", "Do you really want to delete all\nyour save data for this game?"), ga->T("DeleteSaveData"), ga->T("Cancel"), std::bind(&GameScreen::CallbackDeleteSaveData, this, placeholder::_1))); } @@ -165,11 +169,11 @@ void GameScreen::CallbackDeleteSaveData(bool yes) { UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) { I18NCategory *d = GetI18NCategory("Dialog"); - I18NCategory *g = GetI18NCategory("General"); + I18NCategory *ga = GetI18NCategory("Game"); GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, true); if (info) { screenManager()->push( - new PromptScreen(d->T("DeleteGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), g->T("Delete Game"), g->T("Cancel"), + new PromptScreen(d->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("DeleteGame"), ga->T("Cancel"), std::bind(&GameScreen::CallbackDeleteGame, this, placeholder::_1))); } @@ -185,3 +189,10 @@ void GameScreen::CallbackDeleteGame(bool yes) { } } +UI::EventReturn GameScreen::OnCreateShortcut(UI::EventParams &e) { + GameInfo *info = g_gameInfoCache.GetInfo(gamePath_, false); + if (info) { + host->CreateDesktopShortcut(gamePath_, info->title); + } + return UI::EVENT_DONE; +} diff --git a/UI/GameScreen.h b/UI/GameScreen.h index 0e27495453..4443900e67 100644 --- a/UI/GameScreen.h +++ b/UI/GameScreen.h @@ -22,7 +22,9 @@ // Game screen: Allows you to start a game, delete saves, delete the game, // set game specific settings, etc. + // Uses GameInfoCache heavily to implement the functionality. +// Should possibly merge this with the PauseScreen. class GameScreen : public UIDialogScreen { public: @@ -43,6 +45,7 @@ private: UI::EventReturn OnDeleteSaveData(UI::EventParams &e); UI::EventReturn OnDeleteGame(UI::EventParams &e); UI::EventReturn OnSwitchBack(UI::EventParams &e); + UI::EventReturn OnCreateShortcut(UI::EventParams &e); std::string gamePath_; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index fc41d4768a..628008b020 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -34,6 +34,7 @@ #include "math/curves.h" #include "Core/HW/atrac3plus.h" #include "Core/System.h" +#include "Core/Reporting.h" #include "Common/KeyMap.h" #ifdef _WIN32 @@ -69,6 +70,8 @@ public: virtual void Draw(UIContext &dc); + UI::Event OnChoice; + private: void UpdateText(); EventReturn HandleClick(EventParams &e); @@ -104,13 +107,19 @@ void PopupMultiChoice::ChoiceCallback(int num) { if (num != -1) { *value_ = num + minVal_; UpdateText(); + + UI::EventParams e; + e.v = this; + e.a = num; + OnChoice.Trigger(e); } } void PopupMultiChoice::Draw(UIContext &dc) { Choice::Draw(dc); int paddingX = 12; - dc.Draw()->DrawText(dc.theme->uiFont, valueText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); + dc.SetFontStyle(dc.theme->uiFont); + dc.DrawText(valueText_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); } class PopupSliderChoice : public Choice { @@ -160,7 +169,8 @@ void PopupSliderChoice::Draw(UIContext &dc) { Choice::Draw(dc); char temp[32]; sprintf(temp, "%i", *value_); - dc.Draw()->DrawText(dc.theme->uiFont, temp, bounds_.x2() - 12, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); + dc.SetFontStyle(dc.theme->uiFont); + dc.DrawText(temp, bounds_.x2() - 12, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); } EventReturn PopupSliderChoiceFloat::HandleClick(EventParams &e) { @@ -173,7 +183,8 @@ void PopupSliderChoiceFloat::Draw(UIContext &dc) { Choice::Draw(dc); char temp[32]; sprintf(temp, "%2.2f", *value_); - dc.Draw()->DrawText(dc.theme->uiFont, temp, bounds_.x2() - 12, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); + dc.SetFontStyle(dc.theme->uiFont); + dc.DrawText(temp, bounds_.x2() - 12, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER); } } @@ -228,8 +239,8 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("Graphics"), graphicsSettingsScroll); graphicsSettings->Add(new ItemHeader(gs->T("Rendering Mode"))); - static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering", "Read Framebuffers To Memory(CPU)", "Read Framebuffers To Memory(GPU)"}; - graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gs->T("Mode"), renderingMode, 0, 4, gs, screenManager())); + static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering", "Read Framebuffers To Memory (CPU)", "Read Framebuffers To Memory (GPU)"}; + graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gs->T("Mode"), renderingMode, 0, 4, gs, screenManager()))->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingMode); graphicsSettings->Add(new ItemHeader(gs->T("Frame Rate Control"))); static const char *frameSkip[] = {"Off", "Auto", "1", "2", "3", "4", "5", "6", "7", "8"}; @@ -302,7 +313,7 @@ void GameSettingsScreen::CreateViews() { audioSettings->Add(new CheckBox(&g_Config.bEnableSound, a->T("Enable Sound"))); audioSettings->Add(new CheckBox(&g_Config.bEnableAtrac3plus, a->T("Enable Atrac3+"))); - audioSettings->Add(new CheckBox(&g_Config.bLowLatencyAudio, a->T("Low latency (may stutter)"))); + audioSettings->Add(new CheckBox(&g_Config.bLowLatencyAudio, a->T("Low latency audio"))); // Control ViewGroup *controlsSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); @@ -345,14 +356,14 @@ void GameSettingsScreen::CreateViews() { #endif systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, s->T("Change CPU Clock", "Change CPU Clock (0 = default)"), screenManager())); - enableReports_ = g_Config.sReportHost != "default"; + enableReports_ = Reporting::IsEnabled(); //#ifndef ANDROID systemSettings->Add(new ItemHeader(s->T("Cheats", "Cheats (experimental, see forums)"))); systemSettings->Add(new CheckBox(&g_Config.bEnableCheats, s->T("Enable Cheats"))); //#endif LinearLayout *list = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); systemSettings->SetSpacing(0); - systemSettings->Add(new ItemHeader(g->T("General"))); + systemSettings->Add(new ItemHeader(s->T("General"))); systemSettings->Add(new Choice(s->T("System Language", "Language")))->OnClick.Handle(this, &GameSettingsScreen::OnLanguage); #ifdef _WIN32 // Screenshot functionality is not yet available on non-Windows @@ -364,7 +375,10 @@ void GameSettingsScreen::CreateViews() { #ifdef _WIN32 systemSettings->Add(new Choice(s->T("Change Nickname")))->OnClick.Handle(this, &GameSettingsScreen::OnChangeNickname); #endif - systemSettings->Add(new CheckBox(&enableReports_, s->T("Enable Compatibility Server Reports"))); + systemSettings->Add(new Choice(s->T("Clear Recent Games List")))->OnClick.Handle(this, &GameSettingsScreen::OnClearRecents); + enableReportsCheckbox_ = new CheckBox(&enableReports_, s->T("Enable Compatibility Server Reports")); + enableReportsCheckbox_->SetEnabled(Reporting::IsSupported()); + systemSettings->Add(enableReportsCheckbox_); systemSettings->Add(new Choice(s->T("Developer Tools")))->OnClick.Handle(this, &GameSettingsScreen::OnDeveloperTools); @@ -378,12 +392,24 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new PopupMultiChoice(&g_Config.iButtonPreference, s->T("Confirmation Button"), buttonPref, 0, 2, s, screenManager())); } +UI::EventReturn GameSettingsScreen::OnClearRecents(UI::EventParams &e) { + g_Config.recentIsos.clear(); + + return UI::EVENT_DONE; +} + UI::EventReturn GameSettingsScreen::OnReloadCheats(UI::EventParams &e) { // Hmm, strange mechanism. g_Config.bReloadCheats = true; return UI::EVENT_DONE; } +UI::EventReturn GameSettingsScreen::OnRenderingMode(UI::EventParams &e) { + enableReports_ = Reporting::IsEnabled(); + enableReportsCheckbox_->SetEnabled(Reporting::IsSupported()); + return UI::EVENT_DONE; +} + void DrawBackground(float alpha); UI::EventReturn GameSettingsScreen::OnDumpNextFrameToLog(UI::EventParams &e) { @@ -446,7 +472,7 @@ UI::EventReturn GameSettingsScreen::OnBack(UI::EventParams &e) { Atrac3plus_Decoder::Init(); else Atrac3plus_Decoder::Shutdown(); } - g_Config.sReportHost = enableReports_ ? "report.ppsspp.org" : "default"; + Reporting::Enable(enableReports_, "report.ppsspp.org"); g_Config.Save(); #ifdef _WIN32 @@ -463,7 +489,7 @@ void GlobalSettingsScreen::CreateViews() { using namespace UI; root_ = new ScrollView(ORIENT_VERTICAL); - enableReports_ = g_Config.sReportHost != ""; + enableReports_ = Reporting::IsEnabled(); }*/ UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) { @@ -488,7 +514,16 @@ UI::EventReturn GameSettingsScreen::OnFactoryReset(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) { - screenManager()->push(new NewLanguageScreen()); + I18NCategory *d = GetI18NCategory("Developer"); + auto langScreen = new NewLanguageScreen(d->T("Language")); + langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange); + screenManager()->push(langScreen); + return UI::EVENT_DONE; +} + +UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { + RecreateViews(); + OnLanguageChanged.Trigger(e); return UI::EVENT_DONE; } @@ -512,17 +547,19 @@ void DeveloperToolsScreen::CreateViews() { I18NCategory *d = GetI18NCategory("Developer"); I18NCategory *gs = GetI18NCategory("Graphics"); I18NCategory *a = GetI18NCategory("Audio"); + I18NCategory *s = GetI18NCategory("System"); LinearLayout *list = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f))); list->SetSpacing(0); - list->Add(new ItemHeader(g->T("General"))); - list->Add(new Choice(g->T("System Information")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSysInfo); + list->Add(new ItemHeader(s->T("General"))); + list->Add(new Choice(d->T("System Information")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSysInfo); list->Add(new Choice(d->T("Run CPU Tests")))->OnClick.Handle(this, &DeveloperToolsScreen::OnRunCPUTests); + list->Add(new Choice(d->T("Restore Default Settings")))->OnClick.Handle(this, &DeveloperToolsScreen::OnRestoreDefaultSettings); #ifndef __SYMBIAN32__ list->Add(new CheckBox(&g_Config.bSoftwareRendering, gs->T("Software Rendering", "Software Rendering (experimental)"))); #endif list->Add(new CheckBox(&enableLogging_, d->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged); - list->Add(new ItemHeader(g->T("Language"))); + list->Add(new ItemHeader(d->T("Language"))); list->Add(new Choice(d->T("Load language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoadLanguageIni); list->Add(new Choice(d->T("Save language ini")))->OnClick.Handle(this, &DeveloperToolsScreen::OnSaveLanguageIni); list->Add(new Choice(g->T("Back")))->OnClick.Handle(this, &DeveloperToolsScreen::OnBack); @@ -540,6 +577,21 @@ UI::EventReturn DeveloperToolsScreen::OnBack(UI::EventParams &e) { return UI::EVENT_DONE; } +void DeveloperToolsScreen::CallbackRestoreDefaults(bool yes) { + if(yes) + g_Config.RestoreDefaults(); +} + +UI::EventReturn DeveloperToolsScreen::OnRestoreDefaultSettings(UI::EventParams &e) { + I18NCategory *d = GetI18NCategory("Dialog"); + I18NCategory *g = GetI18NCategory("General"); + screenManager()->push( + new PromptScreen(d->T("RestoreDefaultSettings", "Are you sure you want to restore all settings(except control mapping)\nback to their defaults?\nYou can't undo this.\nPlease restart PPSSPP after restoring settings."), g->T("OK"), g->T("Cancel"), + std::bind(&DeveloperToolsScreen::CallbackRestoreDefaults, this, placeholder::_1))); + + return UI::EVENT_DONE; +} + UI::EventReturn DeveloperToolsScreen::OnLoggingChanged(UI::EventParams &e) { #ifdef _WIN32 PostMessage(MainWindow::hwndMain, MainWindow::WM_USER_LOG_STATUS_CHANGED, 0, 0); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index b0b0ed5409..0c01f876b4 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -24,10 +24,13 @@ // per game. class GameSettingsScreen : public UIDialogScreenWithBackground { public: - GameSettingsScreen(std::string gamePath, std::string gameID = "") : gamePath_(gamePath), gameID_(gameID), iAlternateSpeedPercent_(3), enableReports_(false) {} + GameSettingsScreen(std::string gamePath, std::string gameID = "") + : gamePath_(gamePath), gameID_(gameID), iAlternateSpeedPercent_(3), enableReports_(false) {} virtual void update(InputState &input); + UI::Event OnLanguageChanged; + protected: virtual void CreateViews(); virtual void DrawBackground(UIContext &dc); @@ -38,6 +41,7 @@ private: // As we load metadata in the background, we need to be able to update these after the fact. UI::TextView *tvTitle_; UI::TextView *tvGameSize_; + UI::CheckBox *enableReportsCheckbox_; // Event handlers UI::EventReturn OnDownloadPlugin(UI::EventParams &e); @@ -48,14 +52,17 @@ private: // Global settings handlers UI::EventReturn OnLanguage(UI::EventParams &e); + UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnFactoryReset(UI::EventParams &e); UI::EventReturn OnDeveloperTools(UI::EventParams &e); UI::EventReturn OnChangeNickname(UI::EventParams &e); + UI::EventReturn OnClearRecents(UI::EventParams &e); + UI::EventReturn OnRenderingMode(UI::EventParams &e); // Temporaries to convert bools to int settings bool cap60FPS_; - bool enableReports_; int iAlternateSpeedPercent_; + bool enableReports_; }; /* @@ -77,6 +84,7 @@ public: protected: virtual void CreateViews(); + void CallbackRestoreDefaults(bool yes); private: UI::EventReturn OnBack(UI::EventParams &e); @@ -85,6 +93,7 @@ private: UI::EventReturn OnLoggingChanged(UI::EventParams &e); UI::EventReturn OnLoadLanguageIni(UI::EventParams &e); UI::EventReturn OnSaveLanguageIni(UI::EventParams &e); + UI::EventReturn OnRestoreDefaultSettings(UI::EventParams &e); // Temporary variable. bool enableLogging_; diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 611435adeb..2a2ba8ec2c 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -25,6 +25,7 @@ #include "Common/FileUtil.h" #include "Core/System.h" +#include "Core/Host.h" #include "Core/SaveState.h" #include "UI/EmuScreen.h" @@ -180,21 +181,23 @@ void GameButton::Draw(UIContext &dc) { dc.Draw()->Flush(); dc.RebindTexture(); + dc.SetFontStyle(dc.theme->uiFont); if (!gridStyle_) { dc.Draw()->Flush(); dc.PushScissor(bounds_); - dc.Draw()->DrawText(0, ginfo->title.c_str(), bounds_.x + 150, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(ginfo->title.c_str(), bounds_.x + 150, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.Draw()->Flush(); dc.PopScissor(); } else if (!texture) { dc.Draw()->Flush(); dc.PushScissor(bounds_); - dc.Draw()->DrawText(0, ginfo->title.c_str(), bounds_.x + 4, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); + dc.DrawText(ginfo->title.c_str(), bounds_.x + 4, bounds_.centerY(), style.fgColor, ALIGN_VCENTER); dc.Draw()->Flush(); dc.PopScissor(); } else { dc.Draw()->Flush(); } + dc.RebindTexture(); } // Abstraction above path that lets you navigate easily. @@ -533,7 +536,7 @@ void MainScreen::CreateViews() { #endif logos->Add(new ImageView(I_LOGO, IS_DEFAULT, new LinearLayoutParams(Margins(-12, 0, 0, 0)))); rightColumnItems->Add(logos); - rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0))))->SetTextScale(0.5f); + rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0))))->SetSmall(true); #if defined(_WIN32) || defined(USING_QT_UI) rightColumnItems->Add(new Choice(m->T("Load","Load...")))->OnClick.Handle(this, &MainScreen::OnLoadFile); #endif @@ -583,7 +586,17 @@ UI::EventReturn MainScreen::OnGameSelectedInstant(UI::EventParams &e) { UI::EventReturn MainScreen::OnGameSettings(UI::EventParams &e) { // screenManager()->push(new SettingsScreen()); - screenManager()->push(new GameSettingsScreen("","")); + auto gameSettings = new GameSettingsScreen("", ""); + gameSettings->OnLanguageChanged.Handle(this, &MainScreen::OnLanguageChange); + screenManager()->push(gameSettings); + return UI::EVENT_DONE; +} + +UI::EventReturn MainScreen::OnLanguageChange(UI::EventParams &e) { + RecreateViews(); + if (host) { + host->UpdateUI(); + } return UI::EVENT_DONE; } diff --git a/UI/MainScreen.h b/UI/MainScreen.h index c5b4a57e21..2263df29e3 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -41,6 +41,7 @@ private: // Event handlers UI::EventReturn OnLoadFile(UI::EventParams &e); UI::EventReturn OnGameSettings(UI::EventParams &e); + UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnCredits(UI::EventParams &e); UI::EventReturn OnSupport(UI::EventParams &e); UI::EventReturn OnPPSSPPOrg(UI::EventParams &e); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index b3d006d6cb..17c02fa96e 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -99,13 +99,13 @@ std::map> GetLangValuesMapping() { langValuesMapping["ja_JP"] = std::make_pair("日本語", PSP_SYSTEMPARAM_LANGUAGE_JAPANESE); langValuesMapping["en_US"] = std::make_pair("English",PSP_SYSTEMPARAM_LANGUAGE_ENGLISH); langValuesMapping["fr_FR"] = std::make_pair("Français", PSP_SYSTEMPARAM_LANGUAGE_FRENCH); - langValuesMapping["es_ES"] = std::make_pair("Castellano", PSP_SYSTEMPARAM_LANGUAGE_SPANISH); - langValuesMapping["es_LA"] = std::make_pair("Latino", PSP_SYSTEMPARAM_LANGUAGE_SPANISH); + langValuesMapping["es_ES"] = std::make_pair("Castellano (España)", PSP_SYSTEMPARAM_LANGUAGE_SPANISH); + langValuesMapping["es_LA"] = std::make_pair("Español (América Latina)", PSP_SYSTEMPARAM_LANGUAGE_SPANISH); langValuesMapping["de_DE"] = std::make_pair("Deutsch", PSP_SYSTEMPARAM_LANGUAGE_GERMAN); langValuesMapping["it_IT"] = std::make_pair("Italiano", PSP_SYSTEMPARAM_LANGUAGE_ITALIAN); langValuesMapping["nl_NL"] = std::make_pair("Nederlands", PSP_SYSTEMPARAM_LANGUAGE_DUTCH); langValuesMapping["pt_PT"] = std::make_pair("Português", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE); - langValuesMapping["pt_BR"] = std::make_pair("Brasileiro", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE); + langValuesMapping["pt_BR"] = std::make_pair("Português Brasileiro", PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE); langValuesMapping["ru_RU"] = std::make_pair("Русский", PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN); langValuesMapping["ko_KR"] = std::make_pair("한국어", PSP_SYSTEMPARAM_LANGUAGE_KOREAN); langValuesMapping["zh_TW"] = std::make_pair("繁體中文", PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL); @@ -151,7 +151,7 @@ void PromptScreen::CreateViews() { ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f)); root_->Add(leftColumn); - leftColumn->Add(new TextView(message_, ALIGN_LEFT, 1.0f, new AnchorLayoutParams(10, 10, NONE, NONE))); + leftColumn->Add(new TextView(message_, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE))); ViewGroup *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); root_->Add(rightColumnItems); @@ -172,7 +172,7 @@ UI::EventReturn PromptScreen::OnNo(UI::EventParams &e) { return UI::EVENT_DONE; } -NewLanguageScreen::NewLanguageScreen() : ListPopupScreen("Language") { +NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen(title) { // Disable annoying encoding warning #ifdef _MSC_VER #pragma warning(disable:4566) @@ -249,6 +249,7 @@ void NewLanguageScreen::OnCompleted(DialogResult result) { } else { g_Config.ilanguage = langValuesMapping[code].second; } + RecreateViews(); } else { g_Config.languageIni = oldLang; } @@ -301,13 +302,13 @@ void LogoScreen::render() { char temp[256]; sprintf(temp, "%s Henrik Rydgård", c->T("created", "Created by")); - dc.Draw()->SetFontScale(1.5f, 1.5f); dc.Draw()->DrawImage(I_LOGO, dp_xres / 2, dp_yres / 2 - 30, 1.5f, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); //dc.Draw()->DrawTextShadow(UBUNTU48, "PPSSPP", dp_xres / 2, dp_yres / 2 - 30, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); dc.Draw()->SetFontScale(1.0f, 1.0f); - dc.Draw()->DrawTextShadow(UBUNTU24, temp, dp_xres / 2, dp_yres / 2 + 40, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); - dc.Draw()->DrawTextShadow(UBUNTU24, c->T("license", "Free Software under GPL 2.0"), dp_xres / 2, dp_yres / 2 + 70, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); - dc.Draw()->DrawTextShadow(UBUNTU24, "www.ppsspp.org", dp_xres / 2, dp_yres / 2 + 130, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); + dc.SetFontStyle(dc.theme->uiFont); + dc.DrawText(temp, dp_xres / 2, dp_yres / 2 + 40, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); + dc.DrawText(c->T("license", "Free Software under GPL 2.0"), dp_xres / 2, dp_yres / 2 + 70, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); + dc.DrawText("www.ppsspp.org", dp_xres / 2, dp_yres / 2 + 130, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); if (bootFilename_.size()) { ui_draw2d.DrawTextShadow(UBUNTU24, bootFilename_.c_str(), dp_xres / 2, dp_yres / 2 + 180, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER); } @@ -318,6 +319,7 @@ void LogoScreen::render() { void SystemInfoScreen::CreateViews() { // NOTE: Do not translate this section. It will change a lot and will be impossible to keep up. + I18NCategory *g = GetI18NCategory("General"); using namespace UI; root_ = new ScrollView(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT)); @@ -326,11 +328,17 @@ void SystemInfoScreen::CreateViews() { root_->Add(scroll); scroll->Add(new ItemHeader("System Information")); - scroll->Add(new InfoItem("System Name :", System_GetName())); - scroll->Add(new InfoItem("GPU Vendor :", (char *)glGetString(GL_VENDOR))); - scroll->Add(new InfoItem("GPU Model :", (char *)glGetString(GL_RENDERER))); + scroll->Add(new InfoItem("System Name", System_GetName())); + scroll->Add(new InfoItem("GPU Vendor", (char *)glGetString(GL_VENDOR))); + scroll->Add(new InfoItem("GPU Model", (char *)glGetString(GL_RENDERER))); + scroll->Add(new InfoItem("OpenGL Version Supported", (char *)glGetString(GL_VERSION))); + scroll->Add(new Choice(g->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); +#ifdef _WIN32 + scroll->Add(new ItemHeader("OpenGL Extensions")); +#else scroll->Add(new ItemHeader("OpenGL ES 2.0 Extensions")); +#endif std::vector exts; SplitString(g_all_gl_extensions, ' ', exts); for (size_t i = 0; i < exts.size(); i++) { @@ -348,19 +356,20 @@ void SystemInfoScreen::CreateViews() { void CreditsScreen::CreateViews() { using namespace UI; I18NCategory *g = GetI18NCategory("General"); + I18NCategory *c = GetI18NCategory("PSPCredits"); root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); root_->Add(new Button(g->T("Back"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnOK); #ifndef GOLD - root_->Add(new Button(g->T("Buy Gold"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnSupport); + root_->Add(new Button(c->T("Buy Gold"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnSupport); #endif - if(g_Config.languageIni == "zh_CN") { - root_->Add(new Button(g->T("PPSSPP Chinese Forum"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnChineseForum); - root_->Add(new Button(g->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 154, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); + if(g_Config.languageIni == "zh_CN" ||g_Config.languageIni == "zh_TW") { + root_->Add(new Button(c->T("PPSSPP Chinese Forum"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnChineseForum); + root_->Add(new Button(c->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 154, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 228, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg); } else { - root_->Add(new Button(g->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); + root_->Add(new Button(c->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 158, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg); } #ifdef GOLD @@ -463,6 +472,13 @@ void CreditsScreen::render() { "solarmystic (testing)", "all the forum mods", "", + c->T("this translation by", ""), // Empty string as this is the original :) + c->T("translators1", ""), + c->T("translators2", ""), + c->T("translators3", ""), + c->T("translators4", ""), + c->T("translators5", ""), + c->T("translators6", ""), "", c->T("written", "Written in C++ for speed and portability"), "", diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index a584410f43..49fd7ca971 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -64,7 +64,7 @@ private: class NewLanguageScreen : public ListPopupScreen { public: - NewLanguageScreen(); + NewLanguageScreen(const std::string &title); private: virtual void OnCompleted(DialogResult result); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index e2695f1233..d470759cbe 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -37,6 +37,7 @@ #include "native/ext/stb_image_write/stb_image_writer.h" #include "native/ext/jpge/jpge.h" #include "gfx_es2/gl_state.h" +#include "gfx_es2/draw_text.h" #include "gfx/gl_lost_manager.h" #include "gfx/texture.h" #include "i18n/i18n.h" @@ -44,7 +45,6 @@ #include "math/math_util.h" #include "math/lin/matrix4x4.h" #include "ui/screen.h" -#include "ui/ui.h" #include "ui/ui_context.h" #include "ui/view.h" @@ -372,6 +372,16 @@ void NativeInit(int argc, const char *argv[], #endif i18nrepo.LoadIni(g_Config.languageIni); + I18NCategory *d = GetI18NCategory("DesktopUI"); + // Note to translators: do not translate this/add this to PPSSPP-lang's files. + // It's intended to be custom for every user. + // Only add it to your own personal copies of PPSSPP. +#ifdef _WIN32 + // TODO: Could allow a setting to specify a font file to load? + // TODO: Make this a constant if we can sanely load the font on other systems? + AddFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL); + g_Config.sFont = d->T("Font", "Roboto"); +#endif if (!boot_filename.empty() && stateToLoad != NULL) SaveState::Load(stateToLoad); @@ -400,24 +410,22 @@ void NativeInitGraphics() { CheckGLExtensions(); gl_lost_manager_init(); ui_draw2d.SetAtlas(&ui_atlas); + ui_draw2d_front.SetAtlas(&ui_atlas); UIShader_Init(); - // Old style theme, to be removed later - UITheme theme = {0}; - theme.uiFont = UBUNTU24; - theme.uiFontSmall = UBUNTU24; - theme.uiFontSmaller = UBUNTU24; - theme.buttonImage = I_SOLIDWHITE; // not using classic buttons - theme.buttonSelected = I_SOLIDWHITE; - theme.checkOn = I_CHECKEDBOX; - theme.checkOff = I_SQUARE; - // memset(&ui_theme, 0, sizeof(ui_theme)); // New style theme - ui_theme.uiFont = UBUNTU24; - ui_theme.uiFontSmall = UBUNTU24; - ui_theme.uiFontSmaller = UBUNTU24; +#ifdef _WIN32 + ui_theme.uiFont = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 22); + ui_theme.uiFontSmall = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 15); + ui_theme.uiFontSmaller = UI::FontStyle(UBUNTU24, g_Config.sFont.c_str(), 12); +#else + ui_theme.uiFont = UI::FontStyle(UBUNTU24, "", 20); + ui_theme.uiFontSmall = UI::FontStyle(UBUNTU24, "", 14); + ui_theme.uiFontSmaller = UI::FontStyle(UBUNTU24, "", 11); +#endif + ui_theme.checkOn = I_CHECKEDBOX; ui_theme.checkOff = I_SQUARE; ui_theme.whiteImage = I_SOLIDWHITE; @@ -453,8 +461,6 @@ void NativeInitGraphics() { ui_draw2d.Init(); ui_draw2d_front.Init(); - UIInit(&ui_atlas, theme); - uiTexture = new Texture(); if (!uiTexture->Load("ui_atlas.zim")) { PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); @@ -465,7 +471,8 @@ void NativeInitGraphics() { uiContext = new UIContext(); uiContext->theme = &ui_theme; uiContext->Init(UIShader_Get(), UIShader_GetPlain(), uiTexture, &ui_draw2d, &ui_draw2d_front); - + if (uiContext->Text()) + uiContext->Text()->SetFont("Tahoma", 20, 0); screenManager->setUIContext(uiContext); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); @@ -561,6 +568,8 @@ void NativeRender() { glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr()); screenManager->render(); + if (screenManager->getUIContext()->Text()) + screenManager->getUIContext()->Text()->OncePerFrame(); if (g_TakeScreenshot) { TakeScreenshot(); @@ -643,4 +652,8 @@ void NativeShutdown() { ILOG("NativeShutdown called"); exit(0); #endif + +#ifdef _WIN32 + RemoveFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL); +#endif } diff --git a/UI/PluginScreen.cpp b/UI/PluginScreen.cpp index 1516d32bba..b38a1ac9c1 100644 --- a/UI/PluginScreen.cpp +++ b/UI/PluginScreen.cpp @@ -108,6 +108,8 @@ void PluginScreen::update(InputState &input) { abi = "armeabi"; #elif defined(ARMEABI_V7A) abi = "armeabi-v7a"; +#elif defined(ANDROID) && defined(_M_IX86) + abi = "android-x86"; #elif defined(BLACKBERRY) abi = "blackberry10"; #elif defined(IOS) diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 9dcd2aaa7f..5dcd9e0e1f 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -59,27 +59,27 @@ StaticLibrary true v100 - MultiByte + Unicode StaticLibrary true v100 - MultiByte + Unicode StaticLibrary false v100 false - MultiByte + Unicode StaticLibrary false v100 false - MultiByte + Unicode diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 784bc38693..a2ce7847c2 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -28,9 +28,7 @@ Screens - - Screens - + @@ -59,9 +57,7 @@ Screens - - Screens - + diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 3a204d2ea9..72ad3ebfae 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -96,7 +96,7 @@ namespace DSound { char temp[8]; sprintf(temp,"%i\n",hr); - OutputDebugString(temp); + OutputDebugStringUTF8(temp); }*/ return false; } diff --git a/Windows/Debugger/BreakpointWindow.cpp b/Windows/Debugger/BreakpointWindow.cpp index 72c1947ed5..3b325c3ad4 100644 --- a/Windows/Debugger/BreakpointWindow.cpp +++ b/Windows/Debugger/BreakpointWindow.cpp @@ -30,13 +30,13 @@ INT_PTR CALLBACK BreakpointWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, if (bp->address != -1) { sprintf(str,"0x%08X",bp->address); - SetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_ADDRESS),str); + SetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_ADDRESS),str); } sprintf(str,"0x%08X",bp->size); - SetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),str); + SetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),str); - SetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),bp->condition); + SetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),bp->condition); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) @@ -120,49 +120,49 @@ bool BreakpointWindow::fetchDialogData(HWND hwnd) onChange = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_ONCHANGE),BM_GETCHECK,0,0) != 0; // parse address - GetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_ADDRESS),str,256); + GetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_ADDRESS),str,256); if (cpu->initExpression(str,exp) == false) { sprintf(errorMessage,"Invalid expression \"%s\".",str); - MessageBox(hwnd,errorMessage,"Error",MB_OK); + MessageBoxA(hwnd,errorMessage,"Error",MB_OK); return false; } if (cpu->parseExpression(exp,address) == false) { sprintf(errorMessage,"Invalid expression \"%s\".",str); - MessageBox(hwnd,errorMessage,"Error",MB_OK); + MessageBoxA(hwnd,errorMessage,"Error",MB_OK); return false; } if (memory) { // parse size - GetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),str,256); + GetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),str,256); if (cpu->initExpression(str,exp) == false) { sprintf(errorMessage,"Invalid expression \"%s\".",str); - MessageBox(hwnd,errorMessage,"Error",MB_OK); + MessageBoxA(hwnd,errorMessage,"Error",MB_OK); return false; } if (cpu->parseExpression(exp,size) == false) { sprintf(errorMessage,"Invalid expression \"%s\".",str); - MessageBox(hwnd,errorMessage,"Error",MB_OK); + MessageBoxA(hwnd,errorMessage,"Error",MB_OK); return false; } } // condition - GetWindowText(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),condition,128); + GetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),condition,128); compiledCondition.clear(); if (condition[0] != 0) { if (cpu->initExpression(condition,compiledCondition) == false) { sprintf(errorMessage,"Invalid expression \"%s\".",str); - MessageBox(hwnd,errorMessage,"Error",MB_OK); + MessageBoxA(hwnd,errorMessage,"Error",MB_OK); return false; } } diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 0cd1fe678b..3a882911f6 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -18,6 +18,9 @@ #include "Windows/main.h" #include "Common/CommonWindows.h" +#include "util/text/utf8.h" + +#include #include #include @@ -156,9 +159,9 @@ CtrlDisAsmView::CtrlDisAsmView(HWND _wnd) rowHeight = g_Config.iFontHeight+2; font = CreateFont(rowHeight-2,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, - "Lucida Console"); + L"Lucida Console"); boldfont = CreateFont(rowHeight-2,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, - "Lucida Console"); + L"Lucida Console"); curAddress=0; instructionSize=4; showHex=false; @@ -169,7 +172,7 @@ CtrlDisAsmView::CtrlDisAsmView(HWND _wnd) matchAddress = -1; searching = false; - searchQuery[0] = 0; + searchQuery = ""; windowStart = curAddress; whiteBackground = false; displaySymbols = true; @@ -291,26 +294,28 @@ void CtrlDisAsmView::parseDisasm(const char* disasm, char* opcode, char* argumen void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText) { - char op[256]; u32 encoded; - if (Core_IsStepping() == false) - { - MessageBox(wnd,"Cannot change code while the core is running!","Error",MB_OK); + if (Core_IsStepping() == false) { + MessageBox(wnd,L"Cannot change code while the core is running!",L"Error",MB_OK); return; } + std::string op; + bool result = InputBox_GetString(MainWindow::GetHInstance(),wnd,L"Assemble opcode",defaultText, op, false); + if (!result) + return; - bool result = InputBox_GetString(MainWindow::GetHInstance(),wnd,"Assemble opcode",(char*)defaultText.c_str(),op,false); - if (result == false) return; - - result = MIPSAsm::MipsAssembleOpcode(op,debugger,address,encoded); + result = MIPSAsm::MipsAssembleOpcode(op.c_str(),debugger,address,encoded); if (result == true) { - Memory::Write_U32(encoded,address); - MIPSComp::jit->ClearCacheAt(address); + Memory::Write_U32(encoded, address); + // In case this is a delay slot or combined instruction, clear cache above it too. + if (MIPSComp::jit) + MIPSComp::jit->ClearCacheAt(address - 4, 8); redraw(); } else { - MessageBox(wnd,"Couldn''t assemble.","Error",MB_OK); + std::wstring error = ConvertUTF8ToWString(MIPSAsm::GetAssembleError()); + MessageBox(wnd,error.c_str(),L"Error",MB_OK); } } @@ -341,8 +346,8 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) HPEN oldPen=(HPEN)SelectObject(hdc,nullPen); HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush); HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font); - HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOP); - HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOPDISABLE); + HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOP); + HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOPDISABLE); for (int i = 0; i < visibleRows+2; i++) { @@ -396,11 +401,11 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) char addressText[64]; getDisasmAddressText(address,addressText,true); - TextOut(hdc,pixelPositions.addressStart,rowY1+2,addressText,(int)strlen(addressText)); + TextOutA(hdc,pixelPositions.addressStart,rowY1+2,addressText,(int)strlen(addressText)); if (address == debugger->getPC()) { - TextOutW(hdc,pixelPositions.opcodeStart-8,rowY1,L"■",1); + TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"■",1); } // display opcode @@ -415,10 +420,10 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) } int length = (int) strlen(arguments); - if (length != 0) TextOut(hdc,pixelPositions.argumentsStart,rowY1+2,arguments,length); + if (length != 0) TextOutA(hdc,pixelPositions.argumentsStart,rowY1+2,arguments,length); SelectObject(hdc,boldfont); - TextOut(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode)); + TextOutA(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode)); SelectObject(hdc,font); if (info.isBranch && info.isConditional) @@ -460,7 +465,7 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) SelectObject(hdc,oldBrush); // copy bitmap to the actual hdc - BitBlt(actualHdc,0,0,rect.right,rect.bottom,hdc,0,0,SRCCOPY); + BitBlt(actualHdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY); DeleteObject(hBM); DeleteDC(hdc); @@ -666,7 +671,7 @@ void CtrlDisAsmView::toggleBreakpoint() } else if (CBreakPoints::GetBreakPointCondition(curAddress) != NULL) { // don't just delete a breakpoint with a custom condition - int ret = MessageBox(wnd,"This breakpoint has a custom condition.\nDo you want to remove it?","Confirmation",MB_YESNO); + int ret = MessageBox(wnd,L"This breakpoint has a custom condition.\nDo you want to remove it?",L"Confirmation",MB_YESNO); if (ret != IDYES) return; CBreakPoints::RemoveBreakPoint(curAddress); } else { @@ -793,18 +798,18 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) if (sym != -1) { char name[256]; - char newname[256]; + std::string newname; strncpy_s(name, symbolMap.GetSymbolName(sym),_TRUNCATE); - if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), "New function name", name, newname)) + if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"New function name", name, newname)) { - symbolMap.SetSymbolName(sym,newname); + symbolMap.SetSymbolName(sym, newname.c_str()); redraw(); SendMessage(GetParent(wnd),WM_DEB_MAPLOADED,0,0); } } else { - MessageBox(MainWindow::GetHWND(),"No symbol selected",0,0); + MessageBox(MainWindow::GetHWND(), L"No symbol selected",0,0); } } break; @@ -904,7 +909,7 @@ void CtrlDisAsmView::search(bool continueSearch) if (continueSearch == false || searchQuery[0] == 0) { - if (InputBox_GetString(MainWindow::GetHInstance(),MainWindow::GetHWND(),"Search for:","",searchQuery) == false + if (InputBox_GetString(MainWindow::GetHInstance(),MainWindow::GetHWND(),L"Search for:","",searchQuery) == false || searchQuery[0] == 0) { SetFocus(wnd); @@ -924,9 +929,8 @@ void CtrlDisAsmView::search(bool continueSearch) // limit address to sensible ranges if (searchAddress < 0x04000000) searchAddress = 0x04000000; if (searchAddress >= 0x04200000 && searchAddress < 0x08000000) searchAddress = 0x08000000; - if (searchAddress >= 0x0A000000) - { - MessageBox(wnd,"Not found","Search",MB_OK); + if (searchAddress >= 0x0A000000) { + MessageBox(wnd,L"Not found",L"Search",MB_OK); return; } @@ -951,7 +955,7 @@ void CtrlDisAsmView::search(bool continueSearch) merged[mergePos] = 0; // match! - if (strstr(merged,searchQuery) != NULL) + if (strstr(merged, searchQuery.c_str()) != NULL) { matchAddress = searchAddress; searching = false; @@ -970,20 +974,20 @@ void CtrlDisAsmView::search(bool continueSearch) if (searchAddress >= 0x04200000 && searchAddress < 0x08000000) searchAddress = 0x08000000; } - MessageBox(wnd,"Not found","Search",MB_OK); + MessageBox(wnd,L"Not found",L"Search",MB_OK); searching = false; } void CtrlDisAsmView::disassembleToFile() { - char fileName[MAX_PATH]; + wchar_t fileName[MAX_PATH]; u32 size; // get size if (executeExpressionWindow(wnd,debugger,size) == false) return; if (size == 0 || size > 10*1024*1024) { - MessageBox(wnd,"Invalid size!","Error",MB_OK); + MessageBox(wnd,L"Invalid size!",L"Error",MB_OK); return; } @@ -995,7 +999,7 @@ void CtrlDisAsmView::disassembleToFile() ofn.lpstrFile = fileName ; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof( fileName ); - ofn.lpstrFilter = "All files"; + ofn.lpstrFilter = L"All files"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL ; ofn.nMaxFileTitle = 0 ; @@ -1004,10 +1008,9 @@ void CtrlDisAsmView::disassembleToFile() if (GetSaveFileName(&ofn) == false) return; - FILE* output = fopen(fileName,"w"); - if (output == NULL) - { - MessageBox(wnd,"Could not open file!","Error",MB_OK); + FILE* output = _wfopen(fileName, L"w"); + if (output == NULL) { + MessageBox(wnd,L"Could not open file!",L"Error",MB_OK); return; } @@ -1059,14 +1062,14 @@ void CtrlDisAsmView::disassembleToFile() } fclose(output); - MessageBox(wnd,"Finished!","Done",MB_OK); + MessageBox(wnd,L"Finished!",L"Done",MB_OK); } void CtrlDisAsmView::getOpcodeText(u32 address, char* dest) { - char opcode[64],arguments[256]; + char opcode[64]; + char arguments[256]; const char *dis = debugger->disasm(address, instructionSize); parseDisasm(dis,opcode,arguments); - sprintf(dest,"%s %s",opcode,arguments); } \ No newline at end of file diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index aefbc9eb5f..c9437c8f08 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -64,7 +64,7 @@ class CtrlDisAsmView std::vector jumpStack; bool controlHeld; - char searchQuery[256]; + std::string searchQuery; int matchAddress; bool searching; bool dontRedraw; diff --git a/Windows/Debugger/CtrlMemView.cpp b/Windows/Debugger/CtrlMemView.cpp index c00819f20c..c7086f45e2 100644 --- a/Windows/Debugger/CtrlMemView.cpp +++ b/Windows/Debugger/CtrlMemView.cpp @@ -9,6 +9,7 @@ #include "../resource.h" #include "../../Core/MemMap.h" #include "../W32Util/Misc.h" +#include "Windows/InputBox.h" #include "../Main.h" #include "../../Core/Debugger/SymbolMap.h" @@ -16,29 +17,32 @@ #include "DebuggerShared.h" #include "CtrlMemView.h" -TCHAR CtrlMemView::szClassName[] = _T("CtrlMemView"); +wchar_t CtrlMemView::szClassName[] = L"CtrlMemView"; extern HMENU g_hPopupMenus; CtrlMemView::CtrlMemView(HWND _wnd) { - wnd=_wnd; - SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG)this); - SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL); - SetScrollRange(wnd, SB_VERT, -1,1,TRUE); + wnd=_wnd; + SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG)this); + SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL); + SetScrollRange(wnd, SB_VERT, -1,1,TRUE); - rowHeight = g_Config.iFontHeight; - charWidth = g_Config.iFontWidth; + rowHeight = g_Config.iFontHeight; + charWidth = g_Config.iFontWidth; - font = - CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,"Lucida Console"); - underlineFont = - CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,"Lucida Console"); - curAddress=0; - mode=MV_NORMAL; - debugger = 0; + font = + CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); + underlineFont = + CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); + curAddress=0; + debugger = 0; + searchQuery = ""; + matchAddress = -1; + searching = false; + ctrlDown = false; hasFocus = false; windowStart = curAddress; @@ -165,8 +169,6 @@ CtrlMemView *CtrlMemView::getFrom(HWND hwnd) void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) { - if (!debugger) return; - // draw to a bitmap for double buffering PAINTSTRUCT ps; HDC actualHdc = BeginPaint(wnd, &ps); @@ -197,114 +199,68 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) sprintf(temp,"%08X",address); SetTextColor(hdc,0x600000); - TextOut(hdc,addressStart,rowY,temp,(int)strlen(temp)); + TextOutA(hdc,addressStart,rowY,temp,(int)strlen(temp)); SetTextColor(hdc,0x000000); - if (debugger->isAlive()) + + u32 memory[4]; + bool valid = debugger != NULL && debugger->isAlive() && Memory::IsValidAddress(address); + if (valid) { + memory[0] = debugger->readMemory(address); + memory[1] = debugger->readMemory(address+4); + memory[2] = debugger->readMemory(address+8); + memory[3] = debugger->readMemory(address+12); + } - switch(mode) { - case MV_NORMAL: + u8* m = (u8*) memory; + for (int j = 0; j < rowSize; j++) + { + if (valid) sprintf(temp,"%02X",m[j]); + else strcpy(temp,"??"); + + unsigned char c = m[j]; + if (c < 32 || c >= 128 || valid == false) c = '.'; + + if (address+j == curAddress && searching == false) + { + COLORREF oldBkColor = GetBkColor(hdc); + COLORREF oldTextColor = GetTextColor(hdc); + + if (hasFocus && !asciiSelected) { - u32 memory[4]; - if (Memory::IsValidAddress(address)) - { - memory[0] = debugger->readMemory(address); - memory[1] = debugger->readMemory(address+4); - memory[2] = debugger->readMemory(address+8); - memory[3] = debugger->readMemory(address+12); - } - else - { - memory[0] = memory[1] = memory[2] = memory[3] = 0xFFFFFFFF; - } - - u8* m = (u8*) memory; - for (int j = 0; j < rowSize; j++) - { - sprintf(temp,"%02X",m[j]); - unsigned char c = m[j]; - if (c < 32 || c >= 128) c = '.'; - - if (address+j == curAddress) - { - COLORREF oldBkColor = GetBkColor(hdc); - COLORREF oldTextColor = GetTextColor(hdc); - - if (hasFocus && !asciiSelected) - { - SetTextColor(hdc,0xFFFFFF); - SetBkColor(hdc,0xFF9933); - if (selectedNibble == 0) SelectObject(hdc,(HGDIOBJ)underlineFont); - } else { - SetTextColor(hdc,0); - SetBkColor(hdc,0xC0C0C0); - } - TextOut(hdc,hexStart+j*3*charWidth,rowY,&temp[0],1); - - if (hasFocus && !asciiSelected) - { - if (selectedNibble == 1) SelectObject(hdc,(HGDIOBJ)underlineFont); - else SelectObject(hdc,(HGDIOBJ)font); - } - TextOut(hdc,hexStart+j*3*charWidth+charWidth,rowY,&temp[1],1); - - if (hasFocus && asciiSelected) - { - SetTextColor(hdc,0xFFFFFF); - SetBkColor(hdc,0xFF9933); - } else { - SetTextColor(hdc,0); - SetBkColor(hdc,0xC0C0C0); - SelectObject(hdc,(HGDIOBJ)font); - } - TextOut(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1); - - SetTextColor(hdc,oldTextColor); - SetBkColor(hdc,oldBkColor); - } else { - TextOut(hdc,hexStart+j*3*charWidth,rowY,temp,2); - TextOut(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1); - } - } + SetTextColor(hdc,0xFFFFFF); + SetBkColor(hdc,0xFF9933); + if (selectedNibble == 0) SelectObject(hdc,(HGDIOBJ)underlineFont); + } else { + SetTextColor(hdc,0); + SetBkColor(hdc,0xC0C0C0); } - break; -/* case MV_SYMBOLS: + TextOutA(hdc,hexStart+j*3*charWidth,rowY,&temp[0],1); + + if (hasFocus && !asciiSelected) { - SetTextColor(hdc,0x0000FF); - int fn = symbolMap.GetSymbolNum(address); - if (fn==-1) - { - sprintf(temp, "%s (ns)", Memory::GetAddressName(address)); - } - else - sprintf(temp, "%s (0x%x b)", symbolMap.GetSymbolName(fn),symbolMap.GetSymbolSize(fn)); - TextOut(hdc,200,rowY1,temp,(int)strlen(temp)); + if (selectedNibble == 1) SelectObject(hdc,(HGDIOBJ)underlineFont); + else SelectObject(hdc,(HGDIOBJ)font); + } + TextOutA(hdc,hexStart+j*3*charWidth+charWidth,rowY,&temp[1],1); - SetTextColor(hdc,0x000000); - - if (align==4) - { - u32 value = Memory::ReadUnchecked_U32(address); - int num = symbolMap.GetSymbolNum(value); - if (num != -1) - sprintf(temp, "%08x [%s]", value, symbolMap.GetSymbolName(num)); - else - sprintf(temp, "%08x", value); - } - else if (align==2) - { - u16 value = Memory::ReadUnchecked_U16(address); - int num = symbolMap.GetSymbolNum(value); - if (num != -1) - sprintf(temp, "%04x [%s]", value, symbolMap.GetSymbolName(num)); - else - sprintf(temp, "%04x", value); - } + if (hasFocus && asciiSelected) + { + SetTextColor(hdc,0xFFFFFF); + SetBkColor(hdc,0xFF9933); + } else { + SetTextColor(hdc,0); + SetBkColor(hdc,0xC0C0C0); + SelectObject(hdc,(HGDIOBJ)font); + } + TextOutA(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1); - TextOut(hdc,70,rowY1,temp,(int)strlen(temp)); - break; - }*/ + SetTextColor(hdc,oldTextColor); + SetBkColor(hdc,oldBkColor); + } else { + TextOutA(hdc,hexStart+j*3*charWidth,rowY,temp,2); + TextOutA(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1); } } } @@ -347,13 +303,27 @@ void CtrlMemView::onVScroll(WPARAM wParam, LPARAM lParam) void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam) { - if (ctrlDown && tolower(wParam & 0xFFFF) == 'g') - { - ctrlDown = false; - u32 addr; - if (executeExpressionWindow(wnd,debugger,addr) == false) return; - gotoAddr(addr); - return; + if (ctrlDown) + { + switch (tolower(wParam & 0xFFFF)) + { + case 'g': + { + ctrlDown = false; + u32 addr; + if (executeExpressionWindow(wnd,debugger,addr) == false) return; + gotoAddr(addr); + return; + } + break; + case 'f': + case 's': + search(false); + return; + case 'c': + search(true); + return; + } } switch (wParam & 0xFFFF) @@ -458,7 +428,7 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) if (!Core_IsStepping()) // If emulator isn't paused { - MessageBox(wnd,"You have to pause the emulator first","Sorry",0); + MessageBox(wnd,L"You have to pause the emulator first",0,0); break; } else @@ -477,7 +447,7 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) if (asciiSelected) { unsigned char c = Memory::IsValidAddress(curAddress) ? Memory::ReadUnchecked_U8(curAddress) : '.'; - if (c < 32 || c >= 128) c = '.'; + if (c < 32|| c >= 128) c = '.'; sprintf(temp,"%c",c); } else { sprintf(temp,"%02X",Memory::IsValidAddress(curAddress) ? Memory::ReadUnchecked_U8(curAddress) : 0xFF); @@ -485,6 +455,14 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) W32Util::CopyTextToClipboard(wnd,temp); } break; + + case ID_MEMVIEW_COPYADDRESS: + { + char temp[24]; + sprintf(temp,"0x%08X",curAddress); + W32Util::CopyTextToClipboard(wnd,temp); + } + break; } return; } @@ -600,4 +578,103 @@ void CtrlMemView::scrollCursor(int bytes) updateStatusBarText(); redraw(); +} + +void CtrlMemView::search(bool continueSearch) +{ + u32 searchAddress; + if (continueSearch == false || searchQuery[0] == 0) + { + ctrlDown = false; + if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Search for", "",searchQuery) == false) + { + SetFocus(wnd); + return; + } + SetFocus(wnd); + searchAddress = curAddress+1; + } else { + searchAddress = matchAddress+1; + } + + std::vector searchData; + if (asciiSelected) + { + for (int i = 0; i < searchQuery.length(); i++) + { + char c = searchQuery[i]; + searchData.push_back(c); + } + } else { + int index = 0; + while (index < searchQuery.size()) + { + if (searchQuery[index] == ' ' || searchQuery[index] == '\t') + { + index++; + continue; + } + + u8 value = 0; + for (int i = 0; i < 2; i++) + { + char c = tolower(searchQuery[index++]); + if (c >= 'a' && c <= 'f') + { + value |= (c-'a'+10) << (1-i)*4; + } else if (c >= '0' && c <= '9') + { + value |= (c-'0') << (1-i)*4; + } else { + MessageBox(wnd,L"Invalid search text.",L"Error",MB_OK); + return; + } + } + + searchData.push_back(value); + } + } + + std::vector> memoryAreas; + memoryAreas.push_back(std::pair(0x04000000,0x04200000)); + memoryAreas.push_back(std::pair(0x08000000,0x0A000000)); + + searching = true; + redraw(); // so the cursor is disabled + for (int i = 0; i < memoryAreas.size(); i++) + { + u32 segmentStart = memoryAreas[i].first; + u32 segmentEnd = memoryAreas[i].second; + u8* dataPointer = Memory::GetPointer(segmentStart); + if (dataPointer == NULL) continue; // better safe than sorry, I guess + + if (searchAddress < segmentStart) searchAddress = segmentStart; + if (searchAddress >= segmentEnd) continue; + + int index = searchAddress-segmentStart; + int endIndex = segmentEnd-segmentStart-searchData.size(); + + while (index < endIndex) + { + // cancel search + if ((index % 256) == 0 && GetAsyncKeyState(VK_ESCAPE)) + { + searching = false; + return; + } + + if (memcmp(&dataPointer[index],searchData.data(),searchData.size()) == 0) + { + matchAddress = index+segmentStart; + searching = false; + gotoAddr(matchAddress); + return; + } + index++; + } + } + + MessageBox(wnd,L"Not found",L"Search",MB_OK); + searching = false; + redraw(); } \ No newline at end of file diff --git a/Windows/Debugger/CtrlMemView.h b/Windows/Debugger/CtrlMemView.h index 8aa8193cf7..879edc1969 100644 --- a/Windows/Debugger/CtrlMemView.h +++ b/Windows/Debugger/CtrlMemView.h @@ -19,13 +19,6 @@ #include "../../Core/Debugger/DebugInterface.h" -enum MemViewMode -{ - MV_NORMAL, - MV_SYMBOLS, - MV_MAX -}; - class CtrlMemView { HWND wnd; @@ -47,12 +40,16 @@ class CtrlMemView bool ctrlDown; int visibleRows; + + std::string searchQuery; + int matchAddress; + bool searching; bool hasFocus; - static TCHAR szClassName[]; + static wchar_t szClassName[]; DebugInterface *debugger; - MemViewMode mode; void updateStatusBarText(); + void search(bool continueSearch); public: CtrlMemView(HWND _wnd); ~CtrlMemView(); @@ -79,12 +76,6 @@ public: void onMouseMove(WPARAM wParam, LPARAM lParam, int button); void redraw(); - void setMode(MemViewMode m) - { - mode=m; - redraw(); - } - void gotoPoint(int x, int y); void gotoAddr(unsigned int addr); void scrollWindow(int lines); diff --git a/Windows/Debugger/CtrlRegisterList.cpp b/Windows/Debugger/CtrlRegisterList.cpp index 8f06afaa5c..a1e2a928fd 100644 --- a/Windows/Debugger/CtrlRegisterList.cpp +++ b/Windows/Debugger/CtrlRegisterList.cpp @@ -3,8 +3,9 @@ #include #include +#include "util/text/utf8.h" #include "../resource.h" -#include "../../Core/MemMap.h" +#include "Core/MemMap.h" #include "../W32Util/Misc.h" #include "../InputBox.h" @@ -133,7 +134,7 @@ CtrlRegisterList::CtrlRegisterList(HWND _wnd) rowHeight=g_Config.iFontHeight; font = CreateFont(rowHeight,g_Config.iFontWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY,DEFAULT_PITCH,"Lucida Console"); + DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); selecting=false; selection=0; category=0; @@ -201,8 +202,8 @@ void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam) SelectObject(hdc,i==category?currentPen:nullPen); SelectObject(hdc,i==category?pcBrush:nullBrush); Rectangle(hdc,width*i/nc,0,width*(i+1)/nc,rowHeight); - const TCHAR *name = cpu->GetCategoryName(i); - TextOut(hdc,width*i/nc,1,name,(int)strlen(name)); + const char *name = cpu->GetCategoryName(i); + TextOutA(hdc,width*i/nc,1,name,(int)strlen(name)); } int numRows=rect.bottom/rowHeight; @@ -259,7 +260,7 @@ void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam) char temp[256]; int temp_len = sprintf(temp,"%s",cpu->GetRegName(category,i)); SetTextColor(hdc,0x600000); - TextOut(hdc,17,rowY1,temp,temp_len); + TextOutA(hdc,17,rowY1,temp,temp_len); SetTextColor(hdc,0x000000); cpu->PrintRegValue(category,i,temp); @@ -267,7 +268,7 @@ void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam) SetTextColor(hdc, 0x0000FF); else SetTextColor(hdc,0x004000); - TextOut(hdc,77,rowY1,temp,(int)strlen(temp)); + TextOutA(hdc,77,rowY1,temp,(int)strlen(temp)); } else if (category == 0 && i < REGISTERS_END) { char temp[256]; @@ -291,13 +292,13 @@ void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam) } SetTextColor(hdc,0x600000); - TextOut(hdc,17,rowY1,temp,len); + TextOutA(hdc,17,rowY1,temp,len); len = sprintf(temp,"%08X",value); if (changedCat0Regs[i]) SetTextColor(hdc, 0x0000FF); else SetTextColor(hdc,0x004000); - TextOut(hdc,77,rowY1,temp,(int)strlen(temp)); + TextOutA(hdc,77,rowY1,temp,(int)strlen(temp)); } /* @@ -385,7 +386,7 @@ void CtrlRegisterList::copyRegisterValue() { if (!Core_IsStepping()) { - MessageBox(wnd,"Can't copy register values while the core is running.","Error",MB_OK); + MessageBox(wnd,L"Can't copy register values while the core is running.",L"Error",MB_OK); return; } @@ -423,7 +424,7 @@ void CtrlRegisterList::editRegisterValue() { if (!Core_IsStepping()) { - MessageBox(wnd,"Can't change registers while the core is running.","Error",MB_OK); + MessageBox(wnd,L"Can't change registers while the core is running.",L"Error",MB_OK); return; } @@ -454,10 +455,10 @@ void CtrlRegisterList::editRegisterValue() char temp[256]; sprintf(temp,"%08X",val); - if (InputBox_GetString(GetModuleHandle(NULL),wnd,"Set new value",temp,temp)) - { - if (parseExpression(temp,cpu,val) == false) - { + + std::string value = temp; + if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Set new value",value,value)) { + if (parseExpression(value.c_str(),cpu,val) == false) { displayExpressionError(wnd); } else { switch (reg) diff --git a/Windows/Debugger/DebuggerShared.cpp b/Windows/Debugger/DebuggerShared.cpp index ddf37c8b5f..7771edb5f2 100644 --- a/Windows/Debugger/DebuggerShared.cpp +++ b/Windows/Debugger/DebuggerShared.cpp @@ -1,7 +1,9 @@ +#include "util/text/utf8.h" + #include "DebuggerShared.h" #include "../InputBox.h" -bool parseExpression(char* exp, DebugInterface* cpu, u32& dest) +bool parseExpression(const char* exp, DebugInterface* cpu, u32& dest) { PostfixExpression postfix; if (cpu->initExpression(exp,postfix) == false) return false; @@ -10,18 +12,18 @@ bool parseExpression(char* exp, DebugInterface* cpu, u32& dest) void displayExpressionError(HWND hwnd) { - MessageBox(hwnd,getExpressionError(),"Invalid expression",MB_OK); + MessageBox(hwnd,ConvertUTF8ToWString(getExpressionError()).c_str(),L"Invalid expression",MB_OK); } bool executeExpressionWindow(HWND hwnd, DebugInterface* cpu, u32& dest) { - char expression[1024]; - if (InputBox_GetString(GetModuleHandle(NULL), hwnd, "Expression", "",expression) == false) + std::string expression; + if (InputBox_GetString(GetModuleHandle(NULL), hwnd, L"Expression", "",expression) == false) { return false; } - if (parseExpression(expression,cpu,dest) == false) + if (parseExpression(expression.c_str(), cpu, dest) == false) { displayExpressionError(hwnd); return false; diff --git a/Windows/Debugger/DebuggerShared.h b/Windows/Debugger/DebuggerShared.h index d5e8835e0a..1500d46392 100644 --- a/Windows/Debugger/DebuggerShared.h +++ b/Windows/Debugger/DebuggerShared.h @@ -16,4 +16,4 @@ enum { WM_DEB_GOTOWPARAM = WM_USER+2, bool executeExpressionWindow(HWND hwnd, DebugInterface* cpu, u32& dest); void displayExpressionError(HWND hwnd); -bool parseExpression(char* exp, DebugInterface* cpu, u32& dest); \ No newline at end of file +bool parseExpression(const char* exp, DebugInterface* cpu, u32& dest); \ No newline at end of file diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 126aa77ffa..488b843fe4 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -26,6 +26,7 @@ #include "Core/MIPS/MIPSAnalyst.h" #include "base/stringutil.h" +#include "util/text/utf8.h" #ifdef THEMES #include "Windows/XPTheme.h" @@ -73,8 +74,9 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di { cpu = _cpu; lastTicks = CoreTiming::GetTicks(); + keepStatusBarText = false; - SetWindowText(m_hDlg,_cpu->GetName()); + SetWindowText(m_hDlg, ConvertUTF8ToWString(_cpu->GetName()).c_str()); #ifdef THEMES //if (WTL::CTheme::IsThemingSupported()) //EnableThemeDialogTexture(m_hDlg ,ETDT_ENABLETAB); @@ -109,12 +111,12 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di ZeroMemory (&tcItem,sizeof (tcItem)); tcItem.mask = TCIF_TEXT; tcItem.dwState = 0; - tcItem.pszText = "Regs"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Regs"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; tcItem.iImage = 0; int result1 = TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "Funcs"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Funcs"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; int result2 = TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_NORMAL); ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_HIDE); @@ -149,7 +151,7 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di changeSubWindow(SUBWIN_FIRST); // init status bar - statusBarWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", m_hDlg, IDC_DISASMSTATUSBAR); + statusBarWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, L"", m_hDlg, IDC_DISASMSTATUSBAR); if (g_Config.bDisplayStatusBar == false) { ShowWindow(statusBarWnd,SW_HIDE); @@ -412,8 +414,21 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) changeSubWindow(SUBWIN_STACKFRAMES); break; + case ID_DEBUG_DSIPLAYREGISTERLIST: + TabCtrl_SetCurSel(GetDlgItem(m_hDlg, IDC_LEFTTABS),0); + ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_NORMAL); + ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_HIDE); + break; + + case ID_DEBUG_DSIPLAYFUNCTIONLIST: + TabCtrl_SetCurSel(GetDlgItem(m_hDlg, IDC_LEFTTABS),1); + ShowWindow(GetDlgItem(m_hDlg, IDC_REGLIST), SW_HIDE); + ShowWindow(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), SW_NORMAL); + break; + case ID_DEBUG_ADDBREAKPOINT: { + keepStatusBarText = true; bool isRunning = Core_IsActive(); if (isRunning) { @@ -430,6 +445,7 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) SetDebugMode(false); Core_EnableStepping(false); } + keepStatusBarText = false; } break; @@ -554,19 +570,19 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) u32 ra = currentMIPS->r[MIPS_REG_RA]; DWORD addr = Memory::ReadUnchecked_U32(pc); int count=1; - ComboBox_SetItemData(list,ComboBox_AddString(list,symbolMap.GetDescription(pc)),pc); + ComboBox_SetItemData(list, ComboBox_AddString(list, ConvertUTF8ToWString(symbolMap.GetDescription(pc)).c_str()), pc); if (symbolMap.GetDescription(pc) != symbolMap.GetDescription(ra)) { - ComboBox_SetItemData(list,ComboBox_AddString(list,symbolMap.GetDescription(ra)),ra); + ComboBox_SetItemData(list, ComboBox_AddString(list, ConvertUTF8ToWString(symbolMap.GetDescription(ra)).c_str()), ra); count++; } //walk the stack chain while (addr != 0xFFFFFFFF && addr!=0 && count++<20) { DWORD fun = Memory::ReadUnchecked_U32(addr+4); - const char *str = symbolMap.GetDescription(fun); - if (strlen(str)==0) - str = "(unknown)"; + const wchar_t *str = ConvertUTF8ToWString(symbolMap.GetDescription(fun)).c_str(); + if (wcslen(str) == 0) + str = L"(unknown)"; ComboBox_SetItemData(list, ComboBox_AddString(list,str), fun); addr = Memory::ReadUnchecked_U32(addr); } @@ -621,12 +637,12 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) } case WM_DEB_GOTOADDRESSEDIT: { - char szBuffer[256]; + wchar_t szBuffer[256]; CtrlDisAsmView *ptr = CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg,IDC_DISASMVIEW)); GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),szBuffer,256); u32 addr; - if (parseExpression(szBuffer,cpu,addr) == false) + if (parseExpression(ConvertWStringToUTF8(szBuffer).c_str(),cpu,addr) == false) { displayExpressionError(GetDlgItem(m_hDlg,IDC_ADDRESS)); } else { @@ -649,7 +665,8 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) changeSubWindow(SUBWIN_NEXT); break; case WM_DEB_SETSTATUSBARTEXT: - SendMessage(statusBarWnd,WM_SETTEXT,0,lParam); + if (!keepStatusBarText) + SendMessage(statusBarWnd,WM_SETTEXT,0,(LPARAM)ConvertUTF8ToWString((const char *)lParam).c_str()); break; case WM_DEB_GOTOHEXEDIT: { @@ -710,7 +727,7 @@ void CDisasm::updateThreadLabel(bool clear) sprintf(label,"Thread: %s",threadList->getCurrentThreadName()); } - SetDlgItemText(m_hDlg, IDC_THREADNAME,label); + SetDlgItemText(m_hDlg, IDC_THREADNAME, ConvertUTF8ToWString(label).c_str()); } void CDisasm::UpdateSize(WORD width, WORD height) @@ -782,7 +799,7 @@ void CDisasm::SetDebugMode(bool _bDebug) stackTraceView->loadStackTrace(); updateThreadLabel(false); - SetDlgItemText(m_hDlg, IDC_STOPGO, "Go"); + SetDlgItemText(m_hDlg, IDC_STOPGO, L"Go"); EnableWindow( GetDlgItem(hDlg, IDC_STEP), TRUE); EnableWindow( GetDlgItem(hDlg, IDC_STEPOVER), TRUE); EnableWindow( GetDlgItem(hDlg, IDC_STEPHLE), TRUE); @@ -802,7 +819,7 @@ void CDisasm::SetDebugMode(bool _bDebug) { updateThreadLabel(true); - SetDlgItemText(m_hDlg, IDC_STOPGO, "Stop"); + SetDlgItemText(m_hDlg, IDC_STOPGO, L"Stop"); EnableWindow( GetDlgItem(hDlg, IDC_STEP), FALSE); EnableWindow( GetDlgItem(hDlg, IDC_STEPOVER), FALSE); EnableWindow( GetDlgItem(hDlg, IDC_STEPHLE), FALSE); @@ -835,6 +852,7 @@ void CDisasm::UpdateDialog(bool _bComplete) ComboBox_ResetContent(gotoInt); for (int i=0; iredraw(); // Update Debug Counter - char tempTicks[24]; - sprintf(tempTicks, "%lld", CoreTiming::GetTicks()-lastTicks); + wchar_t tempTicks[24]; + _snwprintf(tempTicks, 24, L"%lld", CoreTiming::GetTicks()-lastTicks); SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks); // Update Register Dialog for (int i=0; iUpdate(); + + // repaint windows at the bottom. only the memory view needs to be forced to + // redraw. all others are updated manually + InvalidateRect (GetDlgItem(m_hDlg, IDC_DEBUGMEMVIEW), NULL, TRUE); + UpdateWindow (GetDlgItem(m_hDlg, IDC_DEBUGMEMVIEW)); } \ No newline at end of file diff --git a/Windows/Debugger/Debugger_Disasm.h b/Windows/Debugger/Debugger_Disasm.h index d5425ca2ea..4168a27d5c 100644 --- a/Windows/Debugger/Debugger_Disasm.h +++ b/Windows/Debugger/Debugger_Disasm.h @@ -37,6 +37,7 @@ private: CtrlStackTraceView* stackTraceView; std::vector displayedBreakPoints_; std::vector displayedMemChecks_; + bool keepStatusBarText; BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam); void UpdateSize(WORD width, WORD height); diff --git a/Windows/Debugger/Debugger_Lists.cpp b/Windows/Debugger/Debugger_Lists.cpp index 51427d2c31..26bf9ebd1c 100644 --- a/Windows/Debugger/Debugger_Lists.cpp +++ b/Windows/Debugger/Debugger_Lists.cpp @@ -8,10 +8,11 @@ #include "Windows/main.h" #include "BreakpointWindow.h" #include "../../Core/HLE/sceKernelThread.h" +#include "util/text/utf8.h" typedef struct { - char* name; + wchar_t *name; float size; } ListViewColumn; @@ -20,31 +21,31 @@ enum { BPL_TYPE, BPL_OFFSET, BPL_SIZELABEL, BPL_OPCODE, BPL_CONDITION, BPL_HITS, enum { SF_ENTRY, SF_ENTRYNAME, SF_CURPC, SF_CUROPCODE, SF_CURSP, SF_FRAMESIZE, SF_COLUMNCOUNT }; ListViewColumn threadColumns[TL_COLUMNCOUNT] = { - { "Name", 0.20f }, - { "PC", 0.15f }, - { "Entry Point", 0.15f }, - { "Priority", 0.15f }, - { "State", 0.15f }, - { "Wait type", 0.20f } + { L"Name", 0.20f }, + { L"PC", 0.15f }, + { L"Entry Point", 0.15f }, + { L"Priority", 0.15f }, + { L"State", 0.15f }, + { L"Wait type", 0.20f } }; ListViewColumn breakpointColumns[BPL_COLUMNCOUNT] = { - { "Type", 0.12f }, - { "Offset", 0.12f }, - { "Size/Label", 0.18f }, - { "Opcode", 0.28f }, - { "Condition", 0.17f }, - { "Hits", 0.05f }, - { "Enabled", 0.08f } + { L"Type", 0.12f }, + { L"Offset", 0.12f }, + { L"Size/Label", 0.18f }, + { L"Opcode", 0.28f }, + { L"Condition", 0.17f }, + { L"Hits", 0.05f }, + { L"Enabled", 0.08f } }; ListViewColumn stackTraceColumns[SF_COLUMNCOUNT] = { - { "Entry", 0.12f }, - { "Name", 0.24f }, - { "PC", 0.12f }, - { "Opcode", 0.28f }, - { "SP", 0.12f }, - { "Frame Size", 0.12f } + { L"Entry", 0.12f }, + { L"Name", 0.24f }, + { L"PC", 0.12f }, + { L"Opcode", 0.28f }, + { L"SP", 0.12f }, + { L"Frame Size", 0.12f } }; const int POPUP_SUBMENU_ID_BREAKPOINTLIST = 5; @@ -73,8 +74,7 @@ void CtrlThreadList::setDialogItem(HWND hwnd) GetWindowRect(wnd,&rect); int totalListSize = (rect.right-rect.left-20); - for (int i = 0; i < TL_COLUMNCOUNT; i++) - { + for (int i = 0; i < TL_COLUMNCOUNT; i++) { lvc.cx = threadColumns[i].size * totalListSize; lvc.pszText = threadColumns[i].name; ListView_InsertColumn(wnd, i, &lvc); @@ -201,61 +201,62 @@ void CtrlThreadList::handleNotify(LPARAM lParam) switch (dispInfo->item.iSubItem) { case TL_NAME: - strcpy(stringBuffer,threads[index].name); + wcscpy(stringBuffer, ConvertUTF8ToWString(threads[index].name).c_str()); break; case TL_PROGRAMCOUNTER: switch (threads[index].status) { case THREADSTATUS_DORMANT: case THREADSTATUS_DEAD: - sprintf(stringBuffer,"N/A"); + wcscpy(stringBuffer, L"N/A"); break; default: - sprintf(stringBuffer,"0x%08X",threads[index].curPC); + wsprintf(stringBuffer, L"0x%08X",threads[index].curPC); break; }; break; case TL_ENTRYPOINT: - sprintf(stringBuffer,"0x%08X",threads[index].entrypoint); + wsprintf(stringBuffer,L"0x%08X",threads[index].entrypoint); break; case TL_PRIORITY: - sprintf(stringBuffer,"%d",threads[index].priority); + wsprintf(stringBuffer,L"%d",threads[index].priority); break; case TL_STATE: switch (threads[index].status) { case THREADSTATUS_RUNNING: - strcpy(stringBuffer,"Running"); + wcscpy(stringBuffer,L"Running"); break; case THREADSTATUS_READY: - strcpy(stringBuffer,"Ready"); + wcscpy(stringBuffer,L"Ready"); break; case THREADSTATUS_WAIT: - strcpy(stringBuffer,"Waiting"); + wcscpy(stringBuffer,L"Waiting"); break; case THREADSTATUS_SUSPEND: - strcpy(stringBuffer,"Suspended"); + wcscpy(stringBuffer,L"Suspended"); break; case THREADSTATUS_DORMANT: - strcpy(stringBuffer,"Dormant"); + wcscpy(stringBuffer,L"Dormant"); break; case THREADSTATUS_DEAD: - strcpy(stringBuffer,"Dead"); + wcscpy(stringBuffer,L"Dead"); break; case THREADSTATUS_WAITSUSPEND: - strcpy(stringBuffer,"Waiting/Suspended"); + wcscpy(stringBuffer,L"Waiting/Suspended"); break; default: - strcpy(stringBuffer,"Invalid"); + wcscpy(stringBuffer,L"Invalid"); break; } break; case TL_WAITTYPE: - strcpy(stringBuffer,getWaitTypeName(threads[index].waitType)); + wcscpy(stringBuffer, ConvertUTF8ToWString(getWaitTypeName(threads[index].waitType)).c_str()); break; } - if (stringBuffer[0] == 0) strcat(stringBuffer,"Invalid"); + if (stringBuffer[0] == 0) + wcscat(stringBuffer,L"Invalid"); dispInfo->item.pszText = stringBuffer; } } @@ -563,95 +564,97 @@ void CtrlBreakpointList::handleNotify(LPARAM lParam) int index = getBreakpointIndex(dispInfo->item.iItem,isMemory); if (index == -1) return; - breakpointText[0] = 0; + breakpointText = L""; switch (dispInfo->item.iSubItem) { case BPL_TYPE: { - if (isMemory) - { - switch (displayedMemChecks_[index].cond) - { + if (isMemory) { + switch (displayedMemChecks_[index].cond) { case MEMCHECK_READ: - strcpy(breakpointText, "Read"); + breakpointText = L"Read"; break; case MEMCHECK_WRITE: - strcpy(breakpointText, "Write"); + breakpointText = L"Write"; break; case MEMCHECK_READWRITE: - strcpy(breakpointText, "Read/Write"); + breakpointText = L"Read/Write"; break; } } else { - strcpy(breakpointText,"Execute"); + breakpointText = L"Execute"; } } break; case BPL_OFFSET: { - if (isMemory) - { - sprintf(breakpointText,"0x%08X",displayedMemChecks_[index].start); + wchar_t temp[256]; + if (isMemory) { + wsprintf(temp,L"0x%08X",displayedMemChecks_[index].start); } else { - sprintf(breakpointText,"0x%08X",displayedBreakPoints_[index].addr); + wsprintf(temp,L"0x%08X",displayedBreakPoints_[index].addr); } + breakpointText = temp; } break; case BPL_SIZELABEL: { - if (isMemory) - { + if (isMemory) { auto mc = displayedMemChecks_[index]; - if (mc.end == 0) sprintf(breakpointText,"0x%08X",1); - else sprintf(breakpointText,"0x%08X",mc.end-mc.start); + wchar_t temp[256]; + if (mc.end == 0) + wsprintf(temp,L"0x%08X",1); + else + wsprintf(temp,L"0x%08X",mc.end-mc.start); + breakpointText = temp; } else { const char* sym = cpu->findSymbolForAddress(displayedBreakPoints_[index].addr); if (sym != NULL) { - strcpy(breakpointText,sym); + breakpointText = ConvertUTF8ToWString(sym); } else { - strcpy(breakpointText,"-"); + breakpointText = L"-"; } } } break; case BPL_OPCODE: { - if (isMemory) - { - strcpy(breakpointText,"-"); + if (isMemory) { + breakpointText = L"-"; } else { - disasm->getOpcodeText(displayedBreakPoints_[index].addr,breakpointText); + char temp[256]; + disasm->getOpcodeText(displayedBreakPoints_[index].addr, temp); + breakpointText = ConvertUTF8ToWString(temp); } } break; case BPL_CONDITION: { - if (isMemory || displayedBreakPoints_[index].hasCond == false) - { - strcpy(breakpointText,"-"); + if (isMemory || displayedBreakPoints_[index].hasCond == false) { + breakpointText = L"-"; } else { - strcpy(breakpointText,displayedBreakPoints_[index].cond.expressionString); + breakpointText = ConvertUTF8ToWString(displayedBreakPoints_[index].cond.expressionString); } } break; case BPL_HITS: { - if (isMemory) - { - sprintf(breakpointText,"%d",displayedMemChecks_[index].numHits); + if (isMemory) { + wchar_t temp[256]; + wsprintf(temp,L"%d",displayedMemChecks_[index].numHits); + breakpointText = temp; } else { - strcpy(breakpointText,"-"); + breakpointText = L"-"; } } break; case BPL_ENABLED: { - if (isMemory) - { - strcpy(breakpointText,displayedMemChecks_[index].result & MEMCHECK_BREAK ? "True" : "False"); + if (isMemory) { + breakpointText = displayedMemChecks_[index].result & MEMCHECK_BREAK ? L"True" : L"False"; } else { - strcpy(breakpointText,displayedBreakPoints_[index].enabled ? "True" : "False"); + breakpointText = displayedBreakPoints_[index].enabled ? L"True" : L"False"; } } break; @@ -659,8 +662,9 @@ void CtrlBreakpointList::handleNotify(LPARAM lParam) return; } - if (breakpointText[0] == 0) strcat(breakpointText,"Invalid"); - dispInfo->item.pszText = breakpointText; + if (breakpointText.empty()) + breakpointText = L"Invalid"; + dispInfo->item.pszText = &breakpointText[0]; } } @@ -808,34 +812,37 @@ void CtrlStackTraceView::handleNotify(LPARAM lParam) switch (dispInfo->item.iSubItem) { case SF_ENTRY: - sprintf(stringBuffer,"%08X",frames[index].entry); + wsprintf(stringBuffer,L"%08X",frames[index].entry); break; case SF_ENTRYNAME: { const char* sym = cpu->findSymbolForAddress(frames[index].entry); - if (sym != NULL) - { - strcpy(stringBuffer,sym); + if (sym != NULL) { + wcscpy(stringBuffer, ConvertUTF8ToWString(sym).c_str()); } else { - strcpy(stringBuffer,"-"); + wcscpy(stringBuffer,L"-"); } } break; case SF_CURPC: - sprintf(stringBuffer,"%08X",frames[index].pc); + wsprintf(stringBuffer,L"%08X",frames[index].pc); break; case SF_CUROPCODE: - disasm->getOpcodeText(frames[index].pc,stringBuffer); + { + char temp[512]; + disasm->getOpcodeText(frames[index].pc,temp); + wcscpy(stringBuffer, ConvertUTF8ToWString(temp).c_str()); + } break; case SF_CURSP: - sprintf(stringBuffer,"%08X",frames[index].sp); + wsprintf(stringBuffer,L"%08X",frames[index].sp); break; case SF_FRAMESIZE: - sprintf(stringBuffer,"%08X",frames[index].stackSize); + wsprintf(stringBuffer,L"%08X",frames[index].stackSize); break; } - if (stringBuffer[0] == 0) strcat(stringBuffer,"Invalid"); + if (stringBuffer[0] == 0) wcscat(stringBuffer, L"Invalid"); dispInfo->item.pszText = stringBuffer; } } diff --git a/Windows/Debugger/Debugger_Lists.h b/Windows/Debugger/Debugger_Lists.h index 9431e6720b..0c907b6204 100644 --- a/Windows/Debugger/Debugger_Lists.h +++ b/Windows/Debugger/Debugger_Lists.h @@ -10,7 +10,7 @@ class CtrlThreadList HWND wnd; WNDPROC oldProc; std::vector threads; - char stringBuffer[256]; + wchar_t stringBuffer[256]; public: void setDialogItem(HWND hwnd); @@ -29,7 +29,7 @@ class CtrlBreakpointList WNDPROC oldProc; std::vector displayedBreakPoints_; std::vector displayedMemChecks_; - char breakpointText[256]; + std::wstring breakpointText; DebugInterface* cpu; CtrlDisAsmView* disasm; @@ -63,7 +63,7 @@ class CtrlStackTraceView std::vector frames; DebugInterface* cpu; CtrlDisAsmView* disasm; - char stringBuffer[256]; + wchar_t stringBuffer[256]; public: void setCpu(DebugInterface* cpu) diff --git a/Windows/Debugger/Debugger_MemoryDlg.cpp b/Windows/Debugger/Debugger_MemoryDlg.cpp index 292a891777..fd912d9930 100644 --- a/Windows/Debugger/Debugger_MemoryDlg.cpp +++ b/Windows/Debugger/Debugger_MemoryDlg.cpp @@ -4,13 +4,15 @@ #include #include "..\resource.h" -#include "../../Core/Debugger/SymbolMap.h" -#include "Debugger_MemoryDlg.h" +#include "util/text/utf8.h" +#include "Core/Debugger/SymbolMap.h" +#include "Core/MIPS/MIPSDebugInterface.h" // BAD + +#include "Debugger_MemoryDlg.h" #include "CtrlMemView.h" #include "DebuggerShared.h" -#include "../../Core/MIPS/MIPSDebugInterface.h" // BAD RECT CMemoryDlg::slRect; @@ -47,15 +49,16 @@ LRESULT CALLBACK AddressEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM CMemoryDlg::CMemoryDlg(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_MEMORY, _hInstance,_hParent) { - cpu = _cpu; - TCHAR temp[256]; - sprintf(temp,"Memory Viewer - %s",cpu->GetName()); + cpu = _cpu; + wchar_t temp[256]; + wsprintf(temp,L"Memory Viewer - %S",cpu->GetName()); SetWindowText(m_hDlg,temp); + ShowWindow(m_hDlg,SW_HIDE); CtrlMemView *ptr = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); - ptr->setDebugger(_cpu); + ptr->setDebugger(_cpu); - Button_SetCheck(GetDlgItem(m_hDlg,IDC_RAM), TRUE); + Button_SetCheck(GetDlgItem(m_hDlg,IDC_RAM), TRUE); Button_SetCheck(GetDlgItem(m_hDlg,IDC_MODESYMBOLS), TRUE); GetWindowRect(GetDlgItem(m_hDlg,IDC_SYMBOLS),&slRect); @@ -96,6 +99,7 @@ void CMemoryDlg::NotifyMapLoaded() /* for (int i = 0; i < cpu->getMemMap()->numRegions; i++) { + // TODO: wchar_t int n = ComboBox_AddString(lb,cpu->getMemMap()->regions[i].name); ComboBox_SetItemData(lb,n,cpu->getMemMap()->regions[i].start); }*/ @@ -147,13 +151,6 @@ BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) } break; }; - break; - case IDC_MODENORMAL: - mv->setMode(MV_NORMAL); - break; - case IDC_MODESYMBOLS: - mv->setMode(MV_NORMAL); - // mv->setMode(MV_SYMBOLS); break; } } @@ -164,12 +161,11 @@ BOOL CMemoryDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) case WM_DEB_GOTOADDRESSEDIT: { CtrlMemView *mv = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_MEMVIEW)); - char temp[256]; + wchar_t temp[256]; u32 addr; GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),temp,255); - if (parseExpression(temp,cpu,addr) == false) - { + if (parseExpression(ConvertWStringToUTF8(temp).c_str(),cpu,addr) == false) { displayExpressionError(m_hDlg); } else { mv->gotoAddr(addr); diff --git a/Windows/Debugger/Debugger_VFPUDlg.cpp b/Windows/Debugger/Debugger_VFPUDlg.cpp index 5b94089407..67b4450cd1 100644 --- a/Windows/Debugger/Debugger_VFPUDlg.cpp +++ b/Windows/Debugger/Debugger_VFPUDlg.cpp @@ -4,6 +4,7 @@ #include #include #include "Windows/resource.h" +#include "util/text/utf8.h" #include "Core/Debugger/SymbolMap.h" #include "Windows/Debugger/Debugger_VFPUDlg.h" @@ -17,12 +18,13 @@ CVFPUDlg *vfpudlg; CVFPUDlg::CVFPUDlg(HINSTANCE _hInstance, HWND _hParent, DebugInterface *cpu_) : Dialog((LPCSTR)IDD_VFPU, _hInstance,_hParent) { cpu = cpu_; - TCHAR temp[256]; - sprintf(temp,"VFPU - %s",cpu->GetName()); + wchar_t temp[256]; + wsprintf(temp, L"VFPU - %S", cpu->GetName()); SetWindowText(m_hDlg,temp); + ShowWindow(m_hDlg,SW_HIDE); font = CreateFont(12,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, - "Lucida Console"); + L"Lucida Console"); HWND tabs = GetDlgItem(m_hDlg, IDC_TABDATATYPE); @@ -30,24 +32,24 @@ CVFPUDlg::CVFPUDlg(HINSTANCE _hInstance, HWND _hParent, DebugInterface *cpu_) : ZeroMemory (&tcItem,sizeof (tcItem)); tcItem.mask = TCIF_TEXT; tcItem.dwState = 0; - tcItem.pszText = "Float"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Float"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; tcItem.iImage = 0; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "HalfFloat"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"HalfFloat"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "Hex"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Hex"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "Bytes"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Bytes"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "Shorts"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Shorts"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); - tcItem.pszText = "Ints"; - tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1; + tcItem.pszText = L"Ints"; + tcItem.cchTextMax = (int)wcslen(tcItem.pszText)+1; TabCtrl_InsertItem(tabs, TabCtrl_GetItemCount(tabs),&tcItem); mode=0; Size(); @@ -146,7 +148,7 @@ BOOL CVFPUDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) Rectangle(hdc, 0, my, xStart, my+rowHeight); char temp[256]; int temp_len = sprintf_s(temp, "M%i00", matrix); - TextOut(hdc,3,my+2,temp,temp_len); + TextOutA(hdc,3,my+2,temp,temp_len); Rectangle(hdc,xStart,my+rowHeight,xStart+columnWidth*4,my+5*rowHeight); for (int column = 0; column<4; column++) @@ -156,11 +158,11 @@ BOOL CVFPUDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) Rectangle(hdc, x, y, x + columnWidth, y+rowHeight); temp_len = sprintf_s(temp, "R%i0%i", matrix, column); - TextOut(hdc,x+3,y+2,temp,temp_len); + TextOutA(hdc,x+3,y+2,temp,temp_len); Rectangle(hdc, 0, y+rowHeight*(column+1), xStart, y+rowHeight*(column+2)); temp_len = sprintf_s(temp, "C%i%i0", matrix, column); - TextOut(hdc,3,y+rowHeight*(column+1)+1,temp,temp_len); + TextOutA(hdc,3,y+rowHeight*(column+1)+1,temp,temp_len); y+=rowHeight; @@ -176,7 +178,7 @@ BOOL CVFPUDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) default:temp_len = sprintf_s(temp,"%f",val); break; } - TextOut(hdc,x+3,y+2,temp,temp_len); + TextOutA(hdc,x+3,y+2,temp,temp_len); y+=rowHeight; } } diff --git a/Windows/InputBox.cpp b/Windows/InputBox.cpp index dcc798c212..7d24b4f2b4 100644 --- a/Windows/InputBox.cpp +++ b/Windows/InputBox.cpp @@ -1,29 +1,34 @@ #include "Common/CommonWindows.h" #include "Windows/InputBox.h" #include "Windows/resource.h" +#include "util/text/utf8.h" -static TCHAR textBoxContents[256]; -static TCHAR out[256]; -static TCHAR windowTitle[256]; +static std::wstring textBoxContents; +static std::wstring out; +static std::wstring windowTitle; static bool defaultSelected; static INT_PTR CALLBACK InputBoxFunc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: - SetWindowText(GetDlgItem(hDlg,IDC_INPUTBOX),textBoxContents); - SetWindowText(hDlg, windowTitle); + SetWindowText(GetDlgItem(hDlg, IDC_INPUTBOX), textBoxContents.c_str()); + SetWindowText(hDlg, windowTitle.c_str()); if (defaultSelected == false) PostMessage(GetDlgItem(hDlg,IDC_INPUTBOX),EM_SETSEL,-1,-1); return TRUE; case WM_COMMAND: switch (wParam) { case IDOK: - GetWindowText(GetDlgItem(hDlg,IDC_INPUTBOX),out,255); - EndDialog(hDlg,IDOK); + { + wchar_t temp[256]; + GetWindowText(GetDlgItem(hDlg, IDC_INPUTBOX), temp, 255); + out = temp; + } + EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: - EndDialog(hDlg,IDCANCEL); + EndDialog(hDlg, IDCANCEL); return TRUE; } default: @@ -37,68 +42,87 @@ void InputBoxFunc() } -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, TCHAR *title, TCHAR *defaultvalue, TCHAR *outvalue, bool selected) +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultValue, std::string &outvalue, bool selected) { defaultSelected = selected; - if (defaultvalue && strlen(defaultvalue)<255) - strcpy(textBoxContents,defaultvalue); + if (defaultValue.size() < 255) + textBoxContents = ConvertUTF8ToWString(defaultValue); else - strcpy(textBoxContents,""); + textBoxContents = L""; if (title != NULL) - strcpy(windowTitle,title); + windowTitle = title; else - strcpy(windowTitle,""); + windowTitle = L""; - if (IDOK==DialogBox(hInst,(LPCSTR)IDD_INPUTBOX,hParent,InputBoxFunc)) - { - strcpy(outvalue,out); + if (IDOK == DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc)) { + outvalue = ConvertWStringToUTF8(out); return true; } else return false; } -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, TCHAR *title, const TCHAR *defaultvalue, TCHAR *outvalue, size_t outlength) +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultValue, std::string &outvalue) { - const char *defaultTitle = "Input value"; + const wchar_t *defaultTitle = L"Input value"; defaultSelected = true; - if (defaultvalue && strlen(defaultvalue)<255) - strcpy(textBoxContents,defaultvalue); + textBoxContents = ConvertUTF8ToWString(defaultValue); + + if (title && wcslen(title) <= 0) + windowTitle = defaultTitle; + else if (title && wcslen(title) < 255) + windowTitle = title; else - strcpy(textBoxContents,""); + windowTitle = defaultTitle; - - if(title && strlen(title) <= 0) - strcpy(windowTitle, defaultTitle); - else if(title && strlen(title) < 255) - strcpy(windowTitle, title); - else - strcpy(windowTitle, defaultTitle); - - if (IDOK==DialogBox(hInst,(LPCSTR)IDD_INPUTBOX,hParent,InputBoxFunc)) - { - strncpy(outvalue, out, outlength); + if (IDOK == DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc)) { + outvalue = ConvertWStringToUTF8(out); return true; } else return false; } -bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, TCHAR *title, u32 defaultvalue, u32 &outvalue) +bool InputBox_GetWString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::wstring &defaultValue, std::wstring &outvalue) { - sprintf(textBoxContents,"%08x",defaultvalue); - INT_PTR value = DialogBox(hInst,(LPCSTR)IDD_INPUTBOX,hParent,InputBoxFunc); + const wchar_t *defaultTitle = L"Input value"; + defaultSelected = true; + + textBoxContents = defaultValue; + + if (title && wcslen(title) <= 0) + windowTitle = defaultTitle; + else if (title && wcslen(title) < 255) + windowTitle = title; + else + windowTitle = defaultTitle; + + if (IDOK == DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc)) { + outvalue = out; + return true; + } + else + return false; +} + +bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue) +{ + wchar_t temp[256]; + wsprintf(temp,L"%08x",defaultvalue); + textBoxContents = temp; + + INT_PTR value = DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc); if (value == IDOK) { - sscanf(out,"%08x",&outvalue); + wscanf(out.c_str(),"%08x",&outvalue); return true; } else { - out[0]=0; + outvalue = 0; return false; } } \ No newline at end of file diff --git a/Windows/InputBox.h b/Windows/InputBox.h index d55fe1dada..fdfc1ebd6b 100644 --- a/Windows/InputBox.h +++ b/Windows/InputBox.h @@ -3,6 +3,10 @@ #include "Globals.h" #include "Common/CommonWindows.h" -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, TCHAR *title, TCHAR *defaultvalue, TCHAR *outvalue, bool selected = true); -bool InputBox_GetString(HINSTANCE hInst, HWND hParent, TCHAR *title, const TCHAR *defaultvalue, TCHAR *outvalue, size_t outlength); -bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, TCHAR *title, u32 defaultvalue, u32 &outvalue); + + +// All I/O is in UTF-8 +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultvalue, std::string &outvalue, bool selected); +bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultvalue, std::string &outvalue); +bool InputBox_GetWString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue); +bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue); diff --git a/Windows/KeyboardDevice.cpp b/Windows/KeyboardDevice.cpp index 867d0797b8..01fb2174e9 100644 --- a/Windows/KeyboardDevice.cpp +++ b/Windows/KeyboardDevice.cpp @@ -76,7 +76,7 @@ std::map windowsTransTable = InitConstMap (VK_RSHIFT, NKCODE_SHIFT_RIGHT) (VK_LMENU, NKCODE_ALT_LEFT) (VK_RMENU, NKCODE_ALT_RIGHT) - (VK_BACK, NKCODE_BACK) + (VK_BACK, NKCODE_DEL) // yes! http://stackoverflow.com/questions/4886858/android-edittext-deletebackspace-key-event (VK_SPACE, NKCODE_SPACE) (VK_ESCAPE, NKCODE_ESCAPE) (VK_UP, NKCODE_DPAD_UP) diff --git a/Windows/OpenGLBase.cpp b/Windows/OpenGLBase.cpp index a0701db4fc..e67e77ccbd 100644 --- a/Windows/OpenGLBase.cpp +++ b/Windows/OpenGLBase.cpp @@ -91,6 +91,8 @@ bool GL_Init(HWND window, std::string *error_message) { hWnd = window; GLuint PixelFormat; + // TODO: Change to use WGL_ARB_pixel_format instead + static const PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number @@ -98,9 +100,9 @@ bool GL_Init(HWND window, std::string *error_message) { PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format - 32, // Select Our Color Depth + 24, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer + 8, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored @@ -206,12 +208,12 @@ void GL_Shutdown() { if (hRC) { // Are We Able To Release The DC And RC Contexts? if (!wglMakeCurrent(NULL,NULL)) { - MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + MessageBox(NULL,L"Release Of DC And RC Failed.", L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); } // Are We Able To Delete The RC? if (!wglDeleteContext(hRC)) { - MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + MessageBox(NULL,L"Release Rendering Context Failed.", L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); } hRC = NULL; } @@ -219,7 +221,7 @@ void GL_Shutdown() { if (hDC && !ReleaseDC(hWnd,hDC)) { DWORD err = GetLastError(); if (err != ERROR_DC_NOT_FOUND) { - MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + MessageBox(NULL,L"Release Device Context Failed.", L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); } hDC = NULL; } diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index c5be521b11..6e1cd10342 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -27,21 +27,21 @@ Application - MultiByte + Unicode false Application - MultiByte + Unicode Application - MultiByte + Unicode false Application - MultiByte + Unicode diff --git a/Windows/W32Util/DialogManager.cpp b/Windows/W32Util/DialogManager.cpp index fe77d9a481..32537b283f 100644 --- a/Windows/W32Util/DialogManager.cpp +++ b/Windows/W32Util/DialogManager.cpp @@ -18,7 +18,7 @@ Dialog::~Dialog() void Dialog::Create() { - m_hDlg = CreateDialogParam(m_hInstance, (LPCSTR)m_hResource, m_hParent, DlgProcStatic, (LPARAM)this); + m_hDlg = CreateDialogParam(m_hInstance, (LPCWSTR)m_hResource, m_hParent, DlgProcStatic, (LPARAM)this); SetWindowLongPtr(m_hDlg, GWLP_USERDATA, (LONG_PTR)this); } @@ -70,9 +70,8 @@ void DialogManager::AddDlg(Dialog *dialog) bool DialogManager::IsDialogMessage(LPMSG message) { WindowList::iterator iter; - for (iter=dialogs.begin(); iter!=dialogs.end(); iter++) - { - if (::IsDialogMessage((*iter)->GetDlgHandle(),message)) + for (iter = dialogs.begin(); iter != dialogs.end(); iter++) { + if (::IsDialogMessage((*iter)->GetDlgHandle(), message)) return true; } return false; diff --git a/Windows/W32Util/DialogManager.h b/Windows/W32Util/DialogManager.h index 856747b489..f81627ead7 100644 --- a/Windows/W32Util/DialogManager.h +++ b/Windows/W32Util/DialogManager.h @@ -12,7 +12,7 @@ protected: virtual BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { - MessageBox(0,"WTF? Pure Call",0,0); + MessageBox(0,L"WTF? Pure Call",0,0); return 0; } static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index 482f498c59..e3891bcc9f 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include #include "Misc.h" +#include "util/text/utf8.h" namespace W32Util { @@ -57,24 +58,23 @@ namespace W32Util sprintf(out,"%3.1f %s",f,sizes[s]); } - BOOL CopyTextToClipboard(HWND hwnd, const TCHAR *text) - { + BOOL CopyTextToClipboard(HWND hwnd, const char *text) { + std::wstring wtext = ConvertUTF8ToWString(text); OpenClipboard(hwnd); EmptyClipboard(); - HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (strlen(text) + 1) * sizeof(TCHAR)); - if (hglbCopy == NULL) - { + HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (wtext.size() + 1) * sizeof(wchar_t)); + if (hglbCopy == NULL) { CloseClipboard(); return FALSE; } // Lock the handle and copy the text to the buffer. - TCHAR *lptstrCopy = (TCHAR *)GlobalLock(hglbCopy); - strcpy(lptstrCopy, text); - lptstrCopy[strlen(text)] = (TCHAR) 0; // null character + wchar_t *lptstrCopy = (wchar_t *)GlobalLock(hglbCopy); + wcscpy(lptstrCopy, wtext.c_str()); + lptstrCopy[wtext.size()] = (wchar_t) 0; // null character GlobalUnlock(hglbCopy); - SetClipboardData(CF_TEXT,hglbCopy); + SetClipboardData(CF_UNICODETEXT, hglbCopy); CloseClipboard(); return TRUE; } diff --git a/Windows/W32Util/Misc.h b/Windows/W32Util/Misc.h index 2a53936967..addcd3892a 100644 --- a/Windows/W32Util/Misc.h +++ b/Windows/W32Util/Misc.h @@ -7,6 +7,6 @@ namespace W32Util void CenterWindow(HWND hwnd); HBITMAP CreateBitmapFromARGB(HWND someHwnd, DWORD *image, int w, int h); void NiceSizeFormat(size_t size, char *out); - BOOL CopyTextToClipboard(HWND hwnd, const TCHAR *text); + BOOL CopyTextToClipboard(HWND hwnd, const char *text); void MakeTopMost(HWND hwnd, bool topMost); } \ No newline at end of file diff --git a/Windows/W32Util/PropertySheet.cpp b/Windows/W32Util/PropertySheet.cpp index 50f4b8d07a..1254b64b0b 100644 --- a/Windows/W32Util/PropertySheet.cpp +++ b/Windows/W32Util/PropertySheet.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Misc.h" #include "PropertySheet.h" +#include "util/text/utf8.h" #include @@ -82,7 +83,7 @@ namespace W32Util if (icon) sheet.dwFlags |= PSH_USEHICON; - sheet.pszCaption = title.c_str(); + sheet.pszCaption = ConvertUTF8ToWString(title).c_str(); sheet.nPages = (UINT)list.size(); sheet.phpage = pages; sheet.nStartPage = startpage; diff --git a/Windows/W32Util/ShellUtil.cpp b/Windows/W32Util/ShellUtil.cpp index a0cb33a2f4..54cf473020 100644 --- a/Windows/W32Util/ShellUtil.cpp +++ b/Windows/W32Util/ShellUtil.cpp @@ -3,7 +3,9 @@ #include "stdafx.h" #include "shlobj.h" +#include "util/text/utf8.h" #include "ShellUtil.h" +#include "CommDlg.h" #include #include @@ -15,17 +17,17 @@ namespace W32Util BROWSEINFO info; memset(&info,0,sizeof(info)); info.hwndOwner = parent; - info.lpszTitle = title; + info.lpszTitle = ConvertUTF8ToWString(title).c_str(); info.ulFlags = BIF_EDITBOX | BIF_RETURNONLYFSDIRS | BIF_USENEWUI; //info.pszDisplayName LPCITEMIDLIST idList = SHBrowseForFolder(&info); - char temp[MAX_PATH]; + wchar_t temp[MAX_PATH]; SHGetPathFromIDList(idList, temp); - if (strlen(temp)) + if (wcslen(temp)) { - return temp; + return ConvertWStringToUTF8(temp); } else return ""; @@ -34,15 +36,12 @@ namespace W32Util //--------------------------------------------------------------------------------------------------- // function WinBrowseForFileName //--------------------------------------------------------------------------------------------------- - bool BrowseForFileName (bool _bLoad, HWND _hParent, const char *_pTitle, - const char *_pInitialFolder,const char *_pFilter,const char *_pExtension, + bool BrowseForFileName (bool _bLoad, HWND _hParent, const wchar_t *_pTitle, + const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t *_pExtension, std::string& _strFileName) { - char szFile [MAX_PATH+1]; - char szFileTitle [MAX_PATH+1]; - - strcpy (szFile,""); - strcpy (szFileTitle,""); + wchar_t szFile [MAX_PATH+1] = {0}; + wchar_t szFileTitle [MAX_PATH+1] = {0}; OPENFILENAME ofn; @@ -60,25 +59,22 @@ namespace W32Util ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_HIDEREADONLY; if (_strFileName.size () != 0) - ofn.lpstrFile = (char *)_strFileName.c_str(); + wcscpy(ofn.lpstrFile, ConvertUTF8ToWString(_strFileName).c_str()); - if (((_bLoad)?GetOpenFileName (&ofn):GetSaveFileName (&ofn))) + if (((_bLoad) ? GetOpenFileName(&ofn) : GetSaveFileName (&ofn))) { - _strFileName = ofn.lpstrFile; + _strFileName = ConvertWStringToUTF8(ofn.lpstrFile); return true; } else return false; } - std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const char *_pTitle, - const char *_pInitialFolder,const char *_pFilter,const char *_pExtension) + std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t *_pTitle, + const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t *_pExtension) { - char szFile [MAX_PATH+1+2048*2]; - char szFileTitle [MAX_PATH+1]; - - strcpy (szFile,""); - strcpy (szFileTitle,""); + wchar_t szFile [MAX_PATH+1+2048*2] = {0}; + wchar_t szFileTitle [MAX_PATH+1] = {0}; OPENFILENAME ofn; @@ -97,33 +93,28 @@ namespace W32Util std::vector files; - if (((_bLoad) ? GetOpenFileName (&ofn):GetSaveFileName (&ofn))) + if (((_bLoad) ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn))) { - std::string directory = ofn.lpstrFile; - char *temp = ofn.lpstrFile; - char *oldtemp = temp; - temp+=strlen(temp)+1; + std::string directory = ConvertWStringToUTF8(ofn.lpstrFile); + wchar_t *temp = ofn.lpstrFile; + wchar_t *oldtemp = temp; + temp += wcslen(temp)+1; if (*temp==0) { //we only got one file - files.push_back(std::string(oldtemp)); + files.push_back(ConvertWStringToUTF8(oldtemp)); } else { while (*temp) { - files.push_back(directory+"\\"+std::string(temp)); - temp+=strlen(temp)+1; + files.push_back(directory+"\\"+ConvertWStringToUTF8(temp)); + temp += wcslen(temp)+1; } } return files; } else return std::vector(); // empty vector; - } - - - - } \ No newline at end of file diff --git a/Windows/W32Util/ShellUtil.h b/Windows/W32Util/ShellUtil.h index a598440a19..8d55f33553 100644 --- a/Windows/W32Util/ShellUtil.h +++ b/Windows/W32Util/ShellUtil.h @@ -7,9 +7,9 @@ namespace W32Util { std::string BrowseForFolder(HWND parent, char *title); - bool BrowseForFileName (bool _bLoad, HWND _hParent, const char *_pTitle, - const char *_pInitialFolder,const char *_pFilter,const char *_pExtension, + bool BrowseForFileName (bool _bLoad, HWND _hParent, const wchar_t*_pTitle, + const wchar_t *_pInitialFolder,const wchar_t *_pFilter,const wchar_t*_pExtension, std::string& _strFileName); - std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const char *_pTitle, - const char *_pInitialFolder,const char *_pFilter,const char *_pExtension); + std::vector BrowseForFileNameMultiSelect(bool _bLoad, HWND _hParent, const wchar_t*_pTitle, + const wchar_t*_pInitialFolder,const wchar_t*_pFilter,const wchar_t*_pExtension); } \ No newline at end of file diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index fbae02f6a9..0b8eb4f850 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -17,9 +17,21 @@ #include +// For shell links +#include "windows.h" +#include "winnls.h" +#include "shobjidl.h" +#include "objbase.h" +#include "objidl.h" +#include "shlguid.h" +#include "shlobj.h" + +// native stuff #include "base/NativeApp.h" +#include "file/file_util.h" #include "input/input_state.h" #include "input/keycodes.h" +#include "util/text/utf8.h" #include "Core/Core.h" #include "Core/Config.h" @@ -43,7 +55,6 @@ #include "Core/Debugger/SymbolMap.h" #include "Common/StringUtils.h" -#include "file/file_util.h" #include "main.h" static PMixer *curMixer; @@ -145,7 +156,7 @@ void WindowsHost::ShutdownSound() void WindowsHost::UpdateUI() { - MainWindow::Update(); + PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0); } @@ -289,5 +300,86 @@ void WindowsHost::UpdateConsolePosition() bool WindowsHost::InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outLength) { - return InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), title, defaultValue, outValue, outLength); + std::string out; + if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) { + strcpy(outValue, out.c_str()); + return true; + } else { + return false; + } +} + +bool WindowsHost::InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) +{ + if (InputBox_GetWString(MainWindow::GetHInstance(), MainWindow::GetHWND(), title, defaultvalue, outvalue)) { + return true; + } else { + return false; + } +} + + +// http://msdn.microsoft.com/en-us/library/aa969393.aspx +HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) { + HRESULT hres; + IShellLink* psl; + CoInitialize(0); + + // Get a pointer to the IShellLink interface. It is assumed that CoInitialize + // has already been called. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); + if (SUCCEEDED(hres)) { + IPersistFile* ppf; + + // Set the path to the shortcut target and add the description. + psl->SetPath(lpszPathObj); + psl->SetArguments(lpszArguments); + psl->SetDescription(lpszDesc); + + // Query IShellLink for the IPersistFile interface, used for saving the + // shortcut in persistent storage. + hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); + + if (SUCCEEDED(hres)) { + // Save the link by calling IPersistFile::Save. + hres = ppf->Save(lpszPathLink, TRUE); + ppf->Release(); + } + psl->Release(); + } + CoUninitialize(); + + return hres; +} + +bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string gameTitle) { + // TODO: not working correctly + return false; + + + // Get the desktop folder + wchar_t *pathbuf = new wchar_t[MAX_PATH + gameTitle.size() + 100]; + SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, pathbuf); + + // Sanitize the game title for banned characters. + const char bannedChars[] = "<>:\"/\\|?*"; + for (size_t i = 0; i < gameTitle.size(); i++) { + for (size_t c = 0; c < strlen(bannedChars); c++) { + if (gameTitle[i] == bannedChars[c]) { + gameTitle[i] = '_'; + break; + } + } + } + + wcscat(pathbuf, L"\\"); + wcscat(pathbuf, ConvertUTF8ToWString(gameTitle).c_str()); + + wchar_t module[MAX_PATH]; + GetModuleFileName(NULL, module, MAX_PATH); + + CreateLink(module, ConvertUTF8ToWString(argumentPath).c_str(), pathbuf, ConvertUTF8ToWString(gameTitle).c_str()); + + delete [] pathbuf; + return false; } diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index a1a1f18526..2c4d5c463a 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -55,8 +55,11 @@ public: void SaveSymbolMap(); void SetWindowTitle(const char *message); - bool InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outlength); + virtual bool CanCreateShortcut() {return false;} // Turn on when fixed + virtual bool CreateDesktopShortcut(std::string argumentPath, std::string title); + bool InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outlength); + bool InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue); std::shared_ptr keyboard; private: diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 9a654ababf..e123257b97 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012- PPSSPP Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,9 +19,9 @@ // It's improving slowly, though. :) #include "Common/CommonWindows.h" -#include #include +#include #include "base/NativeApp.h" #include "Globals.h" @@ -29,8 +29,11 @@ #include "shellapi.h" #include "commctrl.h" +#include "i18n/i18n.h" #include "input/input_state.h" #include "input/keycodes.h" +#include "util/text/utf8.h" + #include "Core/Debugger/SymbolMap.h" #include "Windows/OpenGLBase.h" #include "Windows/Debugger/Debugger_Disasm.h" @@ -56,13 +59,11 @@ #include "Windows/W32Util/Misc.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -#include "native/image/png_load.h" #include "GPU/GLES/TextureScaler.h" #include "GPU/GLES/TextureCache.h" #include "GPU/GLES/Framebuffer.h" #include "ControlMapping.h" #include "UI/OnScreenDisplay.h" -#include "i18n/i18n.h" #ifdef THEMES #include "XPTheme.h" @@ -104,6 +105,7 @@ namespace MainWindow static void *rawInputBuffer; static size_t rawInputBufferSize; static int currentSavestateSlot = 0; + static std::map initialMenuKeys; #define MAX_LOADSTRING 100 const TCHAR *szTitle = TEXT("PPSSPP"); @@ -138,7 +140,7 @@ namespace MainWindow wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_PPSSPP); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wcex.lpszMenuName = (LPCSTR)IDR_MENU1; + wcex.lpszMenuName = (LPCWSTR)IDR_MENU1; wcex.lpszClassName = szWindowClass; wcex.hIconSm = (HICON)LoadImage(hInstance, (LPCTSTR)IDI_PPSSPP, IMAGE_ICON, 16,16,LR_SHARED); RegisterClassEx(&wcex); @@ -235,6 +237,193 @@ namespace MainWindow } } + std::string GetMenuItemText(int menuID) { + MENUITEMINFO menuInfo; + memset(&menuInfo, 0, sizeof(menuInfo)); + menuInfo.cbSize = sizeof(MENUITEMINFO); + menuInfo.fMask = MIIM_STRING; + menuInfo.dwTypeData = 0; + + std::string retVal; + if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) { + wchar_t *buffer = new wchar_t[++menuInfo.cch]; + menuInfo.dwTypeData = buffer; + GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo); + retVal = ConvertWStringToUTF8(menuInfo.dwTypeData); + delete [] buffer; + } + + return retVal; + } + + const std::string &GetMenuItemInitialText(const int menuID) { + if (initialMenuKeys.find(menuID) == initialMenuKeys.end()) { + initialMenuKeys[menuID] = GetMenuItemText(menuID); + } + return initialMenuKeys[menuID]; + } + + // These are used as an offset + // to determine which menu item to change. + // Make sure to count(from 0) the separators too, when dealing with submenus!! + enum MenuID{ + // Main menus + MENU_FILE = 0, + MENU_EMULATION = 1, + MENU_DEBUG = 2, + MENU_OPTIONS = 3, + MENU_HELP = 4, + + // Emulation submenus + SUBMENU_RENDERING_BACKEND = 11, + + // Game Settings submenus + SUBMENU_RENDERING_RESOLUTION = 4, + SUBMENU_RENDERING_MODE = 5, + SUBMENU_FRAME_SKIPPING = 6, + SUBMENU_TEXTURE_FILTERING = 7, + SUBMENU_TEXTURE_SCALING = 8, + }; + + void TranslateMenuItembyText(const int menuID, const char *menuText, const char *category="", const bool enabled = true, const bool checked = false, const std::wstring& accelerator = L"") { + I18NCategory *c = GetI18NCategory(category); + std::string key = c->T(menuText); + std::wstring translated = ConvertUTF8ToWString(key); + translated.append(accelerator); + ModifyMenu(menu, menuID, MF_STRING + | (enabled? MF_ENABLED : MF_GRAYED) + | (checked? MF_CHECKED : MF_UNCHECKED), + menuID, translated.c_str()); + + } + + void TranslateMenuHeader(HMENU menu, const char *category, const char *key, const MenuID id, const std::wstring& accelerator = L"") { + I18NCategory *c = GetI18NCategory(category); + std::string s_key = c->T(key); + std::wstring translated = ConvertUTF8ToWString(s_key); + translated.append(accelerator); + ModifyMenu(menu, id, MF_BYPOSITION | MF_STRING, 0, translated.c_str()); + } + + void TranslateSubMenuHeader(HMENU menu, const char *category, const char *key, MenuID mainMenuID, MenuID subMenuID, const std::wstring& accelerator = L"") { + HMENU subMenu; + subMenu = GetSubMenu(menu, mainMenuID); + I18NCategory *c = GetI18NCategory(category); + std::string s_key = c->T(key); + std::wstring translated = ConvertUTF8ToWString(s_key); + translated.append(accelerator); + ModifyMenu(subMenu, subMenuID, MF_BYPOSITION | MF_STRING, 0, translated.c_str()); + } + + void TranslateMenuItem(const int menuID, const char *category, const bool enabled = true, const bool checked = false, const std::wstring& accelerator = L"") { + I18NCategory *c = GetI18NCategory(category); + std::string key = c->T(GetMenuItemInitialText(menuID).c_str()); + std::wstring translated = ConvertUTF8ToWString(key); + translated.append(accelerator); + ModifyMenu(menu, menuID, MF_STRING + | (enabled? MF_ENABLED : MF_GRAYED) + | (checked? MF_CHECKED : MF_UNCHECKED), + menuID, translated.c_str()); + } + + void TranslateMenus() { + const char *desktopUI = "DesktopUI"; + + // File menu + TranslateMenuItem(ID_FILE_LOAD, desktopUI); + TranslateMenuItem(ID_FILE_LOAD_DIR, desktopUI); + TranslateMenuItem(ID_FILE_LOAD_MEMSTICK, desktopUI); + TranslateMenuItem(ID_FILE_MEMSTICK, desktopUI); + TranslateMenuItem(ID_FILE_QUICKLOADSTATE, desktopUI, false, false, L"\tF4"); + TranslateMenuItem(ID_FILE_QUICKSAVESTATE, desktopUI, false, false, L"\tF2"); + TranslateMenuItem(ID_FILE_LOADSTATEFILE, desktopUI, false, false); + TranslateMenuItem(ID_FILE_SAVESTATEFILE, desktopUI, false, false); + TranslateMenuItem(ID_FILE_EXIT, desktopUI); + + // Emulation menu + bool isPaused = Core_IsStepping() && globalUIState == UISTATE_INGAME; + TranslateMenuItembyText(ID_TOGGLE_PAUSE, isPaused ? "Run" : "Pause", "DesktopUI", false, false, L"\tF8"); + TranslateMenuItem(ID_EMULATION_STOP, desktopUI, false, false, L"\tCtrl+W"); + TranslateMenuItem(ID_EMULATION_RESET, desktopUI, false, false, L"\tCtrl+B"); + TranslateMenuItem(ID_EMULATION_RUNONLOAD, desktopUI); + TranslateMenuItem(ID_EMULATION_SOUND, desktopUI, true, true); + TranslateMenuItem(ID_EMULATION_ATRAC3_SOUND, desktopUI, true, false); + TranslateMenuItem(ID_EMULATION_CHEATS, desktopUI); + TranslateMenuItem(ID_EMULATION_RENDER_MODE_OGL, desktopUI, true, true); + TranslateMenuItem(ID_EMULATION_RENDER_MODE_SOFT, desktopUI); + TranslateMenuItem(ID_CPU_DYNAREC, desktopUI); + TranslateMenuItem(ID_CPU_MULTITHREADED, desktopUI); + TranslateMenuItem(ID_IO_MULTITHREADED, desktopUI); + + // Debug menu + TranslateMenuItem(ID_DEBUG_LOADMAPFILE, desktopUI); + TranslateMenuItem(ID_DEBUG_SAVEMAPFILE, desktopUI); + TranslateMenuItem(ID_DEBUG_RESETSYMBOLTABLE, desktopUI); + TranslateMenuItem(ID_DEBUG_DUMPNEXTFRAME, desktopUI); + TranslateMenuItem(ID_DEBUG_TAKESCREENSHOT, desktopUI, true, false, L"\tF12"); + TranslateMenuItem(ID_DEBUG_DISASSEMBLY, desktopUI, true, false, L"\tCtrl+D"); + TranslateMenuItem(ID_DEBUG_LOG, desktopUI, true, false, L"\tCtrl+L"); + TranslateMenuItem(ID_DEBUG_MEMORYVIEW, desktopUI, L"\tCtrl+M"); + + // Options menu + TranslateMenuItem(ID_OPTIONS_FULLSCREEN, desktopUI, true, false, L"\tAlt+Return, F11"); + TranslateMenuItem(ID_OPTIONS_TOPMOST, desktopUI); + TranslateMenuItem(ID_OPTIONS_STRETCHDISPLAY, desktopUI); + TranslateMenuItem(ID_OPTIONS_SCREEN1X, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_SCREEN2X, desktopUI, true, true); + TranslateMenuItem(ID_OPTIONS_SCREEN3X, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_SCREEN4X, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_NONBUFFEREDRENDERING, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_BUFFEREDRENDERING, desktopUI, true, true); + TranslateMenuItem(ID_OPTIONS_READFBOTOMEMORYCPU, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_READFBOTOMEMORYGPU, desktopUI, true, false); + TranslateMenuItem(ID_OPTIONS_FRAMESKIP_0, desktopUI); + TranslateMenuItem(ID_OPTIONS_FRAMESKIP_AUTO, desktopUI); + // Skip frameskipping 2-8.. + TranslateMenuItem(ID_OPTIONS_TEXTUREFILTERING_AUTO, desktopUI); + TranslateMenuItem(ID_OPTIONS_NEARESTFILTERING, desktopUI); + TranslateMenuItem(ID_OPTIONS_LINEARFILTERING, desktopUI); + TranslateMenuItem(ID_OPTIONS_LINEARFILTERING_CG, desktopUI); + TranslateMenuItem(ID_TEXTURESCALING_OFF, desktopUI); + // Skip texture scaling 2x-5x... + TranslateMenuItem(ID_TEXTURESCALING_XBRZ, desktopUI); + TranslateMenuItem(ID_TEXTURESCALING_HYBRID, desktopUI); + TranslateMenuItem(ID_TEXTURESCALING_BICUBIC, desktopUI); + TranslateMenuItem(ID_TEXTURESCALING_HYBRID_BICUBIC, desktopUI); + TranslateMenuItem(ID_TEXTURESCALING_DEPOSTERIZE, desktopUI); + TranslateMenuItem(ID_OPTIONS_HARDWARETRANSFORM, desktopUI, true, true, L"\tF6"); + TranslateMenuItem(ID_OPTIONS_VERTEXCACHE, desktopUI); + TranslateMenuItem(ID_OPTIONS_MIPMAP, desktopUI); + TranslateMenuItem(ID_OPTIONS_ANTIALIASING, desktopUI); + TranslateMenuItem(ID_OPTIONS_VSYNC, desktopUI); + TranslateMenuItem(ID_OPTIONS_SHOWFPS, desktopUI); + TranslateMenuItem(ID_OPTIONS_SHOWDEBUGSTATISTICS, desktopUI); + TranslateMenuItem(ID_OPTIONS_FASTMEMORY, desktopUI); + TranslateMenuItem(ID_OPTIONS_IGNOREILLEGALREADS, desktopUI); + + // Help menu + TranslateMenuItem(ID_HELP_OPENWEBSITE, desktopUI); + TranslateMenuItem(ID_HELP_OPENFORUM, desktopUI); + TranslateMenuItem(ID_HELP_BUYGOLD, desktopUI); + TranslateMenuItem(ID_HELP_ABOUT, desktopUI); + + // Now do the menu headers and a few submenus... + TranslateMenuHeader(menu, desktopUI, "File", MENU_FILE); + TranslateMenuHeader(menu, desktopUI, "Emulation", MENU_EMULATION); + TranslateMenuHeader(menu, desktopUI, "Debugging", MENU_DEBUG); + TranslateMenuHeader(menu, desktopUI, "Game Settings", MENU_OPTIONS); + TranslateMenuHeader(menu, desktopUI, "Help", MENU_HELP); + + TranslateSubMenuHeader(menu, desktopUI, "Rendering Backend", MENU_EMULATION, SUBMENU_RENDERING_BACKEND); + TranslateSubMenuHeader(menu, desktopUI, "Rendering Resolution", MENU_OPTIONS, SUBMENU_RENDERING_RESOLUTION, L"\tCtrl+1"); + TranslateSubMenuHeader(menu, desktopUI, "Rendering Mode", MENU_OPTIONS, SUBMENU_RENDERING_MODE, L"\tF5"); + TranslateSubMenuHeader(menu, desktopUI, "Frame Skipping", MENU_OPTIONS, SUBMENU_FRAME_SKIPPING, L"\tF7"); + TranslateSubMenuHeader(menu, desktopUI, "Texture Filtering", MENU_OPTIONS, SUBMENU_TEXTURE_FILTERING); + TranslateSubMenuHeader(menu, desktopUI, "Texture Scaling", MENU_OPTIONS, SUBMENU_TEXTURE_SCALING); + + DrawMenuBar(hwndMain); + } + void setTexScalingMultiplier(int level) { g_Config.iTexScalingLevel = level; if(gpu) gpu->ClearCacheNextFrame(); @@ -321,17 +510,18 @@ namespace MainWindow u32 style = WS_OVERLAPPEDWINDOW; - hwndMain = CreateWindowEx(0,szWindowClass, "", style, + hwndMain = CreateWindowEx(0,szWindowClass, L"", style, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL); if (!hwndMain) return FALSE; - hwndDisplay = CreateWindowEx(0, szDisplayClass, TEXT(""), WS_CHILD | WS_VISIBLE, + hwndDisplay = CreateWindowEx(0, szDisplayClass, L"", WS_CHILD | WS_VISIBLE, rcOrig.left, rcOrig.top, rcOrig.right - rcOrig.left, rcOrig.bottom - rcOrig.top, hwndMain, 0, hInstance, 0); if (!hwndDisplay) return FALSE; menu = GetMenu(hwndMain); + #ifdef FINAL RemoveMenu(menu,2,MF_BYPOSITION); RemoveMenu(menu,2,MF_BYPOSITION); @@ -352,7 +542,7 @@ namespace MainWindow hideCursor = true; SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0); - + Update(); if(g_Config.bFullScreenOnLaunch) @@ -383,6 +573,17 @@ namespace MainWindow return TRUE; } + void CreateDebugWindows() { + disasmWindow[0] = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); + DialogManager::AddDlg(disasmWindow[0]); + EnableWindow(disasmWindow[0]->GetDlgHandle(),FALSE); + disasmWindow[0]->Show(g_Config.bShowDebuggerOnLoad); + + memoryWindow[0] = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); + DialogManager::AddDlg(memoryWindow[0]); + EnableWindow(memoryWindow[0]->GetDlgHandle(),FALSE); + } + void BrowseAndBoot(std::string defaultPath, bool browseDirectory) { std::string fn; std::string filter = "PSP ROMs (*.iso *.cso *.pbp *.elf)|*.pbp;*.elf;*.iso;*.cso;*.prx|All files (*.*)|*.*||"; @@ -414,7 +615,7 @@ namespace MainWindow NativeMessageReceived("boot", dir.c_str()); } } - else if (W32Util::BrowseForFileName(true, GetHWND(), "Load File", defaultPath.size() ? defaultPath.c_str() : 0, filter.c_str(),"*.pbp;*.elf;*.iso;*.cso;",fn)) + else if (W32Util::BrowseForFileName(true, GetHWND(), L"Load File", defaultPath.size() ? ConvertUTF8ToWString(defaultPath).c_str() : 0, ConvertUTF8ToWString(filter).c_str(), L"*.pbp;*.elf;*.iso;*.cso;",fn)) { if (globalUIState == UISTATE_INGAME || globalUIState == UISTATE_PAUSEMENU) { Core_EnableStepping(false); @@ -704,12 +905,9 @@ namespace MainWindow break; case ID_EMULATION_STOP: - if (memoryWindow[0]) { - SendMessage(memoryWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0); - } - if (disasmWindow[0]) { - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0); - } + EnableWindow(disasmWindow[0]->GetDlgHandle(),FALSE); + EnableWindow(memoryWindow[0]->GetDlgHandle(),FALSE); + if (Core_IsStepping()) { Core_EnableStepping(false); } @@ -718,14 +916,16 @@ namespace MainWindow break; case ID_EMULATION_RESET: + if (Core_IsStepping()) { + Core_EnableStepping(false); + } + EnableWindow(disasmWindow[0]->GetDlgHandle(),FALSE); + EnableWindow(memoryWindow[0]->GetDlgHandle(),FALSE); NativeMessageReceived("reset", ""); break; case ID_EMULATION_CHEATS: NativeMessageReceived("reset", ""); break; - case ID_EMULATION_SPEEDLIMIT: - g_Config.bSpeedLimit = !g_Config.bSpeedLimit; - break; case ID_EMULATION_RENDER_MODE_OGL: g_Config.bSoftwareRendering = false; @@ -736,14 +936,14 @@ namespace MainWindow break; case ID_FILE_LOADSTATEFILE: - if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load state",0,L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0",L"ppst",fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Load(fn, SaveStateActionFinished); } break; case ID_FILE_SAVESTATEFILE: - if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { + if (W32Util::BrowseForFileName(false, hWnd, L"Save state",0,L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0",L"ppst",fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Save(fn, SaveStateActionFinished); } @@ -925,12 +1125,7 @@ namespace MainWindow break; case ID_CPU_DYNAREC: - g_Config.bJit = true; - osm.ShowOnOff(g->T("Dynarec", "Dynarec (JIT)"), g_Config.bJit); - break; - - case ID_CPU_INTERPRETER: - g_Config.bJit = false; + g_Config.bJit = !g_Config.bJit; break; case ID_CPU_MULTITHREADED: @@ -951,7 +1146,7 @@ namespace MainWindow break; case ID_DEBUG_LOADMAPFILE: - if (W32Util::BrowseForFileName(true, hWnd, "Load .MAP",0,"Maps\0*.map\0All files\0*.*\0\0","map",fn)) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load .MAP",0,L"Maps\0*.map\0All files\0*.*\0\0",L"map",fn)) { symbolMap.LoadSymbolMap(fn.c_str()); if (disasmWindow[0]) @@ -963,7 +1158,7 @@ namespace MainWindow break; case ID_DEBUG_SAVEMAPFILE: - if (W32Util::BrowseForFileName(false, hWnd, "Save .MAP",0,"Maps\0*.map\0All files\0*.*\0\0","map",fn)) + if (W32Util::BrowseForFileName(false, hWnd, L"Save .MAP",0,L"Maps\0*.map\0All files\0*.*\0\0",L"map",fn)) symbolMap.SaveSymbolMap(fn.c_str()); break; @@ -980,13 +1175,11 @@ namespace MainWindow break; case ID_DEBUG_DISASSEMBLY: - if (disasmWindow[0]) - disasmWindow[0]->Show(true); + disasmWindow[0]->Show(true); break; case ID_DEBUG_MEMORYVIEW: - if (memoryWindow[0]) - memoryWindow[0]->Show(true); + memoryWindow[0]->Show(true); break; case ID_DEBUG_LOG: @@ -1045,7 +1238,7 @@ namespace MainWindow break; case ID_OPTIONS_CONTROLS: - MessageBox(hWnd, "Control mapping has been moved to the in-window Settings menu.\n", "Sorry", 0); + MessageBox(hWnd, L"Control mapping has been moved to the in-window Settings menu.\n", L"Sorry", 0); break; case ID_EMULATION_SOUND: @@ -1073,11 +1266,15 @@ namespace MainWindow break; case ID_HELP_OPENWEBSITE: - ShellExecute(NULL, "open", "http://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", L"http://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); + break; + + case ID_HELP_BUYGOLD: + ShellExecute(NULL, L"open", L"http://central.ppsspp.org/buygold", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_OPENFORUM: - ShellExecute(NULL, "open", "http://forums.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", L"http://forums.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_ABOUT: @@ -1091,7 +1288,7 @@ namespace MainWindow break; default: - MessageBox(hwndMain,"Unimplemented","Sorry",0); + MessageBox(hwndMain, L"Unimplemented", L"Sorry",0); break; } } @@ -1161,7 +1358,7 @@ namespace MainWindow HDROP hdrop = (HDROP)wParam; int count = DragQueryFile(hdrop,0xFFFFFFFF,0,0); if (count != 1) { - MessageBox(hwndMain,"You can only load one file at a time","Error",MB_ICONINFORMATION); + MessageBox(hwndMain,L"You can only load one file at a time",L"Error",MB_ICONINFORMATION); } else { @@ -1175,7 +1372,7 @@ namespace MainWindow Update(); - NativeMessageReceived("boot", filename); + NativeMessageReceived("boot", ConvertWStringToUTF8(filename).c_str()); } } break; @@ -1192,22 +1389,16 @@ namespace MainWindow break; case WM_USER+1: - if (disasmWindow[0]) - SendMessage(disasmWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0); - if (memoryWindow[0]) - SendMessage(memoryWindow[0]->GetDlgHandle(), WM_CLOSE, 0, 0); - - disasmWindow[0] = new CDisasm(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); - DialogManager::AddDlg(disasmWindow[0]); - disasmWindow[0]->Show(g_Config.bShowDebuggerOnLoad); if (g_Config.bFullScreen) _ViewFullScreen(hWnd); - memoryWindow[0] = new CMemoryDlg(MainWindow::GetHInstance(), MainWindow::GetHWND(), currentDebugMIPS); - DialogManager::AddDlg(memoryWindow[0]); - if (disasmWindow[0]) - disasmWindow[0]->NotifyMapLoaded(); - if (memoryWindow[0]) - memoryWindow[0]->NotifyMapLoaded(); + + EnableWindow (disasmWindow[0]->GetDlgHandle(),TRUE); + EnableWindow (memoryWindow[0]->GetDlgHandle(),TRUE); + + disasmWindow[0]->NotifyMapLoaded(); + memoryWindow[0]->NotifyMapLoaded(); + + disasmWindow[0]->UpdateDialog(); SetForegroundWindow(hwndMain); break; @@ -1233,6 +1424,11 @@ namespace MainWindow EnableMenuItem(menu, ID_EMULATION_ATRAC3_SOUND, MF_GRAYED); break; + case WM_USER_UPDATE_UI: + TranslateMenus(); + Update(); + break; + case WM_MENUSELECT: // Unfortunately, accelerate keys (hotkeys) shares the same enabled/disabled states // with corresponding menu items. @@ -1262,9 +1458,7 @@ namespace MainWindow void UpdateMenus() { HMENU menu = GetMenu(GetHWND()); #define CHECKITEM(item,value) CheckMenuItem(menu,item,MF_BYCOMMAND | ((value) ? MF_CHECKED : MF_UNCHECKED)); - CHECKITEM(ID_EMULATION_SPEEDLIMIT,g_Config.bSpeedLimit); CHECKITEM(ID_OPTIONS_IGNOREILLEGALREADS,g_Config.bIgnoreBadMemAccess); - CHECKITEM(ID_CPU_INTERPRETER,g_Config.bJit == false); CHECKITEM(ID_CPU_DYNAREC,g_Config.bJit == true); CHECKITEM(ID_CPU_MULTITHREADED, g_Config.bSeparateCPUThread); CHECKITEM(ID_IO_MULTITHREADED, g_Config.bSeparateIOThread); @@ -1390,7 +1584,7 @@ namespace MainWindow UpdateCommands(); } - + void UpdateCommands() { static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU; static CoreState lastCoreState = CORE_ERROR; @@ -1403,8 +1597,8 @@ namespace MainWindow HMENU menu = GetMenu(GetHWND()); - const char* pauseMenuText = (Core_IsStepping() || globalUIState != UISTATE_INGAME) ? "Run\tF8" : "Pause\tF8"; - ModifyMenu(menu, ID_TOGGLE_PAUSE, MF_BYCOMMAND | MF_STRING, ID_TOGGLE_PAUSE, pauseMenuText); + bool isPaused = Core_IsStepping() && globalUIState == UISTATE_INGAME; + TranslateMenuItembyText(ID_TOGGLE_PAUSE, isPaused ? "Run" : "Pause", "DesktopUI", false, false, L"\tF8"); UINT ingameEnable = globalUIState == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED; EnableMenuItem(menu, ID_TOGGLE_PAUSE, ingameEnable); @@ -1419,7 +1613,6 @@ namespace MainWindow EnableMenuItem(menu, ID_FILE_QUICKLOADSTATE, !menuEnable); EnableMenuItem(menu, ID_EMULATION_CHEATS, !menuEnable); EnableMenuItem(menu, ID_CPU_DYNAREC, menuEnable); - EnableMenuItem(menu, ID_CPU_INTERPRETER, menuEnable); EnableMenuItem(menu, ID_CPU_MULTITHREADED, menuEnable); EnableMenuItem(menu, ID_IO_MULTITHREADED, menuEnable); EnableMenuItem(menu, ID_DEBUG_LOG, !g_Config.bEnableLogging); @@ -1437,7 +1630,7 @@ namespace MainWindow HWND versionBox = GetDlgItem(hDlg, IDC_VERSION); char temp[256]; sprintf(temp, "PPSSPP %s", PPSSPP_GIT_VERSION); - SetWindowText(versionBox, temp); + SetWindowTextA(versionBox, temp); } return TRUE; diff --git a/Windows/WndMainWindow.h b/Windows/WndMainWindow.h index fa33b052ea..b5c2e24fbc 100644 --- a/Windows/WndMainWindow.h +++ b/Windows/WndMainWindow.h @@ -9,8 +9,9 @@ namespace MainWindow { enum { WM_USER_SAVESTATE_FINISH = WM_USER + 100, - WM_USER_LOG_STATUS_CHANGED = WM_USER + 200, - WM_USER_ATRAC_STATUS_CHANGED = WM_USER + 300, + WM_USER_LOG_STATUS_CHANGED = WM_USER + 101, + WM_USER_ATRAC_STATUS_CHANGED = WM_USER + 102, + WM_USER_UPDATE_UI = WM_USER + 103, }; enum { @@ -41,6 +42,7 @@ namespace MainWindow void Init(HINSTANCE hInstance); BOOL Show(HINSTANCE hInstance, int nCmdShow); + void CreateDebugWindows(); void Close(); void UpdateMenus(); void UpdateCommands(); @@ -53,4 +55,5 @@ namespace MainWindow void SaveStateActionFinished(bool result, void *userdata); void _ViewFullScreen(HWND hWnd); void _ViewNormal(HWND hWnd); + void TranslateMenus(); } diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index a92790a34a..68fa2441d9 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -31,10 +31,10 @@ static int LoadXInputDLL() { } version = (1 << 16) | 4; - s_pXInputDLL = LoadLibrary( "XInput1_4.dll" ); // 1.4 Ships with Windows 8. + s_pXInputDLL = LoadLibrary( L"XInput1_4.dll" ); // 1.4 Ships with Windows 8. if (!s_pXInputDLL) { version = (1 << 16) | 3; - s_pXInputDLL = LoadLibrary( "XInput1_3.dll" ); // 1.3 Ships with Vista and Win7, can be installed as a restributable component. + s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" ); // 1.3 Ships with Vista and Win7, can be installed as a restributable component. } if (!s_pXInputDLL) { return -1; diff --git a/Windows/main.cpp b/Windows/main.cpp index b9e7597e6a..8f362733de 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -19,6 +19,7 @@ #include "file/vfs.h" #include "file/zip_read.h" +#include "util/text/utf8.h" #include "Core/Config.h" #include "Core/SaveState.h" @@ -49,9 +50,8 @@ CDisasm *disasmWindow[MAX_CPUCOUNT] = {0}; CMemoryDlg *memoryWindow[MAX_CPUCOUNT] = {0}; -void LaunchBrowser(const char *url) -{ - ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); +void LaunchBrowser(const char *url) { + ShellExecute(NULL, L"open", ConvertUTF8ToWString(url).c_str(), NULL, NULL, SW_SHOWNORMAL); } std::string System_GetName() { @@ -62,6 +62,17 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin { Common::EnableCrashingOnCrashes(); + wchar_t modulePath[MAX_PATH]; + GetModuleFileName(NULL, modulePath, MAX_PATH); + for (size_t i = wcslen(modulePath) - 1; i > 0; i--) { + if (modulePath[i] == '\\') { + modulePath[i] = 0; + break; + } + } + SetCurrentDirectory(modulePath); + // GetCurrentDirectory(MAX_PATH, modulePath); // for checking in the debugger + bool hideLog = true; #ifdef _DEBUG @@ -107,7 +118,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin timeBeginPeriod(1); MainWindow::Init(_hInstance); - g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS); + g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance, iCmdShow); @@ -125,6 +136,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin host = new WindowsHost(hwndMain, hwndDisplay); host->SetWindowTitle(0); + MainWindow::CreateDebugWindows(); + // Emu thread is always running! EmuThread_Start(); @@ -149,8 +162,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin //Translate accelerators and dialog messages... HWND wnd; HACCEL accel; - if (g_debuggerActive) - { + if (g_debuggerActive) { wnd = disasmWindow[0]->GetDlgHandle(); accel = hDebugAccelTable; } else { diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index cb557f86c2..054802101e 100644 Binary files a/Windows/ppsspp.rc and b/Windows/ppsspp.rc differ diff --git a/Windows/resource.h b/Windows/resource.h index 0c020dac59..03e8c72acc 100644 Binary files a/Windows/resource.h and b/Windows/resource.h differ diff --git a/android/jni/Android.mk b/android/jni/Android.mk index cd01113f80..6a00178011 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -5,9 +5,9 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := native_audio -LOCAL_CFLAGS := -O3 -fsigned-char -ffast-math -Wall -Wno-multichar -Wno-psabi +LOCAL_CFLAGS := -O3 -fsigned-char -Wall -Wno-multichar -Wno-psabi -Wno-literal-suffix # yes, it's really CPPFLAGS for C++ -LOCAL_CPPFLAGS := -std=gnu++11 -fno-rtti +LOCAL_CPPFLAGS := -fno-exceptions -std=gnu++11 -fno-rtti NATIVE := ../../native LOCAL_SRC_FILES := \ $(NATIVE)/android/native-audio-so.cpp @@ -26,9 +26,9 @@ LOCAL_MODULE := ppsspp_jni NATIVE := ../../native SRC := ../.. -LOCAL_CFLAGS := -DUSE_FFMPEG -DUSE_PROFILER -DUSING_GLES2 -O3 -fsigned-char -Wall -Wno-multichar -Wno-psabi -Wno-unused-variable -fno-strict-aliasing -ffast-math +LOCAL_CFLAGS := -DUSE_FFMPEG -DUSE_PROFILER -DUSING_GLES2 -O3 -fsigned-char -Wall -Wno-multichar -Wno-psabi -Wno-unused-variable -fno-strict-aliasing # yes, it's really CPPFLAGS for C++ -LOCAL_CPPFLAGS := -std=gnu++11 -fno-rtti +LOCAL_CPPFLAGS := -fno-exceptions -std=gnu++11 -fno-rtti -Wno-reorder -Wno-literal-suffix LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../../Common \ $(LOCAL_PATH)/../.. \ @@ -57,6 +57,14 @@ LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/armv6/lib/libavutil.a LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ffmpeg/android/armv6/include LOCAL_CFLAGS += -DARMEABI endif +ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86/lib/libavformat.a +LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86/lib/libavcodec.a +LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86/lib/libswresample.a +LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86/lib/libswscale.a +LOCAL_LDLIBS += $(LOCAL_PATH)/../../ffmpeg/android/x86/lib/libavutil.a +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ffmpeg/android/x86/include +endif # $(SRC)/Core/EmuThread.cpp \ @@ -65,7 +73,7 @@ endif ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_IX86 +LOCAL_CFLAGS := $(LOCAL_CFLAGS) -D_M_IX86 -fomit-frame-pointer -mtune=atom -mssse3 ARCH_FILES := \ $(SRC)/Common/ABI.cpp \ diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0327c77982..3d8831bc21 100644 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -1,5 +1,6 @@ APP_STL := gnustl_static -APP_ABI := armeabi-v7a armeabi +#APP_ABI := armeabi-v7a x86 +APP_ABI := armeabi-v7a armeabi x86 #APP_ABI := armeabi-v7a APP_GNUSTL_CPP_FEATURES := -#NDK_TOOLCHAIN_VERSION := 4.8 +NDK_TOOLCHAIN_VERSION := 4.8 diff --git a/assets/Roboto-Condensed.ttf b/assets/Roboto-Condensed.ttf new file mode 100644 index 0000000000..ec7d1e016c Binary files /dev/null and b/assets/Roboto-Condensed.ttf differ diff --git a/ext/disarm.cpp b/ext/disarm.cpp index 17bd426e20..767e112b1a 100644 --- a/ext/disarm.cpp +++ b/ext/disarm.cpp @@ -113,6 +113,10 @@ int GetVm(uint32_t op, bool quad = false, bool dbl = false) { // Horrible array of hacks but hey. Can be cleaned up later. bool DisasmVFP(uint32_t op, char *text) { +#if defined(ANDROID) && defined(_M_IX86) + // Prevent linking errors with ArmEmitter which I've excluded on x86 android. + strcpy(text, "ARM disasm not available"); +#else const char *cond = CCFlagsStr[op >> 28]; switch ((op >> 24) & 0xF) { case 0xD: @@ -216,6 +220,7 @@ bool DisasmVFP(uint32_t op, char *text) { } break; } +#endif return false; } diff --git a/ext/libkirk/libkirk.vcxproj b/ext/libkirk/libkirk.vcxproj index 75268c2a26..fd8203f0e0 100644 --- a/ext/libkirk/libkirk.vcxproj +++ b/ext/libkirk/libkirk.vcxproj @@ -27,27 +27,27 @@ StaticLibrary true v100 - MultiByte + Unicode StaticLibrary true v100 - MultiByte + Unicode StaticLibrary false v100 false - MultiByte + Unicode StaticLibrary false v100 false - MultiByte + Unicode diff --git a/ext/zlib/zlib.vcxproj b/ext/zlib/zlib.vcxproj index f1b99505d1..e3499d2ec0 100644 --- a/ext/zlib/zlib.vcxproj +++ b/ext/zlib/zlib.vcxproj @@ -57,24 +57,24 @@ StaticLibrary true - MultiByte + Unicode StaticLibrary true - MultiByte + Unicode StaticLibrary false false - MultiByte + Unicode StaticLibrary false false - MultiByte + Unicode diff --git a/flash0/font/jpn0.pgf b/flash0/font/jpn0.pgf index 42090ce9df..7b2477666f 100755 Binary files a/flash0/font/jpn0.pgf and b/flash0/font/jpn0.pgf differ diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index dd505e6263..b40b8700dd 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -28,24 +28,24 @@ Application true - MultiByte + Unicode Application true - MultiByte + Unicode Application false false - MultiByte + Unicode Application false false - MultiByte + Unicode diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 022d93d78b..f542803317 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -22,6 +22,7 @@ #include "Common/CommonWindows.h" #include +#include "base/logging.h" #include "gfx_es2/gl_state.h" #include "gfx/gl_common.h" #include "gfx/gl_lost_manager.h" @@ -48,13 +49,13 @@ HWND CreateHiddenWindow() LoadCursor(NULL, IDC_ARROW), (HBRUSH) GetStockObject(BLACK_BRUSH), NULL, - "PPSSPPHeadless", + _T("PPSSPPHeadless"), NULL, }; RegisterClassEx(&wndClass); DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; - return CreateWindowEx(0, "PPSSPPHeadless", "PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL); + return CreateWindowEx(0, _T("PPSSPPHeadless"), _T("PPSSPPHeadless"), style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL); } void SetVSync(int value) @@ -89,7 +90,7 @@ void WindowsHeadlessHost::LoadNativeAssets() void WindowsHeadlessHost::SendDebugOutput(const std::string &output) { fwrite(output.data(), sizeof(char), output.length(), out); - OutputDebugString(output.c_str()); + OutputDebugStringUTF8(output.c_str()); } void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) diff --git a/test.py b/test.py index 1de45a91e2..5197bad262 100755 --- a/test.py +++ b/test.py @@ -103,6 +103,14 @@ tests_good = [ "threads/events/refer/refer", "threads/events/set/set", "threads/events/wait/wait", + "threads/fpl/fpl", + "threads/fpl/allocate", + "threads/fpl/cancel", + "threads/fpl/create", + "threads/fpl/delete", + "threads/fpl/free", + "threads/fpl/priority", + "threads/fpl/tryallocate", "threads/k0/k0", "threads/lwmutex/create", "threads/lwmutex/delete", @@ -131,6 +139,7 @@ tests_good = [ "threads/msgpipe/send", "threads/msgpipe/tryreceive", "threads/msgpipe/trysend", + "threads/mutex/cancel", "threads/mutex/create", "threads/mutex/delete", "threads/mutex/lock", @@ -165,6 +174,9 @@ tests_good = [ "utility/savedata/filelist", "utility/systemparam/systemparam", "power/power", + "power/volatile/lock", + "power/volatile/trylock", + "power/volatile/unlock", "umd/callbacks/umd", "umd/wait/wait", "io/directory/directory", @@ -175,11 +187,9 @@ tests_next = [ "audio/atrac/atractest", "audio/mp3/mp3test", "audio/sascore/sascore", - "audot/sceaudio/datalen", - "audot/sceaudio/output", - "audot/sceaudio/reserve", - "threads/fpl/fpl", - "threads/mutex/cancel", + "audio/sceaudio/datalen", + "audio/sceaudio/output", + "audio/sceaudio/reserve", "threads/scheduling/dispatch", "threads/scheduling/scheduling", "threads/threads/change", diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj index d218ac7f59..0ef1bb9656 100644 --- a/unittest/UnitTests.vcxproj +++ b/unittest/UnitTests.vcxproj @@ -29,27 +29,27 @@ Application true v100 - MultiByte + Unicode Application true v100 - MultiByte + Unicode Application false v100 false - MultiByte + Unicode Application false v100 false - MultiByte + Unicode