mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 22:40:17 +00:00
commit
f5c12d5cda
@ -9,6 +9,8 @@ if (NOT MSVC)
|
|||||||
else()
|
else()
|
||||||
# Silence deprecation warnings
|
# Silence deprecation warnings
|
||||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
# set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
endif()
|
endif()
|
||||||
add_definitions(-DSINGLETHREADED)
|
add_definitions(-DSINGLETHREADED)
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spac
|
|||||||
### Comments
|
### Comments
|
||||||
* For regular comments, use C++ style (`//`) comments, even for multi-line ones.
|
* For regular comments, use C++ style (`//`) comments, even for multi-line ones.
|
||||||
* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`.
|
* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`.
|
||||||
|
* For items that are both defined and declared in two separate files, put the doc-comment only next to the associated declaration. (In a header file, usually.) Otherwise, put it next to the implementation. Never duplicate doc-comments in both places.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
namespace Example {
|
namespace Example {
|
||||||
|
@ -76,9 +76,9 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
|
|||||||
std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
|
std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
|
||||||
m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
|
m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
|
||||||
(VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
|
(VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
|
||||||
window_title.c_str(), NULL, NULL);
|
window_title.c_str(), nullptr, nullptr);
|
||||||
|
|
||||||
if (m_render_window == NULL) {
|
if (m_render_window == nullptr) {
|
||||||
ERROR_LOG(GUI, "Failed to create GLFW window! Exiting...");
|
ERROR_LOG(GUI, "Failed to create GLFW window! Exiting...");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ void EmuWindow_GLFW::MakeCurrent() {
|
|||||||
|
|
||||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||||
void EmuWindow_GLFW::DoneCurrent() {
|
void EmuWindow_GLFW::DoneCurrent() {
|
||||||
glfwMakeContextCurrent(NULL);
|
glfwMakeContextCurrent(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_GLFW::ReloadSetKeymaps() {
|
void EmuWindow_GLFW::ReloadSetKeymaps() {
|
||||||
|
@ -230,7 +230,7 @@ QByteArray GRenderWindow::saveGeometry()
|
|||||||
{
|
{
|
||||||
// If we are a top-level widget, store the current geometry
|
// If we are a top-level widget, store the current geometry
|
||||||
// otherwise, store the last backup
|
// otherwise, store the last backup
|
||||||
if (parent() == NULL)
|
if (parent() == nullptr)
|
||||||
return ((QGLWidget*)this)->saveGeometry();
|
return ((QGLWidget*)this)->saveGeometry();
|
||||||
else
|
else
|
||||||
return geometry;
|
return geometry;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
struct Hotkey
|
struct Hotkey
|
||||||
{
|
{
|
||||||
Hotkey() : shortcut(NULL), context(Qt::WindowShortcut) {}
|
Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
|
||||||
|
|
||||||
QKeySequence keyseq;
|
QKeySequence keyseq;
|
||||||
QShortcut* shortcut;
|
QShortcut* shortcut;
|
||||||
@ -81,7 +81,7 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge
|
|||||||
Hotkey& hk = hotkey_groups[group][action];
|
Hotkey& hk = hotkey_groups[group][action];
|
||||||
|
|
||||||
if (!hk.shortcut)
|
if (!hk.shortcut)
|
||||||
hk.shortcut = new QShortcut(hk.keyseq, widget, NULL, NULL, hk.context);
|
hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context);
|
||||||
|
|
||||||
return hk.shortcut;
|
return hk.shortcut;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ GMainWindow::GMainWindow()
|
|||||||
GMainWindow::~GMainWindow()
|
GMainWindow::~GMainWindow()
|
||||||
{
|
{
|
||||||
// will get automatically deleted otherwise
|
// will get automatically deleted otherwise
|
||||||
if (render_window->parent() == NULL)
|
if (render_window->parent() == nullptr)
|
||||||
delete render_window;
|
delete render_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ void GMainWindow::BootGame(std::string filename)
|
|||||||
|
|
||||||
void GMainWindow::OnMenuLoadFile()
|
void GMainWindow::OnMenuLoadFile()
|
||||||
{
|
{
|
||||||
QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.elf *.axf *.bin *.cci *.cxi)"));
|
QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
|
||||||
if (filename.size())
|
if (filename.size())
|
||||||
BootGame(filename.toLatin1().data());
|
BootGame(filename.toLatin1().data());
|
||||||
}
|
}
|
||||||
@ -213,14 +213,14 @@ void GMainWindow::OnOpenHotkeysDialog()
|
|||||||
void GMainWindow::ToggleWindowMode()
|
void GMainWindow::ToggleWindowMode()
|
||||||
{
|
{
|
||||||
bool enable = ui.action_Popout_Window_Mode->isChecked();
|
bool enable = ui.action_Popout_Window_Mode->isChecked();
|
||||||
if (enable && render_window->parent() != NULL)
|
if (enable && render_window->parent() != nullptr)
|
||||||
{
|
{
|
||||||
ui.horizontalLayout->removeWidget(render_window);
|
ui.horizontalLayout->removeWidget(render_window);
|
||||||
render_window->setParent(NULL);
|
render_window->setParent(nullptr);
|
||||||
render_window->setVisible(true);
|
render_window->setVisible(true);
|
||||||
render_window->RestoreGeometry();
|
render_window->RestoreGeometry();
|
||||||
}
|
}
|
||||||
else if (!enable && render_window->parent() == NULL)
|
else if (!enable && render_window->parent() == nullptr)
|
||||||
{
|
{
|
||||||
render_window->BackupGeometry();
|
render_window->BackupGeometry();
|
||||||
ui.horizontalLayout->addWidget(render_window);
|
ui.horizontalLayout->addWidget(render_window);
|
||||||
|
@ -204,11 +204,11 @@ public:
|
|||||||
{
|
{
|
||||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||||
{
|
{
|
||||||
if (it->second != NULL)
|
if (it->second != nullptr)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T *dv = NULL;
|
T *dv = nullptr;
|
||||||
DoMap(x, dv);
|
DoMap(x, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,11 +264,11 @@ public:
|
|||||||
{
|
{
|
||||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||||
{
|
{
|
||||||
if (it->second != NULL)
|
if (it->second != nullptr)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T *dv = NULL;
|
T *dv = nullptr;
|
||||||
DoMultimap(x, dv);
|
DoMultimap(x, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Do(std::vector<T *> &x)
|
void Do(std::vector<T *> &x)
|
||||||
{
|
{
|
||||||
T *dv = NULL;
|
T *dv = nullptr;
|
||||||
DoVector(x, dv);
|
DoVector(x, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +369,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Do(std::deque<T *> &x)
|
void Do(std::deque<T *> &x)
|
||||||
{
|
{
|
||||||
T *dv = NULL;
|
T *dv = nullptr;
|
||||||
DoDeque(x, dv);
|
DoDeque(x, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +395,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Do(std::list<T *> &x)
|
void Do(std::list<T *> &x)
|
||||||
{
|
{
|
||||||
T *dv = NULL;
|
T *dv = nullptr;
|
||||||
Do(x, dv);
|
Do(x, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +433,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||||
{
|
{
|
||||||
if (*it != NULL)
|
if (*it != nullptr)
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,7 +518,7 @@ public:
|
|||||||
void DoClass(T *&x) {
|
void DoClass(T *&x) {
|
||||||
if (mode == MODE_READ)
|
if (mode == MODE_READ)
|
||||||
{
|
{
|
||||||
if (x != NULL)
|
if (x != nullptr)
|
||||||
delete x;
|
delete x;
|
||||||
x = new T();
|
x = new T();
|
||||||
}
|
}
|
||||||
@ -567,7 +567,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (mode == MODE_READ)
|
if (mode == MODE_READ)
|
||||||
{
|
{
|
||||||
cur->next = 0;
|
cur->next = nullptr;
|
||||||
list_cur = cur;
|
list_cur = cur;
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = cur;
|
prev->next = cur;
|
||||||
@ -586,13 +586,13 @@ public:
|
|||||||
if (mode == MODE_READ)
|
if (mode == MODE_READ)
|
||||||
{
|
{
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = 0;
|
prev->next = nullptr;
|
||||||
if (list_end)
|
if (list_end)
|
||||||
*list_end = prev;
|
*list_end = prev;
|
||||||
if (list_cur)
|
if (list_cur)
|
||||||
{
|
{
|
||||||
if (list_start == list_cur)
|
if (list_start == list_cur)
|
||||||
list_start = 0;
|
list_start = nullptr;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
LinkedListItem<T>* next = list_cur->next;
|
LinkedListItem<T>* next = list_cur->next;
|
||||||
|
@ -106,7 +106,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){
|
|||||||
// Restore the global locale
|
// Restore the global locale
|
||||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||||
}
|
}
|
||||||
else if(new_locale != NULL)
|
else if(new_locale != nullptr)
|
||||||
{
|
{
|
||||||
// Configure the thread to set the locale only for this thread
|
// Configure the thread to set the locale only for this thread
|
||||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
ConsoleListener::ConsoleListener()
|
ConsoleListener::ConsoleListener()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
hConsole = NULL;
|
hConsole = nullptr;
|
||||||
bUseColor = true;
|
bUseColor = true;
|
||||||
#else
|
#else
|
||||||
bUseColor = isatty(fileno(stdout));
|
bUseColor = isatty(fileno(stdout));
|
||||||
@ -66,19 +66,19 @@ void ConsoleListener::UpdateHandle()
|
|||||||
void ConsoleListener::Close()
|
void ConsoleListener::Close()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (hConsole == NULL)
|
if (hConsole == nullptr)
|
||||||
return;
|
return;
|
||||||
FreeConsole();
|
FreeConsole();
|
||||||
hConsole = NULL;
|
hConsole = nullptr;
|
||||||
#else
|
#else
|
||||||
fflush(NULL);
|
fflush(nullptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleListener::IsOpen()
|
bool ConsoleListener::IsOpen()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return (hConsole != NULL);
|
return (hConsole != nullptr);
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
@ -82,7 +82,7 @@ static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add user defined path
|
// Add user defined path
|
||||||
if ( lpszIniPath != NULL )
|
if ( lpszIniPath != nullptr )
|
||||||
if ( lpszIniPath[0] != '\0' )
|
if ( lpszIniPath[0] != '\0' )
|
||||||
{
|
{
|
||||||
strcat( lpszSymbolPath, ";" );
|
strcat( lpszSymbolPath, ";" );
|
||||||
@ -138,7 +138,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
|
|||||||
DWORD dwSymSize = 10000;
|
DWORD dwSymSize = 10000;
|
||||||
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
|
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
|
||||||
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
|
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
|
||||||
LPTSTR lpszParamSep = NULL;
|
LPTSTR lpszParamSep = nullptr;
|
||||||
LPTSTR lpszParsed = lpszUnDSymbol;
|
LPTSTR lpszParsed = lpszUnDSymbol;
|
||||||
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
|
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
|
||||||
|
|
||||||
@ -187,13 +187,13 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
|
|||||||
|
|
||||||
// Let's go through the stack, and modify the function prototype, and insert the actual
|
// Let's go through the stack, and modify the function prototype, and insert the actual
|
||||||
// parameter values from the stack
|
// parameter values from the stack
|
||||||
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
|
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == nullptr && _tcsstr( lpszUnDSymbol, _T("()") ) == nullptr)
|
||||||
{
|
{
|
||||||
ULONG index = 0;
|
ULONG index = 0;
|
||||||
for( ; ; index++ )
|
for( ; ; index++ )
|
||||||
{
|
{
|
||||||
lpszParamSep = _tcschr( lpszParsed, _T(',') );
|
lpszParamSep = _tcschr( lpszParsed, _T(',') );
|
||||||
if ( lpszParamSep == NULL )
|
if ( lpszParamSep == nullptr )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
*lpszParamSep = _T('\0');
|
*lpszParamSep = _T('\0');
|
||||||
@ -205,7 +205,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
|
|||||||
}
|
}
|
||||||
|
|
||||||
lpszParamSep = _tcschr( lpszParsed, _T(')') );
|
lpszParamSep = _tcschr( lpszParsed, _T(')') );
|
||||||
if ( lpszParamSep != NULL )
|
if ( lpszParamSep != nullptr )
|
||||||
{
|
{
|
||||||
*lpszParamSep = _T('\0');
|
*lpszParamSep = _T('\0');
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
|
|||||||
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
|
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
|
||||||
TCHAR fname[_MAX_FNAME];
|
TCHAR fname[_MAX_FNAME];
|
||||||
TCHAR ext[_MAX_EXT];
|
TCHAR ext[_MAX_EXT];
|
||||||
_tsplitpath(lpszFileName, NULL, NULL, fname, ext);
|
_tsplitpath(lpszFileName, nullptr, nullptr, fname, ext);
|
||||||
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
|
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
@ -332,11 +332,11 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
|
|||||||
hProcess,
|
hProcess,
|
||||||
hThread,
|
hThread,
|
||||||
&callStack,
|
&callStack,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
SymFunctionTableAccess,
|
SymFunctionTableAccess,
|
||||||
SymGetModuleBase,
|
SymGetModuleBase,
|
||||||
NULL);
|
nullptr);
|
||||||
|
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
continue;
|
continue;
|
||||||
@ -389,11 +389,11 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip,
|
|||||||
hProcess,
|
hProcess,
|
||||||
hThread,
|
hThread,
|
||||||
&callStack,
|
&callStack,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
SymFunctionTableAccess,
|
SymFunctionTableAccess,
|
||||||
SymGetModuleBase,
|
SymGetModuleBase,
|
||||||
NULL);
|
nullptr);
|
||||||
|
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
@ -57,7 +57,7 @@ public:
|
|||||||
// advance the read pointer
|
// advance the read pointer
|
||||||
m_read_ptr = m_read_ptr->next;
|
m_read_ptr = m_read_ptr->next;
|
||||||
// set the next element to NULL to stop the recursive deletion
|
// set the next element to NULL to stop the recursive deletion
|
||||||
tmpptr->next = NULL;
|
tmpptr->next = nullptr;
|
||||||
delete tmpptr; // this also deletes the element
|
delete tmpptr; // this also deletes the element
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ private:
|
|||||||
class ElementPtr
|
class ElementPtr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ElementPtr() : current(NULL), next(NULL) {}
|
ElementPtr() : current(nullptr), next(nullptr) {}
|
||||||
|
|
||||||
~ElementPtr()
|
~ElementPtr()
|
||||||
{
|
{
|
||||||
|
@ -140,7 +140,7 @@ bool CreateDir(const std::string &path)
|
|||||||
{
|
{
|
||||||
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
|
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL))
|
if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), nullptr))
|
||||||
return true;
|
return true;
|
||||||
DWORD error = GetLastError();
|
DWORD error = GetLastError();
|
||||||
if (error == ERROR_ALREADY_EXISTS)
|
if (error == ERROR_ALREADY_EXISTS)
|
||||||
@ -423,7 +423,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
|
|||||||
FSTEntry entry;
|
FSTEntry entry;
|
||||||
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
|
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
|
||||||
#else
|
#else
|
||||||
struct dirent dirent, *result = NULL;
|
struct dirent dirent, *result = nullptr;
|
||||||
|
|
||||||
DIR *dirp = opendir(directory.c_str());
|
DIR *dirp = opendir(directory.c_str());
|
||||||
if (!dirp)
|
if (!dirp)
|
||||||
@ -491,7 +491,7 @@ bool DeleteDirRecursively(const std::string &directory)
|
|||||||
{
|
{
|
||||||
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
|
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
|
||||||
#else
|
#else
|
||||||
struct dirent dirent, *result = NULL;
|
struct dirent dirent, *result = nullptr;
|
||||||
DIR *dirp = opendir(directory.c_str());
|
DIR *dirp = opendir(directory.c_str());
|
||||||
if (!dirp)
|
if (!dirp)
|
||||||
return false;
|
return false;
|
||||||
@ -552,7 +552,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
|
|||||||
if (!FileUtil::Exists(source_path)) return;
|
if (!FileUtil::Exists(source_path)) return;
|
||||||
if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
|
if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
|
||||||
|
|
||||||
struct dirent dirent, *result = NULL;
|
struct dirent dirent, *result = nullptr;
|
||||||
DIR *dirp = opendir(source_path.c_str());
|
DIR *dirp = opendir(source_path.c_str());
|
||||||
if (!dirp) return;
|
if (!dirp) return;
|
||||||
|
|
||||||
@ -586,11 +586,11 @@ std::string GetCurrentDir()
|
|||||||
{
|
{
|
||||||
char *dir;
|
char *dir;
|
||||||
// Get the current working directory (getcwd uses malloc)
|
// Get the current working directory (getcwd uses malloc)
|
||||||
if (!(dir = __getcwd(NULL, 0))) {
|
if (!(dir = __getcwd(nullptr, 0))) {
|
||||||
|
|
||||||
ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
|
ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
|
||||||
GetLastErrorMsg());
|
GetLastErrorMsg());
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::string strDir = dir;
|
std::string strDir = dir;
|
||||||
free(dir);
|
free(dir);
|
||||||
@ -626,7 +626,7 @@ std::string& GetExeDirectory()
|
|||||||
if (DolphinPath.empty())
|
if (DolphinPath.empty())
|
||||||
{
|
{
|
||||||
TCHAR Dolphin_exe_Path[2048];
|
TCHAR Dolphin_exe_Path[2048];
|
||||||
GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
|
GetModuleFileName(nullptr, Dolphin_exe_Path, 2048);
|
||||||
DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
|
DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
|
||||||
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
|
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
|
||||||
}
|
}
|
||||||
@ -826,7 +826,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
IOFile::IOFile()
|
IOFile::IOFile()
|
||||||
: m_file(NULL), m_good(true)
|
: m_file(nullptr), m_good(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
IOFile::IOFile(std::FILE* file)
|
IOFile::IOFile(std::FILE* file)
|
||||||
@ -834,7 +834,7 @@ IOFile::IOFile(std::FILE* file)
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
IOFile::IOFile(const std::string& filename, const char openmode[])
|
IOFile::IOFile(const std::string& filename, const char openmode[])
|
||||||
: m_file(NULL), m_good(true)
|
: m_file(nullptr), m_good(true)
|
||||||
{
|
{
|
||||||
Open(filename, openmode);
|
Open(filename, openmode);
|
||||||
}
|
}
|
||||||
@ -845,7 +845,7 @@ IOFile::~IOFile()
|
|||||||
}
|
}
|
||||||
|
|
||||||
IOFile::IOFile(IOFile&& other)
|
IOFile::IOFile(IOFile&& other)
|
||||||
: m_file(NULL), m_good(true)
|
: m_file(nullptr), m_good(true)
|
||||||
{
|
{
|
||||||
Swap(other);
|
Swap(other);
|
||||||
}
|
}
|
||||||
@ -880,14 +880,14 @@ bool IOFile::Close()
|
|||||||
if (!IsOpen() || 0 != std::fclose(m_file))
|
if (!IsOpen() || 0 != std::fclose(m_file))
|
||||||
m_good = false;
|
m_good = false;
|
||||||
|
|
||||||
m_file = NULL;
|
m_file = nullptr;
|
||||||
return m_good;
|
return m_good;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::FILE* IOFile::ReleaseHandle()
|
std::FILE* IOFile::ReleaseHandle()
|
||||||
{
|
{
|
||||||
std::FILE* const ret = m_file;
|
std::FILE* const ret = m_file;
|
||||||
m_file = NULL;
|
m_file = nullptr;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,11 +202,11 @@ public:
|
|||||||
return WriteArray(reinterpret_cast<const char*>(data), length);
|
return WriteArray(reinterpret_cast<const char*>(data), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOpen() { return NULL != m_file; }
|
bool IsOpen() { return nullptr != m_file; }
|
||||||
|
|
||||||
// m_good is set to false when a read, write or other function fails
|
// m_good is set to false when a read, write or other function fails
|
||||||
bool IsGood() { return m_good; }
|
bool IsGood() { return m_good; }
|
||||||
operator void*() { return m_good ? m_file : NULL; }
|
operator void*() { return m_good ? m_file : nullptr; }
|
||||||
|
|
||||||
std::FILE* ReleaseHandle();
|
std::FILE* ReleaseHandle();
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ public:
|
|||||||
// good header, read some key/value pairs
|
// good header, read some key/value pairs
|
||||||
K key;
|
K key;
|
||||||
|
|
||||||
V *value = NULL;
|
V *value = nullptr;
|
||||||
u32 value_size;
|
u32 value_size;
|
||||||
u32 entry_number;
|
u32 entry_number;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char*
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager *LogManager::m_logManager = NULL;
|
LogManager *LogManager::m_logManager = nullptr;
|
||||||
|
|
||||||
LogManager::LogManager()
|
LogManager::LogManager()
|
||||||
{
|
{
|
||||||
@ -141,7 +141,7 @@ void LogManager::Init()
|
|||||||
void LogManager::Shutdown()
|
void LogManager::Shutdown()
|
||||||
{
|
{
|
||||||
delete m_logManager;
|
delete m_logManager;
|
||||||
m_logManager = NULL;
|
m_logManager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
|
LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IOS
|
#ifdef IOS
|
||||||
void* globalbase = NULL;
|
void* globalbase = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@ -121,7 +121,7 @@ void MemArena::GrabLowMemSpace(size_t size)
|
|||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef _XBOX
|
#ifndef _XBOX
|
||||||
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
|
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr);
|
||||||
GetSystemInfo(&sysInfo);
|
GetSystemInfo(&sysInfo);
|
||||||
#endif
|
#endif
|
||||||
#elif defined(ANDROID)
|
#elif defined(ANDROID)
|
||||||
@ -178,7 +178,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
|
|||||||
#ifdef _XBOX
|
#ifdef _XBOX
|
||||||
size = roundup(size);
|
size = roundup(size);
|
||||||
// use 64kb pages
|
// use 64kb pages
|
||||||
void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
void * ptr = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||||
return ptr;
|
return ptr;
|
||||||
#else
|
#else
|
||||||
size = roundup(size);
|
size = roundup(size);
|
||||||
@ -243,8 +243,8 @@ u8* MemArena::Find4GBBase()
|
|||||||
return base;
|
return base;
|
||||||
#else
|
#else
|
||||||
#ifdef IOS
|
#ifdef IOS
|
||||||
void* base = NULL;
|
void* base = nullptr;
|
||||||
if (globalbase == NULL){
|
if (globalbase == nullptr){
|
||||||
base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE,
|
base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE,
|
||||||
MAP_ANON | MAP_SHARED, -1, 0);
|
MAP_ANON | MAP_SHARED, -1, 0);
|
||||||
if (base == MAP_FAILED) {
|
if (base == MAP_FAILED) {
|
||||||
@ -357,7 +357,7 @@ bail:
|
|||||||
if (views[j].out_ptr_low && *views[j].out_ptr_low)
|
if (views[j].out_ptr_low && *views[j].out_ptr_low)
|
||||||
{
|
{
|
||||||
arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
|
arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
|
||||||
*views[j].out_ptr_low = NULL;
|
*views[j].out_ptr_low = nullptr;
|
||||||
}
|
}
|
||||||
if (*views[j].out_ptr)
|
if (*views[j].out_ptr)
|
||||||
{
|
{
|
||||||
@ -369,7 +369,7 @@ bail:
|
|||||||
arena->ReleaseView(*views[j].out_ptr, views[j].size);
|
arena->ReleaseView(*views[j].out_ptr, views[j].size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
*views[j].out_ptr = NULL;
|
*views[j].out_ptr = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -415,7 +415,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
|
|||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
// Try a whole range of possible bases. Return once we got a valid one.
|
// Try a whole range of possible bases. Return once we got a valid one.
|
||||||
u32 max_base_addr = 0x7FFF0000 - 0x10000000;
|
u32 max_base_addr = 0x7FFF0000 - 0x10000000;
|
||||||
u8 *base = NULL;
|
u8 *base = nullptr;
|
||||||
|
|
||||||
for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
|
for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
|
||||||
{
|
{
|
||||||
@ -463,8 +463,8 @@ void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemAr
|
|||||||
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
|
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
|
||||||
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
|
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
|
||||||
arena->ReleaseView(*views[i].out_ptr, views[i].size);
|
arena->ReleaseView(*views[i].out_ptr, views[i].size);
|
||||||
*views[i].out_ptr = NULL;
|
*views[i].out_ptr = nullptr;
|
||||||
if (views[i].out_ptr_low)
|
if (views[i].out_ptr_low)
|
||||||
*views[i].out_ptr_low = NULL;
|
*views[i].out_ptr_low = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ void* AllocateMemoryPages(size_t size)
|
|||||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||||
// (unsigned long)size);
|
// (unsigned long)size);
|
||||||
|
|
||||||
if (ptr == NULL)
|
if (ptr == nullptr)
|
||||||
PanicAlert("Failed to allocate raw memory");
|
PanicAlert("Failed to allocate raw memory");
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
@ -104,7 +104,7 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
void* ptr = _aligned_malloc(size,alignment);
|
void* ptr = _aligned_malloc(size,alignment);
|
||||||
#else
|
#else
|
||||||
void* ptr = NULL;
|
void* ptr = nullptr;
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
ptr = memalign(alignment, size);
|
ptr = memalign(alignment, size);
|
||||||
#else
|
#else
|
||||||
@ -116,7 +116,7 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
|||||||
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
// printf("Mapped memory at %p (size %ld)\n", ptr,
|
||||||
// (unsigned long)size);
|
// (unsigned long)size);
|
||||||
|
|
||||||
if (ptr == NULL)
|
if (ptr == nullptr)
|
||||||
PanicAlert("Failed to allocate aligned memory");
|
PanicAlert("Failed to allocate aligned memory");
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
@ -130,7 +130,7 @@ void FreeMemoryPages(void* ptr, size_t size)
|
|||||||
|
|
||||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||||
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||||
ptr = NULL; // Is this our responsibility?
|
ptr = nullptr; // Is this our responsibility?
|
||||||
|
|
||||||
#else
|
#else
|
||||||
munmap(ptr, size);
|
munmap(ptr, size);
|
||||||
@ -184,7 +184,7 @@ std::string MemUsage()
|
|||||||
// Print information about the memory usage of the process.
|
// Print information about the memory usage of the process.
|
||||||
|
|
||||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
||||||
if (NULL == hProcess) return "MemUsage Error";
|
if (nullptr == hProcess) return "MemUsage Error";
|
||||||
|
|
||||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
||||||
Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||||
|
@ -23,9 +23,9 @@ const char* GetLastErrorMsg()
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static __declspec(thread) char err_str[buff_size] = {};
|
static __declspec(thread) char err_str[buff_size] = {};
|
||||||
|
|
||||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
err_str, buff_size, NULL);
|
err_str, buff_size, nullptr);
|
||||||
#else
|
#else
|
||||||
static __thread char err_str[buff_size] = {};
|
static __thread char err_str[buff_size] = {};
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
|
inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
|
||||||
if (localtime_s(result, clock) == 0)
|
if (localtime_s(result, clock) == 0)
|
||||||
return result;
|
return result;
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -31,7 +31,7 @@ std::string ToUpper(std::string str) {
|
|||||||
// faster than sscanf
|
// faster than sscanf
|
||||||
bool AsciiToHex(const char* _szValue, u32& result)
|
bool AsciiToHex(const char* _szValue, u32& result)
|
||||||
{
|
{
|
||||||
char *endptr = NULL;
|
char *endptr = nullptr;
|
||||||
const u32 value = strtoul(_szValue, &endptr, 16);
|
const u32 value = strtoul(_szValue, &endptr, 16);
|
||||||
|
|
||||||
if (!endptr || *endptr)
|
if (!endptr || *endptr)
|
||||||
@ -69,7 +69,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
|
|||||||
// will be present in the middle of a multibyte sequence.
|
// will be present in the middle of a multibyte sequence.
|
||||||
//
|
//
|
||||||
// This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
|
// This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
|
||||||
static locale_t c_locale = NULL;
|
static locale_t c_locale = nullptr;
|
||||||
if (!c_locale)
|
if (!c_locale)
|
||||||
c_locale = _create_locale(LC_ALL, ".1252");
|
c_locale = _create_locale(LC_ALL, ".1252");
|
||||||
writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
|
writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
|
||||||
@ -92,7 +92,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
|
|||||||
std::string StringFromFormat(const char* format, ...)
|
std::string StringFromFormat(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
char *buf = NULL;
|
char *buf = nullptr;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int required = 0;
|
int required = 0;
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ std::string StripQuotes(const std::string& s)
|
|||||||
|
|
||||||
bool TryParse(const std::string &str, u32 *const output)
|
bool TryParse(const std::string &str, u32 *const output)
|
||||||
{
|
{
|
||||||
char *endptr = NULL;
|
char *endptr = nullptr;
|
||||||
|
|
||||||
// Reset errno to a value other than ERANGE
|
// Reset errno to a value other than ERANGE
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
@ -37,7 +37,7 @@ struct ThreadQueueList {
|
|||||||
~ThreadQueueList() {
|
~ThreadQueueList() {
|
||||||
for (int i = 0; i < NUM_QUEUES; ++i)
|
for (int i = 0; i < NUM_QUEUES; ++i)
|
||||||
{
|
{
|
||||||
if (queues[i].data != NULL)
|
if (queues[i].data != nullptr)
|
||||||
free(queues[i].data);
|
free(queues[i].data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ struct ThreadQueueList {
|
|||||||
int contains(const IdType uid) {
|
int contains(const IdType uid) {
|
||||||
for (int i = 0; i < NUM_QUEUES; ++i)
|
for (int i = 0; i < NUM_QUEUES; ++i)
|
||||||
{
|
{
|
||||||
if (queues[i].data == NULL)
|
if (queues[i].data == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Queue *cur = &queues[i];
|
Queue *cur = &queues[i];
|
||||||
@ -133,7 +133,7 @@ struct ThreadQueueList {
|
|||||||
inline void clear() {
|
inline void clear() {
|
||||||
for (int i = 0; i < NUM_QUEUES; ++i)
|
for (int i = 0; i < NUM_QUEUES; ++i)
|
||||||
{
|
{
|
||||||
if (queues[i].data != NULL)
|
if (queues[i].data != nullptr)
|
||||||
free(queues[i].data);
|
free(queues[i].data);
|
||||||
}
|
}
|
||||||
memset(queues, 0, sizeof(queues));
|
memset(queues, 0, sizeof(queues));
|
||||||
@ -147,7 +147,7 @@ struct ThreadQueueList {
|
|||||||
|
|
||||||
inline void prepare(u32 priority) {
|
inline void prepare(u32 priority) {
|
||||||
Queue *cur = &queues[priority];
|
Queue *cur = &queues[priority];
|
||||||
if (cur->next == NULL)
|
if (cur->next == nullptr)
|
||||||
link(priority, INITIAL_CAPACITY);
|
link(priority, INITIAL_CAPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ private:
|
|||||||
|
|
||||||
for (int i = (int) priority - 1; i >= 0; --i)
|
for (int i = (int) priority - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
if (queues[i].next != NULL)
|
if (queues[i].next != nullptr)
|
||||||
{
|
{
|
||||||
cur->next = queues[i].next;
|
cur->next = queues[i].next;
|
||||||
queues[i].next = cur;
|
queues[i].next = cur;
|
||||||
@ -193,7 +193,7 @@ private:
|
|||||||
int size = cur->end - cur->first;
|
int size = cur->end - cur->first;
|
||||||
if (size >= cur->capacity - 2) {
|
if (size >= cur->capacity - 2) {
|
||||||
IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
|
IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
|
||||||
if (new_data != NULL) {
|
if (new_data != nullptr) {
|
||||||
cur->capacity *= 2;
|
cur->capacity *= 2;
|
||||||
cur->data = new_data;
|
cur->data = new_data;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ u32 Timer::GetTimeMs()
|
|||||||
return timeGetTime();
|
return timeGetTime();
|
||||||
#else
|
#else
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
(void)gettimeofday(&t, NULL);
|
(void)gettimeofday(&t, nullptr);
|
||||||
return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
|
return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ std::string Timer::GetTimeFormatted()
|
|||||||
return StringFromFormat("%s:%03i", tmp, tp.millitm);
|
return StringFromFormat("%s:%03i", tmp, tp.millitm);
|
||||||
#else
|
#else
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
(void)gettimeofday(&t, NULL);
|
(void)gettimeofday(&t, nullptr);
|
||||||
return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
|
return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ double Timer::GetDoubleTime()
|
|||||||
(void)::ftime(&tp);
|
(void)::ftime(&tp);
|
||||||
#else
|
#else
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
(void)gettimeofday(&t, NULL);
|
(void)gettimeofday(&t, nullptr);
|
||||||
#endif
|
#endif
|
||||||
// Get continuous timestamp
|
// Get continuous timestamp
|
||||||
u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
|
u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
|
||||||
|
@ -281,28 +281,28 @@ int u8_read_escape_sequence(const char *str, u32 *dest)
|
|||||||
do {
|
do {
|
||||||
digs[dno++] = str[i++];
|
digs[dno++] = str[i++];
|
||||||
} while (octal_digit(str[i]) && dno < 3);
|
} while (octal_digit(str[i]) && dno < 3);
|
||||||
ch = strtol(digs, NULL, 8);
|
ch = strtol(digs, nullptr, 8);
|
||||||
}
|
}
|
||||||
else if (str[0] == 'x') {
|
else if (str[0] == 'x') {
|
||||||
while (hex_digit(str[i]) && dno < 2) {
|
while (hex_digit(str[i]) && dno < 2) {
|
||||||
digs[dno++] = str[i++];
|
digs[dno++] = str[i++];
|
||||||
}
|
}
|
||||||
if (dno > 0)
|
if (dno > 0)
|
||||||
ch = strtol(digs, NULL, 16);
|
ch = strtol(digs, nullptr, 16);
|
||||||
}
|
}
|
||||||
else if (str[0] == 'u') {
|
else if (str[0] == 'u') {
|
||||||
while (hex_digit(str[i]) && dno < 4) {
|
while (hex_digit(str[i]) && dno < 4) {
|
||||||
digs[dno++] = str[i++];
|
digs[dno++] = str[i++];
|
||||||
}
|
}
|
||||||
if (dno > 0)
|
if (dno > 0)
|
||||||
ch = strtol(digs, NULL, 16);
|
ch = strtol(digs, nullptr, 16);
|
||||||
}
|
}
|
||||||
else if (str[0] == 'U') {
|
else if (str[0] == 'U') {
|
||||||
while (hex_digit(str[i]) && dno < 8) {
|
while (hex_digit(str[i]) && dno < 8) {
|
||||||
digs[dno++] = str[i++];
|
digs[dno++] = str[i++];
|
||||||
}
|
}
|
||||||
if (dno > 0)
|
if (dno > 0)
|
||||||
ch = strtol(digs, NULL, 16);
|
ch = strtol(digs, nullptr, 16);
|
||||||
}
|
}
|
||||||
*dest = ch;
|
*dest = ch;
|
||||||
|
|
||||||
@ -353,7 +353,7 @@ const char *u8_strchr(const char *s, u32 ch, int *charn)
|
|||||||
lasti = i;
|
lasti = i;
|
||||||
(*charn)++;
|
(*charn)++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
|
const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
|
||||||
@ -378,7 +378,7 @@ const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
|
|||||||
lasti = i;
|
lasti = i;
|
||||||
(*charn)++;
|
(*charn)++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int u8_is_locale_utf8(const char *locale)
|
int u8_is_locale_utf8(const char *locale)
|
||||||
@ -419,35 +419,35 @@ bool UTF8StringHasNonASCII(const char *utf8string) {
|
|||||||
|
|
||||||
std::string ConvertWStringToUTF8(const wchar_t *wstr) {
|
std::string ConvertWStringToUTF8(const wchar_t *wstr) {
|
||||||
int len = (int)wcslen(wstr);
|
int len = (int)wcslen(wstr);
|
||||||
int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL);
|
int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, nullptr, nullptr);
|
||||||
std::string s;
|
std::string s;
|
||||||
s.resize(size);
|
s.resize(size);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ConvertWStringToUTF8(const std::wstring &wstr) {
|
std::string ConvertWStringToUTF8(const std::wstring &wstr) {
|
||||||
int len = (int)wstr.size();
|
int len = (int)wstr.size();
|
||||||
int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL);
|
int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, nullptr, nullptr);
|
||||||
std::string s;
|
std::string s;
|
||||||
s.resize(size);
|
s.resize(size);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) {
|
void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) {
|
||||||
int len = (int)source.size();
|
int len = (int)source.size();
|
||||||
int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0);
|
int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size));
|
MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ConvertUTF8ToWString(const std::string &source) {
|
std::wstring ConvertUTF8ToWString(const std::string &source) {
|
||||||
int len = (int)source.size();
|
int len = (int)source.size();
|
||||||
int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0);
|
int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
|
||||||
std::wstring str;
|
std::wstring str;
|
||||||
str.resize(size);
|
str.resize(size);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
|
@ -63,6 +63,7 @@ set(SRCS
|
|||||||
loader/elf.cpp
|
loader/elf.cpp
|
||||||
loader/loader.cpp
|
loader/loader.cpp
|
||||||
loader/ncch.cpp
|
loader/ncch.cpp
|
||||||
|
loader/3dsx.cpp
|
||||||
core.cpp
|
core.cpp
|
||||||
core_timing.cpp
|
core_timing.cpp
|
||||||
mem_map.cpp
|
mem_map.cpp
|
||||||
@ -143,6 +144,7 @@ set(HEADERS
|
|||||||
loader/elf.h
|
loader/elf.h
|
||||||
loader/loader.h
|
loader/loader.h
|
||||||
loader/ncch.h
|
loader/ncch.h
|
||||||
|
loader/3dsx.h
|
||||||
core.h
|
core.h
|
||||||
core_timing.h
|
core_timing.h
|
||||||
mem_map.h
|
mem_map.h
|
||||||
|
@ -5724,7 +5724,7 @@ L_stm_s_takeabort:
|
|||||||
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
||||||
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
||||||
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
||||||
state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
|
state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2)&0xFFFF)<< 0x10);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((instr & 0xFF0) == 0xf10)//sadd16
|
else if ((instr & 0xFF0) == 0xf10)//sadd16
|
||||||
@ -5736,7 +5736,7 @@ L_stm_s_takeabort:
|
|||||||
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
||||||
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
||||||
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
||||||
state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10);
|
state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2)&0xFFFF)<< 0x10);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((instr & 0xFF0) == 0xf50)//ssax
|
else if ((instr & 0xFF0) == 0xf50)//ssax
|
||||||
@ -5748,7 +5748,7 @@ L_stm_s_takeabort:
|
|||||||
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
||||||
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
||||||
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
||||||
state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
|
state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((instr & 0xFF0) == 0xf30)//sasx
|
else if ((instr & 0xFF0) == 0xf30)//sasx
|
||||||
@ -5760,7 +5760,7 @@ L_stm_s_takeabort:
|
|||||||
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
|
||||||
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
s16 b1 = (state->Reg[src2] & 0xFFFF);
|
||||||
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
|
||||||
state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
|
state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else printf ("Unhandled v6 insn: sadd/ssub\n");
|
else printf ("Unhandled v6 insn: sadd/ssub\n");
|
||||||
|
@ -67,7 +67,7 @@ s64 idledCycles;
|
|||||||
static std::recursive_mutex externalEventSection;
|
static std::recursive_mutex externalEventSection;
|
||||||
|
|
||||||
// Warning: not included in save state.
|
// Warning: not included in save state.
|
||||||
void(*advanceCallback)(int cyclesExecuted) = NULL;
|
void(*advanceCallback)(int cyclesExecuted) = nullptr;
|
||||||
|
|
||||||
void SetClockFrequencyMHz(int cpuMhz)
|
void SetClockFrequencyMHz(int cpuMhz)
|
||||||
{
|
{
|
||||||
@ -231,7 +231,7 @@ void ClearPendingEvents()
|
|||||||
|
|
||||||
void AddEventToQueue(Event* ne)
|
void AddEventToQueue(Event* ne)
|
||||||
{
|
{
|
||||||
Event* prev = NULL;
|
Event* prev = nullptr;
|
||||||
Event** pNext = &first;
|
Event** pNext = &first;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -327,7 +327,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
|
|||||||
}
|
}
|
||||||
if (!tsFirst)
|
if (!tsFirst)
|
||||||
{
|
{
|
||||||
tsLast = NULL;
|
tsLast = nullptr;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +433,7 @@ void RemoveThreadsafeEvent(int event_type)
|
|||||||
}
|
}
|
||||||
if (!tsFirst)
|
if (!tsFirst)
|
||||||
{
|
{
|
||||||
tsLast = NULL;
|
tsLast = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event *prev = tsFirst;
|
Event *prev = tsFirst;
|
||||||
@ -495,7 +495,7 @@ void MoveEvents()
|
|||||||
AddEventToQueue(tsFirst);
|
AddEventToQueue(tsFirst);
|
||||||
tsFirst = next;
|
tsFirst = next;
|
||||||
}
|
}
|
||||||
tsLast = NULL;
|
tsLast = nullptr;
|
||||||
|
|
||||||
// Move free events to threadsafe pool
|
// Move free events to threadsafe pool
|
||||||
while (allocatedTsEvents > 0 && eventPool)
|
while (allocatedTsEvents > 0 && eventPool)
|
||||||
@ -614,7 +614,7 @@ void DoState(PointerWrap &p)
|
|||||||
// These (should) be filled in later by the modules.
|
// These (should) be filled in later by the modules.
|
||||||
event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT"));
|
event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT"));
|
||||||
|
|
||||||
p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)NULL);
|
p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)nullptr);
|
||||||
p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
|
p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
|
||||||
|
|
||||||
p.Do(g_clock_rate_arm11);
|
p.Do(g_clock_rate_arm11);
|
||||||
|
@ -193,6 +193,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool DeleteFile(const FileSys::Path& path) const = 0;
|
virtual bool DeleteFile(const FileSys::Path& path) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a File specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
virtual bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -207,6 +215,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool CreateDirectory(const Path& path) const = 0;
|
virtual bool CreateDirectory(const Path& path) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a Directory specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
virtual bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
|
@ -43,6 +43,11 @@ bool Archive_RomFS::DeleteFile(const FileSys::Path& path) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Archive_RomFS::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
|
||||||
|
ERROR_LOG(FILESYS, "Attempted to rename a file within ROMFS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -63,6 +68,11 @@ bool Archive_RomFS::CreateDirectory(const Path& path) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
|
||||||
|
ERROR_LOG(FILESYS, "Attempted to rename a file within ROMFS.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
|
@ -43,6 +43,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool DeleteFile(const FileSys::Path& path) const override;
|
bool DeleteFile(const FileSys::Path& path) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a File specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -57,6 +65,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool CreateDirectory(const Path& path) const override;
|
bool CreateDirectory(const Path& path) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a Directory specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
|
@ -66,6 +66,10 @@ bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
|
|||||||
return FileUtil::Delete(GetMountPoint() + path.AsString());
|
return FileUtil::Delete(GetMountPoint() + path.AsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
|
||||||
|
return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -84,6 +88,10 @@ bool Archive_SDMC::CreateDirectory(const Path& path) const {
|
|||||||
return FileUtil::CreateDir(GetMountPoint() + path.AsString());
|
return FileUtil::CreateDir(GetMountPoint() + path.AsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
|
||||||
|
return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -92,6 +100,8 @@ bool Archive_SDMC::CreateDirectory(const Path& path) const {
|
|||||||
std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const {
|
std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const {
|
||||||
DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str());
|
DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str());
|
||||||
Directory_SDMC* directory = new Directory_SDMC(this, path);
|
Directory_SDMC* directory = new Directory_SDMC(this, path);
|
||||||
|
if (!directory->Open())
|
||||||
|
return nullptr;
|
||||||
return std::unique_ptr<Directory>(directory);
|
return std::unique_ptr<Directory>(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool DeleteFile(const FileSys::Path& path) const override;
|
bool DeleteFile(const FileSys::Path& path) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a File specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a directory specified by its path
|
* Delete a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
@ -61,6 +69,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool CreateDirectory(const Path& path) const override;
|
bool CreateDirectory(const Path& path) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a Directory specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a directory specified by its path
|
* Open a directory specified by its path
|
||||||
* @param path Path relative to the archive
|
* @param path Path relative to the archive
|
||||||
|
@ -41,6 +41,12 @@ public:
|
|||||||
Directory() { }
|
Directory() { }
|
||||||
virtual ~Directory() { }
|
virtual ~Directory() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the directory
|
||||||
|
* @return true if the directory opened correctly
|
||||||
|
*/
|
||||||
|
virtual bool Open() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List files contained in the directory
|
* List files contained in the directory
|
||||||
* @param count Number of entries to return at once in entries
|
* @param count Number of entries to return at once in entries
|
||||||
|
@ -17,6 +17,10 @@ Directory_RomFS::Directory_RomFS() {
|
|||||||
Directory_RomFS::~Directory_RomFS() {
|
Directory_RomFS::~Directory_RomFS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Directory_RomFS::Open() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List files contained in the directory
|
* List files contained in the directory
|
||||||
* @param count Number of entries to return at once in entries
|
* @param count Number of entries to return at once in entries
|
||||||
|
@ -19,6 +19,12 @@ public:
|
|||||||
Directory_RomFS();
|
Directory_RomFS();
|
||||||
~Directory_RomFS() override;
|
~Directory_RomFS() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the directory
|
||||||
|
* @return true if the directory opened correctly
|
||||||
|
*/
|
||||||
|
bool Open() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List files contained in the directory
|
* List files contained in the directory
|
||||||
* @param count Number of entries to return at once in entries
|
* @param count Number of entries to return at once in entries
|
||||||
|
@ -19,15 +19,22 @@ Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
|
|||||||
// TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
|
// TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
|
||||||
// the root directory we set while opening the archive.
|
// the root directory we set while opening the archive.
|
||||||
// For example, opening /../../usr/bin can give the emulated program your installed programs.
|
// For example, opening /../../usr/bin can give the emulated program your installed programs.
|
||||||
std::string absolute_path = archive->GetMountPoint() + path.AsString();
|
this->path = archive->GetMountPoint() + path.AsString();
|
||||||
FileUtil::ScanDirectoryTree(absolute_path, directory);
|
|
||||||
children_iterator = directory.children.begin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory_SDMC::~Directory_SDMC() {
|
Directory_SDMC::~Directory_SDMC() {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Directory_SDMC::Open() {
|
||||||
|
if (!FileUtil::IsDirectory(path))
|
||||||
|
return false;
|
||||||
|
FileUtil::ScanDirectoryTree(path, directory);
|
||||||
|
children_iterator = directory.children.begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List files contained in the directory
|
* List files contained in the directory
|
||||||
* @param count Number of entries to return at once in entries
|
* @param count Number of entries to return at once in entries
|
||||||
|
@ -22,6 +22,12 @@ public:
|
|||||||
Directory_SDMC(const Archive_SDMC* archive, const Path& path);
|
Directory_SDMC(const Archive_SDMC* archive, const Path& path);
|
||||||
~Directory_SDMC() override;
|
~Directory_SDMC() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the directory
|
||||||
|
* @return true if the directory opened correctly
|
||||||
|
*/
|
||||||
|
bool Open() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List files contained in the directory
|
* List files contained in the directory
|
||||||
* @param count Number of entries to return at once in entries
|
* @param count Number of entries to return at once in entries
|
||||||
@ -37,6 +43,7 @@ public:
|
|||||||
bool Close() const override;
|
bool Close() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string path;
|
||||||
u32 total_entries_in_directory;
|
u32 total_entries_in_directory;
|
||||||
FileUtil::FSTEntry directory;
|
FileUtil::FSTEntry directory;
|
||||||
|
|
||||||
|
@ -38,12 +38,15 @@ bool File_SDMC::Open() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string mode_string;
|
std::string mode_string;
|
||||||
if (mode.read_flag && mode.write_flag)
|
if (mode.create_flag)
|
||||||
mode_string = "w+";
|
mode_string = "w+";
|
||||||
|
else if (mode.write_flag)
|
||||||
|
mode_string = "r+"; // Files opened with Write access can be read from
|
||||||
else if (mode.read_flag)
|
else if (mode.read_flag)
|
||||||
mode_string = "r";
|
mode_string = "r";
|
||||||
else if (mode.write_flag)
|
|
||||||
mode_string = "w";
|
// Open the file in binary mode, to avoid problems with CR/LF on Windows systems
|
||||||
|
mode_string += "b";
|
||||||
|
|
||||||
file = new FileUtil::IOFile(path, mode_string.c_str());
|
file = new FileUtil::IOFile(path, mode_string.c_str());
|
||||||
return true;
|
return true;
|
||||||
|
@ -53,7 +53,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
|
|||||||
// Wait current thread (acquire the arbiter)...
|
// Wait current thread (acquire the arbiter)...
|
||||||
case ArbitrationType::WaitIfLessThan:
|
case ArbitrationType::WaitIfLessThan:
|
||||||
if ((s32)Memory::Read32(address) <= value) {
|
if ((s32)Memory::Read32(address) <= value) {
|
||||||
Kernel::WaitCurrentThread(WAITTYPE_ARB, handle);
|
Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address);
|
||||||
HLE::Reschedule(__func__);
|
HLE::Reschedule(__func__);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -340,49 +340,68 @@ ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path
|
|||||||
return MakeResult<Handle>(handle);
|
return MakeResult<Handle>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
||||||
* Delete a File from an Archive
|
|
||||||
* @param archive_handle Handle to an open Archive object
|
|
||||||
* @param path Path to the File inside of the Archive
|
|
||||||
* @return Whether deletion succeeded
|
|
||||||
*/
|
|
||||||
Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
|
||||||
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
||||||
if (archive == nullptr)
|
if (archive == nullptr)
|
||||||
return -1;
|
return InvalidHandle(ErrorModule::FS);
|
||||||
if (archive->backend->DeleteFile(path))
|
if (archive->backend->DeleteFile(path))
|
||||||
return 0;
|
return RESULT_SUCCESS;
|
||||||
return -1;
|
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
|
||||||
* Delete a Directory from an Archive
|
Handle dest_archive_handle, const FileSys::Path& dest_path) {
|
||||||
* @param archive_handle Handle to an open Archive object
|
Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle);
|
||||||
* @param path Path to the Directory inside of the Archive
|
Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle);
|
||||||
* @return Whether deletion succeeded
|
if (src_archive == nullptr || dest_archive == nullptr)
|
||||||
*/
|
return InvalidHandle(ErrorModule::FS);
|
||||||
Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
if (src_archive == dest_archive) {
|
||||||
|
if (src_archive->backend->RenameFile(src_path, dest_path))
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
// TODO: Implement renaming across archives
|
||||||
|
return UnimplementedFunction(ErrorModule::FS);
|
||||||
|
}
|
||||||
|
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
||||||
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
||||||
if (archive == nullptr)
|
if (archive == nullptr)
|
||||||
return -1;
|
return InvalidHandle(ErrorModule::FS);
|
||||||
if (archive->backend->DeleteDirectory(path))
|
if (archive->backend->DeleteDirectory(path))
|
||||||
return 0;
|
return RESULT_SUCCESS;
|
||||||
return -1;
|
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
||||||
* Create a Directory from an Archive
|
|
||||||
* @param archive_handle Handle to an open Archive object
|
|
||||||
* @param path Path to the Directory inside of the Archive
|
|
||||||
* @return Whether creation succeeded
|
|
||||||
*/
|
|
||||||
Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
|
|
||||||
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
|
||||||
if (archive == nullptr)
|
if (archive == nullptr)
|
||||||
return -1;
|
return InvalidHandle(ErrorModule::FS);
|
||||||
if (archive->backend->CreateDirectory(path))
|
if (archive->backend->CreateDirectory(path))
|
||||||
return 0;
|
return RESULT_SUCCESS;
|
||||||
return -1;
|
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
|
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
|
||||||
|
Handle dest_archive_handle, const FileSys::Path& dest_path) {
|
||||||
|
Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle);
|
||||||
|
Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle);
|
||||||
|
if (src_archive == nullptr || dest_archive == nullptr)
|
||||||
|
return InvalidHandle(ErrorModule::FS);
|
||||||
|
if (src_archive == dest_archive) {
|
||||||
|
if (src_archive->backend->RenameDirectory(src_path, dest_path))
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
// TODO: Implement renaming across archives
|
||||||
|
return UnimplementedFunction(ErrorModule::FS);
|
||||||
|
}
|
||||||
|
return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
|
||||||
|
ErrorSummary::NothingHappened, ErrorLevel::Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -402,6 +421,11 @@ ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys:
|
|||||||
directory->path = path;
|
directory->path = path;
|
||||||
directory->backend = archive->backend->OpenDirectory(path);
|
directory->backend = archive->backend->OpenDirectory(path);
|
||||||
|
|
||||||
|
if (!directory->backend) {
|
||||||
|
return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
|
||||||
|
ErrorSummary::NotFound, ErrorLevel::Permanent);
|
||||||
|
}
|
||||||
|
|
||||||
return MakeResult<Handle>(handle);
|
return MakeResult<Handle>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,18 @@ ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path
|
|||||||
* @param path Path to the File inside of the Archive
|
* @param path Path to the File inside of the Archive
|
||||||
* @return Whether deletion succeeded
|
* @return Whether deletion succeeded
|
||||||
*/
|
*/
|
||||||
Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
|
ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a File between two Archives
|
||||||
|
* @param src_archive_handle Handle to the source Archive object
|
||||||
|
* @param src_path Path to the File inside of the source Archive
|
||||||
|
* @param dest_archive_handle Handle to the destination Archive object
|
||||||
|
* @param dest_path Path to the File inside of the destination Archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
|
||||||
|
Handle dest_archive_handle, const FileSys::Path& dest_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a Directory from an Archive
|
* Delete a Directory from an Archive
|
||||||
@ -58,7 +69,7 @@ Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
|
|||||||
* @param path Path to the Directory inside of the Archive
|
* @param path Path to the Directory inside of the Archive
|
||||||
* @return Whether deletion succeeded
|
* @return Whether deletion succeeded
|
||||||
*/
|
*/
|
||||||
Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
|
ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Directory from an Archive
|
* Create a Directory from an Archive
|
||||||
@ -66,7 +77,18 @@ Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
|
|||||||
* @param path Path to the Directory inside of the Archive
|
* @param path Path to the Directory inside of the Archive
|
||||||
* @return Whether creation of directory succeeded
|
* @return Whether creation of directory succeeded
|
||||||
*/
|
*/
|
||||||
Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
|
ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a Directory between two Archives
|
||||||
|
* @param src_archive_handle Handle to the source Archive object
|
||||||
|
* @param src_path Path to the Directory inside of the source Archive
|
||||||
|
* @param dest_archive_handle Handle to the destination Archive object
|
||||||
|
* @param dest_path Path to the Directory inside of the destination Archive
|
||||||
|
* @return Whether rename succeeded
|
||||||
|
*/
|
||||||
|
ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
|
||||||
|
Handle dest_archive_handle, const FileSys::Path& dest_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a Directory from an Archive
|
* Open a Directory from an Archive
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Licensed under GPLv2
|
// Licensed under GPLv2
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
@ -37,7 +39,7 @@ Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectPool::IsValid(Handle handle) {
|
bool ObjectPool::IsValid(Handle handle) const {
|
||||||
int index = handle - HANDLE_OFFSET;
|
int index = handle - HANDLE_OFFSET;
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return false;
|
return false;
|
||||||
@ -75,13 +77,8 @@ void ObjectPool::List() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ObjectPool::GetCount() {
|
int ObjectPool::GetCount() const {
|
||||||
int count = 0;
|
return std::count(occupied.begin(), occupied.end(), true);
|
||||||
for (int i = 0; i < MAX_COUNT; i++) {
|
|
||||||
if (occupied[i])
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object* ObjectPool::CreateByIDType(int type) {
|
Object* ObjectPool::CreateByIDType(int type) {
|
||||||
|
@ -86,7 +86,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid(Handle handle);
|
bool IsValid(Handle handle) const;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T* Get(Handle handle) {
|
T* Get(Handle handle) {
|
||||||
@ -142,7 +142,7 @@ public:
|
|||||||
Object* &operator [](Handle handle);
|
Object* &operator [](Handle handle);
|
||||||
void List();
|
void List();
|
||||||
void Clear();
|
void Clear();
|
||||||
int GetCount();
|
int GetCount() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@ public:
|
|||||||
|
|
||||||
ThreadContext context;
|
ThreadContext context;
|
||||||
|
|
||||||
|
u32 thread_id;
|
||||||
|
|
||||||
u32 status;
|
u32 status;
|
||||||
u32 entry_point;
|
u32 entry_point;
|
||||||
u32 stack_top;
|
u32 stack_top;
|
||||||
@ -61,6 +63,7 @@ public:
|
|||||||
|
|
||||||
WaitType wait_type;
|
WaitType wait_type;
|
||||||
Handle wait_handle;
|
Handle wait_handle;
|
||||||
|
VAddr wait_address;
|
||||||
|
|
||||||
std::vector<Handle> waiting_threads;
|
std::vector<Handle> waiting_threads;
|
||||||
|
|
||||||
@ -76,6 +79,9 @@ static Common::ThreadQueueList<Handle> thread_ready_queue;
|
|||||||
static Handle current_thread_handle;
|
static Handle current_thread_handle;
|
||||||
static Thread* current_thread;
|
static Thread* current_thread;
|
||||||
|
|
||||||
|
static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
|
||||||
|
static u32 next_thread_id; ///< The next available thread id
|
||||||
|
|
||||||
/// Gets the current thread
|
/// Gets the current thread
|
||||||
inline Thread* GetCurrentThread() {
|
inline Thread* GetCurrentThread() {
|
||||||
return current_thread;
|
return current_thread;
|
||||||
@ -121,6 +127,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
|
|||||||
}
|
}
|
||||||
t->wait_type = WAITTYPE_NONE;
|
t->wait_type = WAITTYPE_NONE;
|
||||||
t->wait_handle = 0;
|
t->wait_handle = 0;
|
||||||
|
t->wait_address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change a thread to "ready" state
|
/// Change a thread to "ready" state
|
||||||
@ -141,11 +148,17 @@ void ChangeReadyState(Thread* t, bool ready) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that a thread has not been released from waiting
|
/// Verify that a thread has not been released from waiting
|
||||||
inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
|
static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
|
||||||
_dbg_assert_(KERNEL, thread != nullptr);
|
_dbg_assert_(KERNEL, thread != nullptr);
|
||||||
return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
|
return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify that a thread has not been released from waiting (with wait address)
|
||||||
|
static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
|
||||||
|
_dbg_assert_(KERNEL, thread != nullptr);
|
||||||
|
return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address);
|
||||||
|
}
|
||||||
|
|
||||||
/// Stops the current thread
|
/// Stops the current thread
|
||||||
ResultCode StopThread(Handle handle, const char* reason) {
|
ResultCode StopThread(Handle handle, const char* reason) {
|
||||||
Thread* thread = g_object_pool.Get<Thread>(handle);
|
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||||
@ -164,6 +177,7 @@ ResultCode StopThread(Handle handle, const char* reason) {
|
|||||||
// Stopped threads are never waiting.
|
// Stopped threads are never waiting.
|
||||||
thread->wait_type = WAITTYPE_NONE;
|
thread->wait_type = WAITTYPE_NONE;
|
||||||
thread->wait_handle = 0;
|
thread->wait_handle = 0;
|
||||||
|
thread->wait_address = 0;
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -192,12 +206,12 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
|
|||||||
for (Handle handle : thread_queue) {
|
for (Handle handle : thread_queue) {
|
||||||
Thread* thread = g_object_pool.Get<Thread>(handle);
|
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||||
|
|
||||||
// TODO(bunnei): Verify arbiter address...
|
if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
|
||||||
if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
|
continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
|
||||||
|
|
||||||
if(thread->current_priority <= priority) {
|
if(thread->current_priority <= priority) {
|
||||||
highest_priority_thread = handle;
|
highest_priority_thread = handle;
|
||||||
priority = thread->current_priority;
|
priority = thread->current_priority;
|
||||||
@ -217,8 +231,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
|
|||||||
for (Handle handle : thread_queue) {
|
for (Handle handle : thread_queue) {
|
||||||
Thread* thread = g_object_pool.Get<Thread>(handle);
|
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||||
|
|
||||||
// TODO(bunnei): Verify arbiter address...
|
if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
|
||||||
if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
|
|
||||||
ResumeThreadFromWait(handle);
|
ResumeThreadFromWait(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,11 +285,6 @@ Thread* NextThread() {
|
|||||||
return Kernel::g_object_pool.Get<Thread>(next);
|
return Kernel::g_object_pool.Get<Thread>(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts the current thread in the wait state for the given type
|
|
||||||
* @param wait_type Type of wait
|
|
||||||
* @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
|
|
||||||
*/
|
|
||||||
void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
|
void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
|
||||||
Thread* thread = GetCurrentThread();
|
Thread* thread = GetCurrentThread();
|
||||||
thread->wait_type = wait_type;
|
thread->wait_type = wait_type;
|
||||||
@ -284,6 +292,11 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
|
|||||||
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
|
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) {
|
||||||
|
WaitCurrentThread(wait_type, wait_handle);
|
||||||
|
GetCurrentThread()->wait_address = wait_address;
|
||||||
|
}
|
||||||
|
|
||||||
/// Resumes a thread from waiting by marking it as "ready"
|
/// Resumes a thread from waiting by marking it as "ready"
|
||||||
void ResumeThreadFromWait(Handle handle) {
|
void ResumeThreadFromWait(Handle handle) {
|
||||||
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
|
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
|
||||||
@ -325,6 +338,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
|
|||||||
thread_queue.push_back(handle);
|
thread_queue.push_back(handle);
|
||||||
thread_ready_queue.prepare(priority);
|
thread_ready_queue.prepare(priority);
|
||||||
|
|
||||||
|
thread->thread_id = next_thread_id++;
|
||||||
thread->status = THREADSTATUS_DORMANT;
|
thread->status = THREADSTATUS_DORMANT;
|
||||||
thread->entry_point = entry_point;
|
thread->entry_point = entry_point;
|
||||||
thread->stack_top = stack_top;
|
thread->stack_top = stack_top;
|
||||||
@ -333,6 +347,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
|
|||||||
thread->processor_id = processor_id;
|
thread->processor_id = processor_id;
|
||||||
thread->wait_type = WAITTYPE_NONE;
|
thread->wait_type = WAITTYPE_NONE;
|
||||||
thread->wait_handle = 0;
|
thread->wait_handle = 0;
|
||||||
|
thread->wait_address = 0;
|
||||||
thread->name = name;
|
thread->name = name;
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
@ -465,9 +480,21 @@ void Reschedule() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
||||||
|
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||||
|
if (thread == nullptr)
|
||||||
|
return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS,
|
||||||
|
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||||
|
|
||||||
|
*thread_id = thread->thread_id;
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ThreadingInit() {
|
void ThreadingInit() {
|
||||||
|
next_thread_id = INITIAL_THREAD_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadingShutdown() {
|
void ThreadingShutdown() {
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
#include "core/mem_map.h"
|
||||||
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
@ -58,6 +61,14 @@ void Reschedule();
|
|||||||
/// Stops the current thread
|
/// Stops the current thread
|
||||||
ResultCode StopThread(Handle thread, const char* reason);
|
ResultCode StopThread(Handle thread, const char* reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the ID of the specified thread handle
|
||||||
|
* @param thread_id Will contain the output thread id
|
||||||
|
* @param handle Handle to the thread we want
|
||||||
|
* @return Whether the function was successful or not
|
||||||
|
*/
|
||||||
|
ResultCode GetThreadId(u32* thread_id, Handle handle);
|
||||||
|
|
||||||
/// Resumes a thread from waiting by marking it as "ready"
|
/// Resumes a thread from waiting by marking it as "ready"
|
||||||
void ResumeThreadFromWait(Handle handle);
|
void ResumeThreadFromWait(Handle handle);
|
||||||
|
|
||||||
@ -77,6 +88,14 @@ Handle GetCurrentThreadHandle();
|
|||||||
*/
|
*/
|
||||||
void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
|
void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the current thread in the wait state for the given type
|
||||||
|
* @param wait_type Type of wait
|
||||||
|
* @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
|
||||||
|
* @param wait_address Arbitration address used to resume from wait
|
||||||
|
*/
|
||||||
|
void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address);
|
||||||
|
|
||||||
/// Put current thread in a wait state - on WaitSynchronization
|
/// Put current thread in a wait state - on WaitSynchronization
|
||||||
void WaitThread_Synchronization();
|
void WaitThread_Synchronization();
|
||||||
|
|
||||||
|
@ -11,6 +11,24 @@
|
|||||||
|
|
||||||
namespace AC_U {
|
namespace AC_U {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AC_U::GetWifiStatus service function
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet.
|
||||||
|
*/
|
||||||
|
void GetWifiStatus(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(purpasmart96): This function is only a stub,
|
||||||
|
// it returns a valid result without implementing full functionality.
|
||||||
|
|
||||||
|
cmd_buff[1] = 0; // No error
|
||||||
|
cmd_buff[2] = 0; // Connection type set to none
|
||||||
|
|
||||||
|
WARN_LOG(KERNEL, "(STUBBED) called");
|
||||||
|
}
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00010000, nullptr, "CreateDefaultConfig"},
|
{0x00010000, nullptr, "CreateDefaultConfig"},
|
||||||
{0x00040006, nullptr, "ConnectAsync"},
|
{0x00040006, nullptr, "ConnectAsync"},
|
||||||
@ -18,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x00080004, nullptr, "CloseAsync"},
|
{0x00080004, nullptr, "CloseAsync"},
|
||||||
{0x00090002, nullptr, "GetCloseResult"},
|
{0x00090002, nullptr, "GetCloseResult"},
|
||||||
{0x000A0000, nullptr, "GetLastErrorCode"},
|
{0x000A0000, nullptr, "GetLastErrorCode"},
|
||||||
{0x000D0000, nullptr, "GetWifiStatus"},
|
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
|
||||||
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
||||||
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
||||||
{0x00110042, nullptr, "GetNZoneApNumService"},
|
{0x00110042, nullptr, "GetNZoneApNumService"},
|
||||||
|
@ -15,6 +15,25 @@ namespace DSP_DSP {
|
|||||||
static Handle semaphore_event;
|
static Handle semaphore_event;
|
||||||
static Handle interrupt_event;
|
static Handle interrupt_event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DSP_DSP::ConvertProcessAddressFromDspDram service function
|
||||||
|
* Inputs:
|
||||||
|
* 1 : Address
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : (inaddr << 1) + 0x1FF40000 (where 0x1FF00000 is the DSP RAM address)
|
||||||
|
*/
|
||||||
|
void ConvertProcessAddressFromDspDram(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
u32 addr = cmd_buff[1];
|
||||||
|
|
||||||
|
cmd_buff[1] = 0; // No error
|
||||||
|
cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000);
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "(STUBBED) called with address %u", addr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DSP_DSP::LoadComponent service function
|
* DSP_DSP::LoadComponent service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
@ -90,31 +109,31 @@ void WriteReg0x10(Service::Interface* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00010040, nullptr, "RecvData"},
|
{0x00010040, nullptr, "RecvData"},
|
||||||
{0x00020040, nullptr, "RecvDataIsReady"},
|
{0x00020040, nullptr, "RecvDataIsReady"},
|
||||||
{0x00030080, nullptr, "SendData"},
|
{0x00030080, nullptr, "SendData"},
|
||||||
{0x00040040, nullptr, "SendDataIsEmpty"},
|
{0x00040040, nullptr, "SendDataIsEmpty"},
|
||||||
{0x00070040, WriteReg0x10, "WriteReg0x10"},
|
{0x00070040, WriteReg0x10, "WriteReg0x10"},
|
||||||
{0x00080000, nullptr, "GetSemaphore"},
|
{0x00080000, nullptr, "GetSemaphore"},
|
||||||
{0x00090040, nullptr, "ClearSemaphore"},
|
{0x00090040, nullptr, "ClearSemaphore"},
|
||||||
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
|
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
|
||||||
{0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"},
|
{0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
|
||||||
{0x000D0082, nullptr, "WriteProcessPipe"},
|
{0x000D0082, nullptr, "WriteProcessPipe"},
|
||||||
{0x001000C0, nullptr, "ReadPipeIfPossible"},
|
{0x001000C0, nullptr, "ReadPipeIfPossible"},
|
||||||
{0x001100C2, LoadComponent, "LoadComponent"},
|
{0x001100C2, LoadComponent, "LoadComponent"},
|
||||||
{0x00120000, nullptr, "UnloadComponent"},
|
{0x00120000, nullptr, "UnloadComponent"},
|
||||||
{0x00130082, nullptr, "FlushDataCache"},
|
{0x00130082, nullptr, "FlushDataCache"},
|
||||||
{0x00140082, nullptr, "InvalidateDCache"},
|
{0x00140082, nullptr, "InvalidateDCache"},
|
||||||
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
|
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
|
||||||
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
|
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
|
||||||
{0x00170040, nullptr, "SetSemaphoreMask"},
|
{0x00170040, nullptr, "SetSemaphoreMask"},
|
||||||
{0x00180040, nullptr, "GetPhysicalAddress"},
|
{0x00180040, nullptr, "GetPhysicalAddress"},
|
||||||
{0x00190040, nullptr, "GetVirtualAddress"},
|
{0x00190040, nullptr, "GetVirtualAddress"},
|
||||||
{0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
|
{0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
|
||||||
{0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
|
{0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
|
||||||
{0x001C0082, nullptr, "SetIirFilterEQ"},
|
{0x001C0082, nullptr, "SetIirFilterEQ"},
|
||||||
{0x001F0000, nullptr, "GetHeadphoneStatus"},
|
{0x001F0000, nullptr, "GetHeadphoneStatus"},
|
||||||
{0x00210000, nullptr, "GetIsDspOccupied"},
|
{0x00210000, nullptr, "GetIsDspOccupied"},
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -159,7 +159,49 @@ void DeleteFile(Service::Interface* self) {
|
|||||||
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
|
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
|
||||||
filename_type, filename_size, file_path.DebugStr().c_str());
|
filename_type, filename_size, file_path.DebugStr().c_str());
|
||||||
|
|
||||||
cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path);
|
cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw;
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FS_User::RenameFile service function
|
||||||
|
* Inputs:
|
||||||
|
* 2 : Source archive handle lower word
|
||||||
|
* 3 : Source archive handle upper word
|
||||||
|
* 4 : Source file path type
|
||||||
|
* 5 : Source file path size
|
||||||
|
* 6 : Dest archive handle lower word
|
||||||
|
* 7 : Dest archive handle upper word
|
||||||
|
* 8 : Dest file path type
|
||||||
|
* 9 : Dest file path size
|
||||||
|
* 11: Source file path string data
|
||||||
|
* 13: Dest file path string
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
*/
|
||||||
|
void RenameFile(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to
|
||||||
|
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
|
||||||
|
Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]);
|
||||||
|
auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||||
|
u32 src_filename_size = cmd_buff[5];
|
||||||
|
Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]);
|
||||||
|
auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||||
|
u32 dest_filename_size = cmd_buff[9];
|
||||||
|
u32 src_filename_ptr = cmd_buff[11];
|
||||||
|
u32 dest_filename_ptr = cmd_buff[13];
|
||||||
|
|
||||||
|
FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr);
|
||||||
|
FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr);
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||||
|
src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(),
|
||||||
|
dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str());
|
||||||
|
|
||||||
|
cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw;
|
||||||
|
|
||||||
DEBUG_LOG(KERNEL, "called");
|
DEBUG_LOG(KERNEL, "called");
|
||||||
}
|
}
|
||||||
@ -190,7 +232,7 @@ void DeleteDirectory(Service::Interface* self) {
|
|||||||
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
|
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
|
||||||
dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
||||||
|
|
||||||
cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path);
|
cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
|
||||||
|
|
||||||
DEBUG_LOG(KERNEL, "called");
|
DEBUG_LOG(KERNEL, "called");
|
||||||
}
|
}
|
||||||
@ -220,11 +262,53 @@ static void CreateDirectory(Service::Interface* self) {
|
|||||||
|
|
||||||
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
||||||
|
|
||||||
cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path);
|
cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw;
|
||||||
|
|
||||||
DEBUG_LOG(KERNEL, "called");
|
DEBUG_LOG(KERNEL, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FS_User::RenameDirectory service function
|
||||||
|
* Inputs:
|
||||||
|
* 2 : Source archive handle lower word
|
||||||
|
* 3 : Source archive handle upper word
|
||||||
|
* 4 : Source dir path type
|
||||||
|
* 5 : Source dir path size
|
||||||
|
* 6 : Dest archive handle lower word
|
||||||
|
* 7 : Dest archive handle upper word
|
||||||
|
* 8 : Dest dir path type
|
||||||
|
* 9 : Dest dir path size
|
||||||
|
* 11: Source dir path string data
|
||||||
|
* 13: Dest dir path string
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
*/
|
||||||
|
void RenameDirectory(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to
|
||||||
|
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
|
||||||
|
Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]);
|
||||||
|
auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||||
|
u32 src_dirname_size = cmd_buff[5];
|
||||||
|
Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]);
|
||||||
|
auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||||
|
u32 dest_dirname_size = cmd_buff[9];
|
||||||
|
u32 src_dirname_ptr = cmd_buff[11];
|
||||||
|
u32 dest_dirname_ptr = cmd_buff[13];
|
||||||
|
|
||||||
|
FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr);
|
||||||
|
FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr);
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||||
|
src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(),
|
||||||
|
dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str());
|
||||||
|
|
||||||
|
cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw;
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "called");
|
||||||
|
}
|
||||||
|
|
||||||
static void OpenDirectory(Service::Interface* self) {
|
static void OpenDirectory(Service::Interface* self) {
|
||||||
u32* cmd_buff = Service::GetCommandBuffer();
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
@ -314,12 +398,12 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
{0x080201C2, OpenFile, "OpenFile"},
|
{0x080201C2, OpenFile, "OpenFile"},
|
||||||
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
|
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
|
||||||
{0x08040142, DeleteFile, "DeleteFile"},
|
{0x08040142, DeleteFile, "DeleteFile"},
|
||||||
{0x08050244, nullptr, "RenameFile"},
|
{0x08050244, RenameFile, "RenameFile"},
|
||||||
{0x08060142, DeleteDirectory, "DeleteDirectory"},
|
{0x08060142, DeleteDirectory, "DeleteDirectory"},
|
||||||
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
|
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
|
||||||
{0x08080202, nullptr, "CreateFile"},
|
{0x08080202, nullptr, "CreateFile"},
|
||||||
{0x08090182, CreateDirectory, "CreateDirectory"},
|
{0x08090182, CreateDirectory, "CreateDirectory"},
|
||||||
{0x080A0244, nullptr, "RenameDirectory"},
|
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
||||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||||
{0x080D0144, nullptr, "ControlArchive"},
|
{0x080D0144, nullptr, "ControlArchive"},
|
||||||
|
@ -55,7 +55,7 @@ static void UpdateNextCirclePadState() {
|
|||||||
/**
|
/**
|
||||||
* Sets a Pad state (button or button combo) as pressed
|
* Sets a Pad state (button or button combo) as pressed
|
||||||
*/
|
*/
|
||||||
void PadButtonPress(PadState pad_state) {
|
void PadButtonPress(const PadState& pad_state) {
|
||||||
next_state.hex |= pad_state.hex;
|
next_state.hex |= pad_state.hex;
|
||||||
UpdateNextCirclePadState();
|
UpdateNextCirclePadState();
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ void PadButtonPress(PadState pad_state) {
|
|||||||
/**
|
/**
|
||||||
* Sets a Pad state (button or button combo) as released
|
* Sets a Pad state (button or button combo) as released
|
||||||
*/
|
*/
|
||||||
void PadButtonRelease(PadState pad_state) {
|
void PadButtonRelease(const PadState& pad_state) {
|
||||||
next_state.hex &= ~pad_state.hex;
|
next_state.hex &= ~pad_state.hex;
|
||||||
UpdateNextCirclePadState();
|
UpdateNextCirclePadState();
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,8 @@ const PadState PAD_CIRCLE_UP = {{1u << 30}};
|
|||||||
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
|
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
|
||||||
|
|
||||||
// Methods for updating the HID module's state
|
// Methods for updating the HID module's state
|
||||||
void PadButtonPress(PadState pad_state);
|
void PadButtonPress(const PadState& pad_state);
|
||||||
void PadButtonRelease(PadState pad_state);
|
void PadButtonRelease(const PadState& pad_state);
|
||||||
void PadUpdateComplete();
|
void PadUpdateComplete();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,15 +11,101 @@
|
|||||||
|
|
||||||
namespace PTM_U {
|
namespace PTM_U {
|
||||||
|
|
||||||
|
/// Charge levels used by PTM functions
|
||||||
|
enum class ChargeLevels : u32 {
|
||||||
|
CriticalBattery = 1,
|
||||||
|
LowBattery = 2,
|
||||||
|
HalfFull = 3,
|
||||||
|
MostlyFull = 4,
|
||||||
|
CompletelyFull = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool shell_open = true;
|
||||||
|
|
||||||
|
static bool battery_is_charging = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is unknown if GetAdapterState is the same as GetBatteryChargeState,
|
||||||
|
* it is likely to just be a duplicate function of GetBatteryChargeState
|
||||||
|
* that controls another part of the HW.
|
||||||
|
* PTM_U::GetAdapterState service function
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : Output of function, 0 = not charging, 1 = charging.
|
||||||
|
*/
|
||||||
|
static void GetAdapterState(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(purpasmart96): This function is only a stub,
|
||||||
|
// it returns a valid result without implementing full functionality.
|
||||||
|
|
||||||
|
cmd_buff[1] = 0; // No error
|
||||||
|
cmd_buff[2] = battery_is_charging ? 1 : 0;
|
||||||
|
|
||||||
|
WARN_LOG(KERNEL, "(STUBBED) called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PTM_User::GetShellState service function.
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
|
||||||
|
*/
|
||||||
|
static void GetShellState(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
cmd_buff[1] = 0;
|
||||||
|
cmd_buff[2] = shell_open ? 1 : 0;
|
||||||
|
|
||||||
|
DEBUG_LOG(KERNEL, "PTM_U::GetShellState called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PTM_U::GetBatteryLevel service function
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
|
||||||
|
* 3 = half full battery, 2 = low battery, 1 = critical battery.
|
||||||
|
*/
|
||||||
|
static void GetBatteryLevel(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(purpasmart96): This function is only a stub,
|
||||||
|
// it returns a valid result without implementing full functionality.
|
||||||
|
|
||||||
|
cmd_buff[1] = 0; // No error
|
||||||
|
cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery
|
||||||
|
|
||||||
|
WARN_LOG(KERNEL, "(STUBBED) called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PTM_U::GetBatteryChargeState service function
|
||||||
|
* Outputs:
|
||||||
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
|
* 2 : Output of function, 0 = not charging, 1 = charging.
|
||||||
|
*/
|
||||||
|
static void GetBatteryChargeState(Service::Interface* self) {
|
||||||
|
u32* cmd_buff = Service::GetCommandBuffer();
|
||||||
|
|
||||||
|
// TODO(purpasmart96): This function is only a stub,
|
||||||
|
// it returns a valid result without implementing full functionality.
|
||||||
|
|
||||||
|
cmd_buff[1] = 0; // No error
|
||||||
|
cmd_buff[2] = battery_is_charging ? 1 : 0;
|
||||||
|
|
||||||
|
WARN_LOG(KERNEL, "(STUBBED) called");
|
||||||
|
}
|
||||||
|
|
||||||
const Interface::FunctionInfo FunctionTable[] = {
|
const Interface::FunctionInfo FunctionTable[] = {
|
||||||
{0x00010002, nullptr, "RegisterAlarmClient"},
|
{0x00010002, nullptr, "RegisterAlarmClient"},
|
||||||
{0x00020080, nullptr, "SetRtcAlarm"},
|
{0x00020080, nullptr, "SetRtcAlarm"},
|
||||||
{0x00030000, nullptr, "GetRtcAlarm"},
|
{0x00030000, nullptr, "GetRtcAlarm"},
|
||||||
{0x00040000, nullptr, "CancelRtcAlarm"},
|
{0x00040000, nullptr, "CancelRtcAlarm"},
|
||||||
{0x00050000, nullptr, "GetAdapterState"},
|
{0x00050000, GetAdapterState, "GetAdapterState"},
|
||||||
{0x00060000, nullptr, "GetShellState"},
|
{0x00060000, GetShellState, "GetShellState"},
|
||||||
{0x00070000, nullptr, "GetBatteryLevel"},
|
{0x00070000, GetBatteryLevel, "GetBatteryLevel"},
|
||||||
{0x00080000, nullptr, "GetBatteryChargeState"},
|
{0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
|
||||||
{0x00090000, nullptr, "GetPedometerState"},
|
{0x00090000, nullptr, "GetPedometerState"},
|
||||||
{0x000A0042, nullptr, "GetStepHistoryEntry"},
|
{0x000A0042, nullptr, "GetStepHistoryEntry"},
|
||||||
{0x000B00C2, nullptr, "GetStepHistory"},
|
{0x000B00C2, nullptr, "GetStepHistory"},
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
#include "core/mem_map.h"
|
#include "core/mem_map.h"
|
||||||
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
@ -79,21 +80,20 @@ public:
|
|||||||
u32* cmd_buff = GetCommandBuffer();
|
u32* cmd_buff = GetCommandBuffer();
|
||||||
auto itr = m_functions.find(cmd_buff[0]);
|
auto itr = m_functions.find(cmd_buff[0]);
|
||||||
|
|
||||||
if (itr == m_functions.end()) {
|
if (itr == m_functions.end() || itr->second.func == nullptr) {
|
||||||
ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
|
// Number of params == bits 0-5 + bits 6-11
|
||||||
GetPortName().c_str(), cmd_buff[0]);
|
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
|
||||||
|
|
||||||
|
std::string error = "unknown/unimplemented function '%s': port=%s";
|
||||||
|
for (int i = 1; i <= num_params; ++i) {
|
||||||
|
error += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
|
||||||
|
|
||||||
|
ERROR_LOG(OSHLE, error.c_str(), name.c_str(), GetPortName().c_str());
|
||||||
|
|
||||||
// TODO(bunnei): Hack - ignore error
|
// TODO(bunnei): Hack - ignore error
|
||||||
u32* cmd_buff = Service::GetCommandBuffer();
|
|
||||||
cmd_buff[1] = 0;
|
|
||||||
return MakeResult<bool>(false);
|
|
||||||
}
|
|
||||||
if (itr->second.func == nullptr) {
|
|
||||||
ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
|
|
||||||
GetPortName().c_str(), itr->second.name.c_str());
|
|
||||||
|
|
||||||
// TODO(bunnei): Hack - ignore error
|
|
||||||
u32* cmd_buff = Service::GetCommandBuffer();
|
|
||||||
cmd_buff[1] = 0;
|
cmd_buff[1] = 0;
|
||||||
return MakeResult<bool>(false);
|
return MakeResult<bool>(false);
|
||||||
}
|
}
|
||||||
|
@ -281,10 +281,11 @@ static Result ReleaseMutex(Handle handle) {
|
|||||||
return res.raw;
|
return res.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current thread ID
|
/// Get the ID for the specified thread.
|
||||||
static Result GetThreadId(u32* thread_id, Handle thread) {
|
static Result GetThreadId(u32* thread_id, Handle handle) {
|
||||||
ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
|
DEBUG_LOG(SVC, "called thread=0x%08X", handle);
|
||||||
return 0;
|
ResultCode result = Kernel::GetThreadId(thread_id, handle);
|
||||||
|
return result.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query memory
|
/// Query memory
|
||||||
|
236
src/core/loader/3dsx.cpp
Normal file
236
src/core/loader/3dsx.cpp
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
// Copyright 2014 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/file_sys/archive_romfs.h"
|
||||||
|
#include "core/loader/elf.h"
|
||||||
|
#include "core/loader/ncch.h"
|
||||||
|
#include "core/hle/kernel/archive.h"
|
||||||
|
#include "core/mem_map.h"
|
||||||
|
|
||||||
|
#include "3dsx.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Loader {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File layout:
|
||||||
|
* - File header
|
||||||
|
* - Code, rodata and data relocation table headers
|
||||||
|
* - Code segment
|
||||||
|
* - Rodata segment
|
||||||
|
* - Loadable (non-BSS) part of the data segment
|
||||||
|
* - Code relocation table
|
||||||
|
* - Rodata relocation table
|
||||||
|
* - Data relocation table
|
||||||
|
*
|
||||||
|
* Memory layout before relocations are applied:
|
||||||
|
* [0..codeSegSize) -> code segment
|
||||||
|
* [codeSegSize..rodataSegSize) -> rodata segment
|
||||||
|
* [rodataSegSize..dataSegSize) -> data segment
|
||||||
|
*
|
||||||
|
* Memory layout after relocations are applied: well, however the loader sets it up :)
|
||||||
|
* The entrypoint is always the start of the code segment.
|
||||||
|
* The BSS section must be cleared manually by the application.
|
||||||
|
*/
|
||||||
|
enum THREEDSX_Error {
|
||||||
|
ERROR_NONE = 0,
|
||||||
|
ERROR_READ = 1,
|
||||||
|
ERROR_FILE = 2,
|
||||||
|
ERROR_ALLOC = 3
|
||||||
|
};
|
||||||
|
static const u32 RELOCBUFSIZE = 512;
|
||||||
|
|
||||||
|
// File header
|
||||||
|
static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
|
||||||
|
#pragma pack(1)
|
||||||
|
struct THREEDSX_Header
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u16 header_size, reloc_hdr_size;
|
||||||
|
u32 format_ver;
|
||||||
|
u32 flags;
|
||||||
|
|
||||||
|
// Sizes of the code, rodata and data segments +
|
||||||
|
// size of the BSS section (uninitialized latter half of the data segment)
|
||||||
|
u32 code_seg_size, rodata_seg_size, data_seg_size, bss_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
|
||||||
|
struct THREEDSX_RelocHdr
|
||||||
|
{
|
||||||
|
// # of absolute relocations (that is, fix address to post-relocation memory layout)
|
||||||
|
u32 cross_segment_absolute;
|
||||||
|
// # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
|
||||||
|
u32 cross_segment_relative;
|
||||||
|
// more?
|
||||||
|
|
||||||
|
// Relocations are written in this order:
|
||||||
|
// - Absolute relocations
|
||||||
|
// - Relative relocations
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relocation entry: from the current pointer, skip X words and patch Y words
|
||||||
|
struct THREEDSX_Reloc
|
||||||
|
{
|
||||||
|
u16 skip, patch;
|
||||||
|
};
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
struct THREEloadinfo
|
||||||
|
{
|
||||||
|
u8* seg_ptrs[3]; // code, rodata & data
|
||||||
|
u32 seg_addrs[3];
|
||||||
|
u32 seg_sizes[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
class THREEDSXReader {
|
||||||
|
public:
|
||||||
|
static int Load3DSXFile(const std::string& filename, u32 base_addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
|
||||||
|
{
|
||||||
|
if (addr < offsets[0])
|
||||||
|
return loadinfo->seg_addrs[0] + addr;
|
||||||
|
if (addr < offsets[1])
|
||||||
|
return loadinfo->seg_addrs[1] + addr - offsets[0];
|
||||||
|
return loadinfo->seg_addrs[2] + addr - offsets[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
|
||||||
|
{
|
||||||
|
FileUtil::IOFile file(filename, "rb");
|
||||||
|
if (!file.IsOpen()) {
|
||||||
|
return ERROR_FILE;
|
||||||
|
}
|
||||||
|
THREEDSX_Header hdr;
|
||||||
|
if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
|
||||||
|
return ERROR_READ;
|
||||||
|
|
||||||
|
THREEloadinfo loadinfo;
|
||||||
|
//loadinfo segments must be a multiple of 0x1000
|
||||||
|
loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF;
|
||||||
|
loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
|
||||||
|
loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
|
||||||
|
u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
|
||||||
|
u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF;
|
||||||
|
u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size;
|
||||||
|
u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
|
||||||
|
std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
|
||||||
|
|
||||||
|
loadinfo.seg_addrs[0] = base_addr;
|
||||||
|
loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
|
||||||
|
loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
|
||||||
|
loadinfo.seg_ptrs[0] = &all_mem[0];
|
||||||
|
loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
|
||||||
|
loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
|
||||||
|
|
||||||
|
// Skip header for future compatibility
|
||||||
|
file.Seek(hdr.header_size, SEEK_SET);
|
||||||
|
|
||||||
|
// Read the relocation headers
|
||||||
|
u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
|
||||||
|
|
||||||
|
for (u32 current_segment = 0; current_segment < 3; current_segment++) {
|
||||||
|
if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4)
|
||||||
|
return ERROR_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the segments
|
||||||
|
if (file.ReadBytes(loadinfo.seg_ptrs[0], hdr.code_seg_size) != hdr.code_seg_size)
|
||||||
|
return ERROR_READ;
|
||||||
|
if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size)
|
||||||
|
return ERROR_READ;
|
||||||
|
if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size)
|
||||||
|
return ERROR_READ;
|
||||||
|
|
||||||
|
// BSS clear
|
||||||
|
memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
|
||||||
|
|
||||||
|
// Relocate the segments
|
||||||
|
for (u32 current_segment = 0; current_segment < 3; current_segment++) {
|
||||||
|
for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
|
||||||
|
u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table];
|
||||||
|
if (current_segment_reloc_table >= 2) {
|
||||||
|
// We are not using this table - ignore it because we don't know what it dose
|
||||||
|
file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
|
||||||
|
|
||||||
|
u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
|
||||||
|
u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
|
||||||
|
|
||||||
|
while (n_relocs) {
|
||||||
|
u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
|
||||||
|
n_relocs -= remaining;
|
||||||
|
|
||||||
|
if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc))
|
||||||
|
return ERROR_READ;
|
||||||
|
|
||||||
|
for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
|
||||||
|
DEBUG_LOG(LOADER, "(t=%d,skip=%u,patch=%u)\n",
|
||||||
|
current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch);
|
||||||
|
pos += reloc_table[current_inprogress].skip;
|
||||||
|
s32 num_patches = reloc_table[current_inprogress].patch;
|
||||||
|
while (0 < num_patches && pos < end_pos) {
|
||||||
|
u32 in_addr = (char*)pos - (char*)&all_mem[0];
|
||||||
|
u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
|
||||||
|
DEBUG_LOG(LOADER, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
|
||||||
|
base_addr + in_addr, addr, current_segment_reloc_table, *pos);
|
||||||
|
switch (current_segment_reloc_table) {
|
||||||
|
case 0: *pos = (addr); break;
|
||||||
|
case 1: *pos = (addr - in_addr); break;
|
||||||
|
default: break; //this should never happen
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
num_patches--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the data
|
||||||
|
memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
|
||||||
|
|
||||||
|
DEBUG_LOG(LOADER, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
|
||||||
|
DEBUG_LOG(LOADER, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
|
||||||
|
DEBUG_LOG(LOADER, "DATA: %u pages\n", data_load_size / 0x1000);
|
||||||
|
DEBUG_LOG(LOADER, "BSS: %u pages\n", bss_load_size / 0x1000);
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AppLoader_DSX constructor
|
||||||
|
AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AppLoader_DSX destructor
|
||||||
|
AppLoader_THREEDSX::~AppLoader_THREEDSX() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a 3DSX file
|
||||||
|
* @return Success on success, otherwise Error
|
||||||
|
*/
|
||||||
|
ResultStatus AppLoader_THREEDSX::Load() {
|
||||||
|
INFO_LOG(LOADER, "Loading 3DSX file %s...", filename.c_str());
|
||||||
|
FileUtil::IOFile file(filename, "rb");
|
||||||
|
if (file.IsOpen()) {
|
||||||
|
|
||||||
|
THREEDSXReader reader;
|
||||||
|
reader.Load3DSXFile(filename, 0x00100000);
|
||||||
|
Kernel::LoadExec(0x00100000);
|
||||||
|
} else {
|
||||||
|
return ResultStatus::Error;
|
||||||
|
}
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Loader
|
32
src/core/loader/3dsx.h
Normal file
32
src/core/loader/3dsx.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project / Citra Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Loader namespace
|
||||||
|
|
||||||
|
namespace Loader {
|
||||||
|
|
||||||
|
/// Loads an 3DSX file
|
||||||
|
class AppLoader_THREEDSX final : public AppLoader {
|
||||||
|
public:
|
||||||
|
AppLoader_THREEDSX(const std::string& filename);
|
||||||
|
~AppLoader_THREEDSX() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the bootable file
|
||||||
|
* @return ResultStatus result of function
|
||||||
|
*/
|
||||||
|
ResultStatus Load() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string filename;
|
||||||
|
bool is_loaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Loader
|
@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/file_sys/archive_romfs.h"
|
#include "core/file_sys/archive_romfs.h"
|
||||||
|
#include "core/loader/3dsx.h"
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
#include "core/loader/ncch.h"
|
#include "core/loader/ncch.h"
|
||||||
#include "core/hle/kernel/archive.h"
|
#include "core/hle/kernel/archive.h"
|
||||||
@ -42,6 +43,8 @@ FileType IdentifyFile(const std::string &filename) {
|
|||||||
return FileType::CCI;
|
return FileType::CCI;
|
||||||
} else if (extension == ".bin") {
|
} else if (extension == ".bin") {
|
||||||
return FileType::BIN;
|
return FileType::BIN;
|
||||||
|
} else if (extension == ".3dsx") {
|
||||||
|
return FileType::THREEDSX;
|
||||||
}
|
}
|
||||||
return FileType::Unknown;
|
return FileType::Unknown;
|
||||||
}
|
}
|
||||||
@ -56,6 +59,10 @@ ResultStatus LoadFile(const std::string& filename) {
|
|||||||
|
|
||||||
switch (IdentifyFile(filename)) {
|
switch (IdentifyFile(filename)) {
|
||||||
|
|
||||||
|
//3DSX file format...
|
||||||
|
case FileType::THREEDSX:
|
||||||
|
return AppLoader_THREEDSX(filename).Load();
|
||||||
|
|
||||||
// Standard ELF file format...
|
// Standard ELF file format...
|
||||||
case FileType::ELF:
|
case FileType::ELF:
|
||||||
return AppLoader_ELF(filename).Load();
|
return AppLoader_ELF(filename).Load();
|
||||||
|
@ -22,6 +22,7 @@ enum class FileType {
|
|||||||
CIA,
|
CIA,
|
||||||
ELF,
|
ELF,
|
||||||
BIN,
|
BIN,
|
||||||
|
THREEDSX, //3DSX
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Return type for functions in Loader namespace
|
/// Return type for functions in Loader namespace
|
||||||
|
@ -16,10 +16,9 @@ typedef u32 PAddr; ///< Represents a pointer in the physical address space.
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
enum {
|
enum : u32 {
|
||||||
BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
||||||
MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
||||||
DSP_SIZE = 0x00080000, ///< DSP memory size
|
|
||||||
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
||||||
|
|
||||||
FCRAM_SIZE = 0x08000000, ///< FCRAM size
|
FCRAM_SIZE = 0x08000000, ///< FCRAM size
|
||||||
@ -27,47 +26,42 @@ enum {
|
|||||||
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
|
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
|
||||||
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
||||||
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
|
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
|
||||||
FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask
|
|
||||||
|
|
||||||
SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
|
SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
|
||||||
SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory
|
SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory
|
||||||
SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE),
|
SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE),
|
||||||
SHARED_MEMORY_MASK = (SHARED_MEMORY_SIZE - 1),
|
|
||||||
|
DSP_MEMORY_SIZE = 0x00080000, ///< DSP memory size
|
||||||
|
DSP_MEMORY_VADDR = 0x1FF00000, ///< DSP memory virtual address
|
||||||
|
|
||||||
CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size
|
CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size
|
||||||
CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address
|
CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address
|
||||||
CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE),
|
CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE),
|
||||||
CONFIG_MEMORY_MASK = (CONFIG_MEMORY_SIZE - 1),
|
|
||||||
|
|
||||||
KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size
|
KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size
|
||||||
KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are
|
KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are
|
||||||
KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE),
|
KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE),
|
||||||
KERNEL_MEMORY_MASK = (KERNEL_MEMORY_SIZE - 1),
|
|
||||||
|
|
||||||
EXEFS_CODE_SIZE = 0x03F00000,
|
EXEFS_CODE_SIZE = 0x03F00000,
|
||||||
EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here
|
EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here
|
||||||
EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
|
EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
|
||||||
EXEFS_CODE_MASK = 0x03FFFFFF,
|
|
||||||
|
|
||||||
// Region of FCRAM used by system
|
// Region of FCRAM used by system
|
||||||
SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
|
SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
|
||||||
SYSTEM_MEMORY_VADDR = 0x04000000,
|
SYSTEM_MEMORY_VADDR = 0x04000000,
|
||||||
SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
|
SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
|
||||||
SYSTEM_MEMORY_MASK = 0x03FFFFFF,
|
|
||||||
|
|
||||||
HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
|
HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
|
||||||
//HEAP_PADDR = HEAP_GSP_SIZE,
|
//HEAP_PADDR = HEAP_GSP_SIZE,
|
||||||
//HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
|
//HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
|
||||||
HEAP_VADDR = 0x08000000,
|
HEAP_VADDR = 0x08000000,
|
||||||
HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
|
HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
|
||||||
HEAP_MASK = (HEAP_SIZE - 1),
|
|
||||||
|
|
||||||
HEAP_GSP_SIZE = 0x02000000, ///< GSP heap size... TODO: Define correctly?
|
HEAP_GSP_SIZE = 0x02000000, ///< GSP heap size... TODO: Define correctly?
|
||||||
HEAP_GSP_VADDR = 0x14000000,
|
HEAP_GSP_VADDR = 0x14000000,
|
||||||
HEAP_GSP_VADDR_END = (HEAP_GSP_VADDR + HEAP_GSP_SIZE),
|
HEAP_GSP_VADDR_END = (HEAP_GSP_VADDR + HEAP_GSP_SIZE),
|
||||||
HEAP_GSP_PADDR = 0x00000000,
|
HEAP_GSP_PADDR = 0x00000000,
|
||||||
HEAP_GSP_PADDR_END = (HEAP_GSP_PADDR + HEAP_GSP_SIZE),
|
HEAP_GSP_PADDR_END = (HEAP_GSP_PADDR + HEAP_GSP_SIZE),
|
||||||
HEAP_GSP_MASK = (HEAP_GSP_SIZE - 1),
|
|
||||||
|
|
||||||
HARDWARE_IO_SIZE = 0x01000000,
|
HARDWARE_IO_SIZE = 0x01000000,
|
||||||
HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start
|
HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start
|
||||||
@ -80,12 +74,10 @@ enum {
|
|||||||
VRAM_VADDR = 0x1F000000,
|
VRAM_VADDR = 0x1F000000,
|
||||||
VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
|
VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
|
||||||
VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE),
|
VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE),
|
||||||
VRAM_MASK = 0x007FFFFF,
|
|
||||||
|
|
||||||
SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
|
SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
|
||||||
SCRATCHPAD_VADDR_END = 0x10000000,
|
SCRATCHPAD_VADDR_END = 0x10000000,
|
||||||
SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
|
SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
|
||||||
SCRATCHPAD_MASK = (SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -56,7 +56,7 @@ inline void Read(T &var, const VAddr vaddr) {
|
|||||||
|
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]);
|
var = *((const T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR]);
|
||||||
|
|
||||||
// Hardware I/O register reads
|
// Hardware I/O register reads
|
||||||
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
||||||
@ -65,23 +65,23 @@ inline void Read(T &var, const VAddr vaddr) {
|
|||||||
|
|
||||||
// ExeFS:/.code is loaded here
|
// ExeFS:/.code is loaded here
|
||||||
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
||||||
var = *((const T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK]);
|
var = *((const T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR]);
|
||||||
|
|
||||||
// FCRAM - GSP heap
|
// FCRAM - GSP heap
|
||||||
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||||
var = *((const T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK]);
|
var = *((const T*)&g_heap_gsp[vaddr - HEAP_GSP_VADDR]);
|
||||||
|
|
||||||
// FCRAM - application heap
|
// FCRAM - application heap
|
||||||
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||||
var = *((const T*)&g_heap[vaddr & HEAP_MASK]);
|
var = *((const T*)&g_heap[vaddr - HEAP_VADDR]);
|
||||||
|
|
||||||
// Shared memory
|
// Shared memory
|
||||||
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
||||||
var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]);
|
var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]);
|
||||||
|
|
||||||
// System memory
|
// System memory
|
||||||
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
||||||
var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]);
|
var = *((const T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR]);
|
||||||
|
|
||||||
// Config memory
|
// Config memory
|
||||||
} else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
|
||||||
@ -89,7 +89,7 @@ inline void Read(T &var, const VAddr vaddr) {
|
|||||||
|
|
||||||
// VRAM
|
// VRAM
|
||||||
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
||||||
var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
|
var = *((const T*)&g_vram[vaddr - VRAM_VADDR]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
|
ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
|
||||||
@ -101,7 +101,7 @@ inline void Write(const VAddr vaddr, const T data) {
|
|||||||
|
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
*(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data;
|
*(T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR] = data;
|
||||||
|
|
||||||
// Hardware I/O register writes
|
// Hardware I/O register writes
|
||||||
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
||||||
@ -110,27 +110,27 @@ inline void Write(const VAddr vaddr, const T data) {
|
|||||||
|
|
||||||
// ExeFS:/.code is loaded here
|
// ExeFS:/.code is loaded here
|
||||||
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
||||||
*(T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK] = data;
|
*(T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR] = data;
|
||||||
|
|
||||||
// FCRAM - GSP heap
|
// FCRAM - GSP heap
|
||||||
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||||
*(T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK] = data;
|
*(T*)&g_heap_gsp[vaddr - HEAP_GSP_VADDR] = data;
|
||||||
|
|
||||||
// FCRAM - application heap
|
// FCRAM - application heap
|
||||||
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||||
*(T*)&g_heap[vaddr & HEAP_MASK] = data;
|
*(T*)&g_heap[vaddr - HEAP_VADDR] = data;
|
||||||
|
|
||||||
// Shared memory
|
// Shared memory
|
||||||
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
||||||
*(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data;
|
*(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data;
|
||||||
|
|
||||||
// System memory
|
// System memory
|
||||||
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
||||||
*(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data;
|
*(T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR] = data;
|
||||||
|
|
||||||
// VRAM
|
// VRAM
|
||||||
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
||||||
*(T*)&g_vram[vaddr & VRAM_MASK] = data;
|
*(T*)&g_vram[vaddr - VRAM_VADDR] = data;
|
||||||
|
|
||||||
//} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
|
//} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
|
||||||
// _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
|
// _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
|
||||||
@ -148,31 +148,31 @@ inline void Write(const VAddr vaddr, const T data) {
|
|||||||
u8 *GetPointer(const VAddr vaddr) {
|
u8 *GetPointer(const VAddr vaddr) {
|
||||||
// Kernel memory command buffer
|
// Kernel memory command buffer
|
||||||
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
|
||||||
return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK);
|
return g_kernel_mem + (vaddr - KERNEL_MEMORY_VADDR);
|
||||||
|
|
||||||
// ExeFS:/.code is loaded here
|
// ExeFS:/.code is loaded here
|
||||||
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
|
||||||
return g_exefs_code + (vaddr & EXEFS_CODE_MASK);
|
return g_exefs_code + (vaddr - EXEFS_CODE_VADDR);
|
||||||
|
|
||||||
// FCRAM - GSP heap
|
// FCRAM - GSP heap
|
||||||
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||||
return g_heap_gsp + (vaddr & HEAP_GSP_MASK);
|
return g_heap_gsp + (vaddr - HEAP_GSP_VADDR);
|
||||||
|
|
||||||
// FCRAM - application heap
|
// FCRAM - application heap
|
||||||
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||||
return g_heap + (vaddr & HEAP_MASK);
|
return g_heap + (vaddr - HEAP_VADDR);
|
||||||
|
|
||||||
// Shared memory
|
// Shared memory
|
||||||
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
|
||||||
return g_shared_mem + (vaddr & SHARED_MEMORY_MASK);
|
return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR);
|
||||||
|
|
||||||
// System memory
|
// System memory
|
||||||
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
|
||||||
return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK);
|
return g_system_mem + (vaddr - SYSTEM_MEMORY_VADDR);
|
||||||
|
|
||||||
// VRAM
|
// VRAM
|
||||||
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
|
||||||
return g_vram + (vaddr & VRAM_MASK);
|
return g_vram + (vaddr - VRAM_VADDR);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(MEMMAP, "unknown GetPointer @ 0x%08x", vaddr);
|
ERROR_LOG(MEMMAP, "unknown GetPointer @ 0x%08x", vaddr);
|
||||||
|
@ -60,7 +60,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
const u8* load_address = base_address + loader_config.data_offset;
|
const u8* load_address = base_address + loader_config.data_offset;
|
||||||
|
|
||||||
// TODO: What happens if a loader overwrites a previous one's data?
|
// TODO: What happens if a loader overwrites a previous one's data?
|
||||||
for (int component = 0; component < loader_config.component_count; ++component) {
|
for (unsigned component = 0; component < loader_config.component_count; ++component) {
|
||||||
u32 attribute_index = loader_config.GetComponent(component);
|
u32 attribute_index = loader_config.GetComponent(component);
|
||||||
vertex_attribute_sources[attribute_index] = load_address;
|
vertex_attribute_sources[attribute_index] = load_address;
|
||||||
vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
|
vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
|
||||||
|
@ -155,7 +155,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
|
|||||||
|
|
||||||
// This is put into a try-catch block to make sure we notice unknown configurations.
|
// This is put into a try-catch block to make sure we notice unknown configurations.
|
||||||
std::vector<OutputRegisterInfo> output_info_table;
|
std::vector<OutputRegisterInfo> output_info_table;
|
||||||
for (int i = 0; i < 7; ++i) {
|
for (unsigned i = 0; i < 7; ++i) {
|
||||||
using OutputAttributes = Pica::Regs::VSOutputAttributes;
|
using OutputAttributes = Pica::Regs::VSOutputAttributes;
|
||||||
|
|
||||||
// TODO: It's still unclear how the attribute components map to the register!
|
// TODO: It's still unclear how the attribute components map to the register!
|
||||||
@ -375,8 +375,8 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
|||||||
png_write_info(png_ptr, info_ptr);
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
buf = new u8[row_stride * texture_config.height];
|
buf = new u8[row_stride * texture_config.height];
|
||||||
for (int y = 0; y < texture_config.height; ++y) {
|
for (unsigned y = 0; y < texture_config.height; ++y) {
|
||||||
for (int x = 0; x < texture_config.width; ++x) {
|
for (unsigned x = 0; x < texture_config.width; ++x) {
|
||||||
// Cf. rasterizer code for an explanation of this algorithm.
|
// Cf. rasterizer code for an explanation of this algorithm.
|
||||||
int texel_index_within_tile = 0;
|
int texel_index_within_tile = 0;
|
||||||
for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
|
for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
|
||||||
@ -402,7 +402,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write image data
|
// Write image data
|
||||||
for (auto y = 0; y < texture_config.height; ++y)
|
for (unsigned y = 0; y < texture_config.height; ++y)
|
||||||
{
|
{
|
||||||
u8* row_ptr = (u8*)buf + y * row_stride;
|
u8* row_ptr = (u8*)buf + y * row_stride;
|
||||||
u8* ptr = row_ptr;
|
u8* ptr = row_ptr;
|
||||||
|
@ -22,7 +22,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
|||||||
// Compile Vertex Shader
|
// Compile Vertex Shader
|
||||||
DEBUG_LOG(GPU, "Compiling vertex shader.");
|
DEBUG_LOG(GPU, "Compiling vertex shader.");
|
||||||
|
|
||||||
glShaderSource(vertex_shader_id, 1, &vertex_shader, NULL);
|
glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr);
|
||||||
glCompileShader(vertex_shader_id);
|
glCompileShader(vertex_shader_id);
|
||||||
|
|
||||||
// Check Vertex Shader
|
// Check Vertex Shader
|
||||||
@ -31,14 +31,14 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
|||||||
|
|
||||||
if (info_log_length > 1) {
|
if (info_log_length > 1) {
|
||||||
std::vector<char> vertex_shader_error(info_log_length);
|
std::vector<char> vertex_shader_error(info_log_length);
|
||||||
glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
|
glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
|
||||||
DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]);
|
DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile Fragment Shader
|
// Compile Fragment Shader
|
||||||
DEBUG_LOG(GPU, "Compiling fragment shader.");
|
DEBUG_LOG(GPU, "Compiling fragment shader.");
|
||||||
|
|
||||||
glShaderSource(fragment_shader_id, 1, &fragment_shader, NULL);
|
glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr);
|
||||||
glCompileShader(fragment_shader_id);
|
glCompileShader(fragment_shader_id);
|
||||||
|
|
||||||
// Check Fragment Shader
|
// Check Fragment Shader
|
||||||
@ -47,7 +47,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
|||||||
|
|
||||||
if (info_log_length > 1) {
|
if (info_log_length > 1) {
|
||||||
std::vector<char> fragment_shader_error(info_log_length);
|
std::vector<char> fragment_shader_error(info_log_length);
|
||||||
glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
|
glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, &fragment_shader_error[0]);
|
||||||
DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]);
|
DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
|||||||
|
|
||||||
if (info_log_length > 1) {
|
if (info_log_length > 1) {
|
||||||
std::vector<char> program_error(info_log_length);
|
std::vector<char> program_error(info_log_length);
|
||||||
glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
|
glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
|
||||||
DEBUG_LOG(GPU, "%s", &program_error[0]);
|
DEBUG_LOG(GPU, "%s", &program_error[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
for(int i : {0, 1}) {
|
for(int i : {0, 1}) {
|
||||||
const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
|
const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
|
||||||
|
|
||||||
if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) {
|
if (textures[i].width != (GLsizei)framebuffer.width || textures[i].height != (GLsizei)framebuffer.height) {
|
||||||
// Reallocate texture if the framebuffer size has changed.
|
// Reallocate texture if the framebuffer size has changed.
|
||||||
// This is expected to not happen very often and hence should not be a
|
// This is expected to not happen very often and hence should not be a
|
||||||
// performance problem.
|
// performance problem.
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
EmuWindow* g_emu_window = NULL; ///< Frontend emulator window
|
EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window
|
||||||
RendererBase* g_renderer = NULL; ///< Renderer plugin
|
RendererBase* g_renderer = nullptr; ///< Renderer plugin
|
||||||
int g_current_frame = 0;
|
int g_current_frame = 0;
|
||||||
|
|
||||||
/// Initialize the video core
|
/// Initialize the video core
|
||||||
|
Loading…
Reference in New Issue
Block a user