diff options
| author | 2014-06-14 12:13:16 -0400 | |
|---|---|---|
| committer | 2014-06-14 12:13:16 -0400 | |
| commit | 004df767953a949817da89bddcd5d1379240f769 (patch) | |
| tree | b2d54928dcbf3cb4dde0cd5d3277afe7999b7bd9 /src | |
| parent | GPU debugger: Const correctness and build fix. (diff) | |
| parent | Kernel: Removed unnecessary "#pragma once". (diff) | |
| download | yuzu-004df767953a949817da89bddcd5d1379240f769.tar.gz yuzu-004df767953a949817da89bddcd5d1379240f769.tar.xz yuzu-004df767953a949817da89bddcd5d1379240f769.zip | |
Merge branch 'threading' of https://github.com/bunnei/citra
Conflicts:
src/core/hle/function_wrappers.h
src/core/hle/service/gsp.cpp
Diffstat (limited to 'src')
41 files changed, 1243 insertions, 1199 deletions
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index ccc83abf2..4e8f841f4 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -48,7 +48,7 @@ void DisassemblerWidget::Init() | |||
| 48 | unsigned int curInstAddr = base_addr; | 48 | unsigned int curInstAddr = base_addr; |
| 49 | char result[255]; | 49 | char result[255]; |
| 50 | 50 | ||
| 51 | for (int i = 0; i < 10000; i++) // fixed for now | 51 | for (int i = 0; i < 20000; i++) // fixed for now |
| 52 | { | 52 | { |
| 53 | disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); | 53 | disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); |
| 54 | model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); | 54 | model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); |
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp index b5f32d1bd..db48abbf6 100644 --- a/src/common/console_listener.cpp +++ b/src/common/console_listener.cpp | |||
| @@ -259,14 +259,17 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) | |||
| 259 | 259 | ||
| 260 | switch (Level) | 260 | switch (Level) |
| 261 | { | 261 | { |
| 262 | case OS_LEVEL: // light yellow | ||
| 263 | Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; | ||
| 264 | break; | ||
| 262 | case NOTICE_LEVEL: // light green | 265 | case NOTICE_LEVEL: // light green |
| 263 | Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; | 266 | Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; |
| 264 | break; | 267 | break; |
| 265 | case ERROR_LEVEL: // light red | 268 | case ERROR_LEVEL: // light red |
| 266 | Color = FOREGROUND_RED | FOREGROUND_INTENSITY; | 269 | Color = FOREGROUND_RED | FOREGROUND_INTENSITY; |
| 267 | break; | 270 | break; |
| 268 | case WARNING_LEVEL: // light yellow | 271 | case WARNING_LEVEL: // light purple |
| 269 | Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; | 272 | Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |
| 270 | break; | 273 | break; |
| 271 | case INFO_LEVEL: // cyan | 274 | case INFO_LEVEL: // cyan |
| 272 | Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; | 275 | Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |
| @@ -278,15 +281,8 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) | |||
| 278 | Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; | 281 | Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |
| 279 | break; | 282 | break; |
| 280 | } | 283 | } |
| 281 | if (strlen(Text) > 10) | ||
| 282 | { | ||
| 283 | // First 10 chars white | ||
| 284 | SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); | ||
| 285 | WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL); | ||
| 286 | Text += 10; | ||
| 287 | } | ||
| 288 | SetConsoleTextAttribute(hConsole, Color); | 284 | SetConsoleTextAttribute(hConsole, Color); |
| 289 | WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); | 285 | printf(Text); |
| 290 | #else | 286 | #else |
| 291 | char ColorAttr[16] = ""; | 287 | char ColorAttr[16] = ""; |
| 292 | char ResetAttr[16] = ""; | 288 | char ResetAttr[16] = ""; |
diff --git a/src/common/log.h b/src/common/log.h index d0da68aad..e923224ed 100644 --- a/src/common/log.h +++ b/src/common/log.h | |||
| @@ -7,11 +7,14 @@ | |||
| 7 | 7 | ||
| 8 | #define LOGGING | 8 | #define LOGGING |
| 9 | 9 | ||
| 10 | #define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. | 10 | enum { |
| 11 | #define ERROR_LEVEL 2 // Critical errors | 11 | OS_LEVEL, // Printed by the emulated operating system |
| 12 | #define WARNING_LEVEL 3 // Something is suspicious. | 12 | NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports. |
| 13 | #define INFO_LEVEL 4 // General information. | 13 | ERROR_LEVEL, // Critical errors |
| 14 | #define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. | 14 | WARNING_LEVEL, // Something is suspicious. |
| 15 | INFO_LEVEL, // General information. | ||
| 16 | DEBUG_LEVEL, // Detailed debugging - might make things slow. | ||
| 17 | }; | ||
| 15 | 18 | ||
| 16 | namespace LogTypes | 19 | namespace LogTypes |
| 17 | { | 20 | { |
| @@ -70,6 +73,7 @@ enum LOG_TYPE { | |||
| 70 | 73 | ||
| 71 | // FIXME: should this be removed? | 74 | // FIXME: should this be removed? |
| 72 | enum LOG_LEVELS { | 75 | enum LOG_LEVELS { |
| 76 | LOS = OS_LEVEL, | ||
| 73 | LNOTICE = NOTICE_LEVEL, | 77 | LNOTICE = NOTICE_LEVEL, |
| 74 | LERROR = ERROR_LEVEL, | 78 | LERROR = ERROR_LEVEL, |
| 75 | LWARNING = WARNING_LEVEL, | 79 | LWARNING = WARNING_LEVEL, |
| @@ -82,31 +86,34 @@ enum LOG_LEVELS { | |||
| 82 | 86 | ||
| 83 | } // namespace | 87 | } // namespace |
| 84 | 88 | ||
| 85 | void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, | 89 | void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line, |
| 86 | const char *file, int line, const char *fmt, ...) | 90 | const char* function, const char* fmt, ...) |
| 87 | #ifdef __GNUC__ | 91 | #ifdef __GNUC__ |
| 88 | __attribute__((format(printf, 5, 6))) | 92 | __attribute__((format(printf, 6, 7))) |
| 89 | #endif | 93 | #endif |
| 90 | ; | 94 | ; |
| 91 | 95 | ||
| 92 | #if defined LOGGING || defined _DEBUG || defined DEBUGFAST | 96 | #if defined LOGGING || defined _DEBUG || defined DEBUGFAST |
| 93 | #define MAX_LOGLEVEL DEBUG_LEVEL | 97 | #define MAX_LOGLEVEL LDEBUG |
| 94 | #else | 98 | #else |
| 95 | #ifndef MAX_LOGLEVEL | 99 | #ifndef MAX_LOGLEVEL |
| 96 | #define MAX_LOGLEVEL WARNING_LEVEL | 100 | #define MAX_LOGLEVEL LWARNING |
| 97 | #endif // loglevel | 101 | #endif // loglevel |
| 98 | #endif // logging | 102 | #endif // logging |
| 99 | 103 | ||
| 100 | #ifdef GEKKO | 104 | #ifdef _WIN32 |
| 101 | #define GENERIC_LOG(t, v, ...) | 105 | #ifndef __func__ |
| 102 | #else | 106 | #define __func__ __FUNCTION__ |
| 107 | #endif | ||
| 108 | #endif | ||
| 109 | |||
| 103 | // Let the compiler optimize this out | 110 | // Let the compiler optimize this out |
| 104 | #define GENERIC_LOG(t, v, ...) { \ | 111 | #define GENERIC_LOG(t, v, ...) { \ |
| 105 | if (v <= MAX_LOGLEVEL) \ | 112 | if (v <= LogTypes::MAX_LOGLEVEL) \ |
| 106 | GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ | 113 | GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \ |
| 107 | } | 114 | } |
| 108 | #endif | ||
| 109 | 115 | ||
| 116 | #define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0) | ||
| 110 | #define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) | 117 | #define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) |
| 111 | #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) | 118 | #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) |
| 112 | #define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) | 119 | #define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) |
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index b4a761c75..4e1cb60bd 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp | |||
| @@ -10,14 +10,16 @@ | |||
| 10 | #include "common/thread.h" | 10 | #include "common/thread.h" |
| 11 | #include "common/file_util.h" | 11 | #include "common/file_util.h" |
| 12 | 12 | ||
| 13 | void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, | 13 | void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, |
| 14 | const char *file, int line, const char* fmt, ...) | 14 | const char* function, const char* fmt, ...) |
| 15 | { | 15 | { |
| 16 | va_list args; | 16 | va_list args; |
| 17 | va_start(args, fmt); | 17 | va_start(args, fmt); |
| 18 | if (LogManager::GetInstance()) | 18 | |
| 19 | if (LogManager::GetInstance()) { | ||
| 19 | LogManager::GetInstance()->Log(level, type, | 20 | LogManager::GetInstance()->Log(level, type, |
| 20 | file, line, fmt, args); | 21 | file, line, function, fmt, args); |
| 22 | } | ||
| 21 | va_end(args); | 23 | va_end(args); |
| 22 | } | 24 | } |
| 23 | 25 | ||
| @@ -88,6 +90,8 @@ LogManager::LogManager() | |||
| 88 | m_Log[i]->AddListener(m_debuggerLog); | 90 | m_Log[i]->AddListener(m_debuggerLog); |
| 89 | #endif | 91 | #endif |
| 90 | } | 92 | } |
| 93 | |||
| 94 | m_consoleLog->Open(); | ||
| 91 | } | 95 | } |
| 92 | 96 | ||
| 93 | LogManager::~LogManager() | 97 | LogManager::~LogManager() |
| @@ -107,8 +111,8 @@ LogManager::~LogManager() | |||
| 107 | delete m_debuggerLog; | 111 | delete m_debuggerLog; |
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, | 114 | void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, |
| 111 | const char *file, int line, const char *format, va_list args) | 115 | int line, const char* function, const char *fmt, va_list args) |
| 112 | { | 116 | { |
| 113 | char temp[MAX_MSGLEN]; | 117 | char temp[MAX_MSGLEN]; |
| 114 | char msg[MAX_MSGLEN * 2]; | 118 | char msg[MAX_MSGLEN * 2]; |
| @@ -117,17 +121,15 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, | |||
| 117 | if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) | 121 | if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) |
| 118 | return; | 122 | return; |
| 119 | 123 | ||
| 120 | CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); | 124 | CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); |
| 121 | 125 | ||
| 122 | static const char level_to_char[7] = "-NEWID"; | 126 | static const char level_to_char[7] = "ONEWID"; |
| 123 | sprintf(msg, "%s %s:%u %c[%s]: %s\n", | 127 | sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, |
| 124 | Common::Timer::GetTimeFormatted().c_str(), | 128 | level_to_char[(int)level], log->GetShortName(), function, temp); |
| 125 | file, line, level_to_char[(int)level], | 129 | |
| 126 | log->GetShortName(), temp); | ||
| 127 | #ifdef ANDROID | 130 | #ifdef ANDROID |
| 128 | Host_SysMessage(msg); | 131 | Host_SysMessage(msg); |
| 129 | #endif | 132 | #endif |
| 130 | printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this | ||
| 131 | log->Trigger(level, msg); | 133 | log->Trigger(level, msg); |
| 132 | } | 134 | } |
| 133 | 135 | ||
| @@ -147,7 +149,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena | |||
| 147 | { | 149 | { |
| 148 | strncpy(m_fullName, fullName, 128); | 150 | strncpy(m_fullName, fullName, 128); |
| 149 | strncpy(m_shortName, shortName, 32); | 151 | strncpy(m_shortName, shortName, 32); |
| 150 | m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; | 152 | m_level = LogTypes::MAX_LOGLEVEL; |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 153 | // LogContainer | 155 | // LogContainer |
diff --git a/src/common/log_manager.h b/src/common/log_manager.h index 580860b4d..6d3d7c7ff 100644 --- a/src/common/log_manager.h +++ b/src/common/log_manager.h | |||
| @@ -97,10 +97,10 @@ private: | |||
| 97 | ~LogManager(); | 97 | ~LogManager(); |
| 98 | public: | 98 | public: |
| 99 | 99 | ||
| 100 | static u32 GetMaxLevel() { return MAX_LOGLEVEL; } | 100 | static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; } |
| 101 | 101 | ||
| 102 | void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, | 102 | void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, |
| 103 | const char *file, int line, const char *fmt, va_list args); | 103 | const char* function, const char *fmt, va_list args); |
| 104 | 104 | ||
| 105 | void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) | 105 | void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) |
| 106 | { | 106 | { |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1c1a2eeb3..7116b88e9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -34,12 +34,14 @@ set(SRCS core.cpp | |||
| 34 | hle/config_mem.cpp | 34 | hle/config_mem.cpp |
| 35 | hle/coprocessor.cpp | 35 | hle/coprocessor.cpp |
| 36 | hle/svc.cpp | 36 | hle/svc.cpp |
| 37 | hle/kernel/event.cpp | ||
| 37 | hle/kernel/kernel.cpp | 38 | hle/kernel/kernel.cpp |
| 38 | hle/kernel/mutex.cpp | 39 | hle/kernel/mutex.cpp |
| 39 | hle/kernel/thread.cpp | 40 | hle/kernel/thread.cpp |
| 40 | hle/service/apt.cpp | 41 | hle/service/apt.cpp |
| 41 | hle/service/gsp.cpp | 42 | hle/service/gsp.cpp |
| 42 | hle/service/hid.cpp | 43 | hle/service/hid.cpp |
| 44 | hle/service/ndm.cpp | ||
| 43 | hle/service/service.cpp | 45 | hle/service/service.cpp |
| 44 | hle/service/srv.cpp | 46 | hle/service/srv.cpp |
| 45 | hw/gpu.cpp | 47 | hw/gpu.cpp |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 34a2eba1b..be677ae20 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -89,6 +89,9 @@ public: | |||
| 89 | */ | 89 | */ |
| 90 | virtual void LoadContext(const ThreadContext& ctx) = 0; | 90 | virtual void LoadContext(const ThreadContext& ctx) = 0; |
| 91 | 91 | ||
| 92 | /// Prepare core for thread reschedule (if needed to correctly handle state) | ||
| 93 | virtual void PrepareReschedule() = 0; | ||
| 94 | |||
| 92 | /// Getter for num_instructions | 95 | /// Getter for num_instructions |
| 93 | u64 GetNumInstructions() { | 96 | u64 GetNumInstructions() { |
| 94 | return num_instructions; | 97 | return num_instructions; |
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index 17f787b86..0e893f182 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp | |||
| @@ -98,7 +98,7 @@ u64 ARM_Interpreter::GetTicks() const { | |||
| 98 | * @param num_instructions Number of instructions to executes | 98 | * @param num_instructions Number of instructions to executes |
| 99 | */ | 99 | */ |
| 100 | void ARM_Interpreter::ExecuteInstructions(int num_instructions) { | 100 | void ARM_Interpreter::ExecuteInstructions(int num_instructions) { |
| 101 | state->NumInstrsToExecute = num_instructions; | 101 | state->NumInstrsToExecute = num_instructions - 1; |
| 102 | ARMul_Emulate32(state); | 102 | ARMul_Emulate32(state); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| @@ -118,6 +118,9 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) { | |||
| 118 | 118 | ||
| 119 | ctx.fpscr = state->VFP[1]; | 119 | ctx.fpscr = state->VFP[1]; |
| 120 | ctx.fpexc = state->VFP[2]; | 120 | ctx.fpexc = state->VFP[2]; |
| 121 | |||
| 122 | ctx.reg_15 = state->Reg[15]; | ||
| 123 | ctx.mode = state->NextInstr; | ||
| 121 | } | 124 | } |
| 122 | 125 | ||
| 123 | /** | 126 | /** |
| @@ -137,6 +140,11 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { | |||
| 137 | state->VFP[1] = ctx.fpscr; | 140 | state->VFP[1] = ctx.fpscr; |
| 138 | state->VFP[2] = ctx.fpexc; | 141 | state->VFP[2] = ctx.fpexc; |
| 139 | 142 | ||
| 140 | state->Reg[15] = ctx.pc; | 143 | state->Reg[15] = ctx.reg_15; |
| 141 | state->NextInstr = RESUME; | 144 | state->NextInstr = ctx.mode; |
| 145 | } | ||
| 146 | |||
| 147 | /// Prepare core for thread reschedule (if needed to correctly handle state) | ||
| 148 | void ARM_Interpreter::PrepareReschedule() { | ||
| 149 | state->NumInstrsToExecute = 0; | ||
| 142 | } | 150 | } |
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 6a531e497..1e82883a2 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h | |||
| @@ -72,6 +72,9 @@ public: | |||
| 72 | */ | 72 | */ |
| 73 | void LoadContext(const ThreadContext& ctx); | 73 | void LoadContext(const ThreadContext& ctx); |
| 74 | 74 | ||
| 75 | /// Prepare core for thread reschedule (if needed to correctly handle state) | ||
| 76 | void PrepareReschedule(); | ||
| 77 | |||
| 75 | protected: | 78 | protected: |
| 76 | 79 | ||
| 77 | /** | 80 | /** |
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index e5dc7bd44..f3c14e608 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp | |||
| @@ -4456,6 +4456,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 4456 | } | 4456 | } |
| 4457 | /* Drop through. */ | 4457 | /* Drop through. */ |
| 4458 | 4458 | ||
| 4459 | case 0xe0: | ||
| 4459 | case 0xe4: | 4460 | case 0xe4: |
| 4460 | case 0xe6: | 4461 | case 0xe6: |
| 4461 | case 0xe8: | 4462 | case 0xe8: |
| @@ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 4489 | 4490 | ||
| 4490 | 4491 | ||
| 4491 | /* Co-Processor Register Transfers (MRC) and Data Ops. */ | 4492 | /* Co-Processor Register Transfers (MRC) and Data Ops. */ |
| 4492 | case 0xe0: | ||
| 4493 | case 0xe1: | 4493 | case 0xe1: |
| 4494 | case 0xe3: | 4494 | case 0xe3: |
| 4495 | case 0xe5: | 4495 | case 0xe5: |
| @@ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state) | |||
| 4533 | case 0xfd: | 4533 | case 0xfd: |
| 4534 | case 0xfe: | 4534 | case 0xfe: |
| 4535 | case 0xff: | 4535 | case 0xff: |
| 4536 | if (instr == ARMul_ABORTWORD | ||
| 4537 | && state->AbortAddr == pc) { | ||
| 4538 | /* A prefetch abort. */ | ||
| 4539 | XScale_set_fsr_far (state, | ||
| 4540 | ARMul_CP15_R5_MMU_EXCPT, | ||
| 4541 | pc); | ||
| 4542 | ARMul_Abort (state, | ||
| 4543 | ARMul_PrefetchAbortV); | ||
| 4544 | break; | ||
| 4545 | } | ||
| 4546 | //sky_pref_t* pref = get_skyeye_pref(); | ||
| 4547 | //if(pref->user_mode_sim){ | ||
| 4548 | // ARMul_OSHandleSWI (state, BITS (0, 23)); | ||
| 4549 | // break; | ||
| 4550 | //} | ||
| 4551 | HLE::CallSVC(instr); | 4536 | HLE::CallSVC(instr); |
| 4552 | ARMul_Abort (state, ARMul_SWIV); | ||
| 4553 | break; | 4537 | break; |
| 4554 | } | 4538 | } |
| 4555 | } | 4539 | } |
diff --git a/src/core/core.cpp b/src/core/core.cpp index f88bcd704..7dc0809d0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -9,21 +9,24 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/mem_map.h" | 10 | #include "core/mem_map.h" |
| 11 | #include "core/hw/hw.h" | 11 | #include "core/hw/hw.h" |
| 12 | #include "core/hw/gpu.h" | ||
| 12 | #include "core/arm/disassembler/arm_disasm.h" | 13 | #include "core/arm/disassembler/arm_disasm.h" |
| 13 | #include "core/arm/interpreter/arm_interpreter.h" | 14 | #include "core/arm/interpreter/arm_interpreter.h" |
| 14 | 15 | ||
| 16 | #include "core/hle/hle.h" | ||
| 15 | #include "core/hle/kernel/thread.h" | 17 | #include "core/hle/kernel/thread.h" |
| 16 | 18 | ||
| 17 | namespace Core { | 19 | namespace Core { |
| 18 | 20 | ||
| 19 | ARM_Disasm* g_disasm = NULL; ///< ARM disassembler | 21 | u64 g_last_ticks = 0; ///< Last CPU ticks |
| 20 | ARM_Interface* g_app_core = NULL; ///< ARM11 application core | 22 | ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler |
| 21 | ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core | 23 | ARM_Interface* g_app_core = nullptr; ///< ARM11 application core |
| 24 | ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core | ||
| 22 | 25 | ||
| 23 | /// Run the core CPU loop | 26 | /// Run the core CPU loop |
| 24 | void RunLoop() { | 27 | void RunLoop() { |
| 25 | for (;;){ | 28 | for (;;){ |
| 26 | g_app_core->Run(100); | 29 | g_app_core->Run(GPU::kFrameTicks); |
| 27 | HW::Update(); | 30 | HW::Update(); |
| 28 | Kernel::Reschedule(); | 31 | Kernel::Reschedule(); |
| 29 | } | 32 | } |
| @@ -32,8 +35,14 @@ void RunLoop() { | |||
| 32 | /// Step the CPU one instruction | 35 | /// Step the CPU one instruction |
| 33 | void SingleStep() { | 36 | void SingleStep() { |
| 34 | g_app_core->Step(); | 37 | g_app_core->Step(); |
| 35 | HW::Update(); | 38 | |
| 36 | Kernel::Reschedule(); | 39 | // Update and reschedule after approx. 1 frame |
| 40 | u64 current_ticks = Core::g_app_core->GetTicks(); | ||
| 41 | if ((current_ticks - g_last_ticks) >= GPU::kFrameTicks || HLE::g_reschedule) { | ||
| 42 | g_last_ticks = current_ticks; | ||
| 43 | HW::Update(); | ||
| 44 | Kernel::Reschedule(); | ||
| 45 | } | ||
| 37 | } | 46 | } |
| 38 | 47 | ||
| 39 | /// Halt the core | 48 | /// Halt the core |
| @@ -54,6 +63,8 @@ int Init() { | |||
| 54 | g_app_core = new ARM_Interpreter(); | 63 | g_app_core = new ARM_Interpreter(); |
| 55 | g_sys_core = new ARM_Interpreter(); | 64 | g_sys_core = new ARM_Interpreter(); |
| 56 | 65 | ||
| 66 | g_last_ticks = Core::g_app_core->GetTicks(); | ||
| 67 | |||
| 57 | return 0; | 68 | return 0; |
| 58 | } | 69 | } |
| 59 | 70 | ||
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 8a3ad83ea..8eb189a8b 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj | |||
| @@ -168,12 +168,14 @@ | |||
| 168 | <ClCompile Include="hle\config_mem.cpp" /> | 168 | <ClCompile Include="hle\config_mem.cpp" /> |
| 169 | <ClCompile Include="hle\coprocessor.cpp" /> | 169 | <ClCompile Include="hle\coprocessor.cpp" /> |
| 170 | <ClCompile Include="hle\hle.cpp" /> | 170 | <ClCompile Include="hle\hle.cpp" /> |
| 171 | <ClCompile Include="hle\kernel\event.cpp" /> | ||
| 171 | <ClCompile Include="hle\kernel\kernel.cpp" /> | 172 | <ClCompile Include="hle\kernel\kernel.cpp" /> |
| 172 | <ClCompile Include="hle\kernel\mutex.cpp" /> | 173 | <ClCompile Include="hle\kernel\mutex.cpp" /> |
| 173 | <ClCompile Include="hle\kernel\thread.cpp" /> | 174 | <ClCompile Include="hle\kernel\thread.cpp" /> |
| 174 | <ClCompile Include="hle\service\apt.cpp" /> | 175 | <ClCompile Include="hle\service\apt.cpp" /> |
| 175 | <ClCompile Include="hle\service\gsp.cpp" /> | 176 | <ClCompile Include="hle\service\gsp.cpp" /> |
| 176 | <ClCompile Include="hle\service\hid.cpp" /> | 177 | <ClCompile Include="hle\service\hid.cpp" /> |
| 178 | <ClCompile Include="hle\service\ndm.cpp" /> | ||
| 177 | <ClCompile Include="hle\service\service.cpp" /> | 179 | <ClCompile Include="hle\service\service.cpp" /> |
| 178 | <ClCompile Include="hle\service\srv.cpp" /> | 180 | <ClCompile Include="hle\service\srv.cpp" /> |
| 179 | <ClCompile Include="hle\svc.cpp" /> | 181 | <ClCompile Include="hle\svc.cpp" /> |
| @@ -217,12 +219,14 @@ | |||
| 217 | <ClInclude Include="hle\coprocessor.h" /> | 219 | <ClInclude Include="hle\coprocessor.h" /> |
| 218 | <ClInclude Include="hle\function_wrappers.h" /> | 220 | <ClInclude Include="hle\function_wrappers.h" /> |
| 219 | <ClInclude Include="hle\hle.h" /> | 221 | <ClInclude Include="hle\hle.h" /> |
| 222 | <ClInclude Include="hle\kernel\event.h" /> | ||
| 220 | <ClInclude Include="hle\kernel\kernel.h" /> | 223 | <ClInclude Include="hle\kernel\kernel.h" /> |
| 221 | <ClInclude Include="hle\kernel\mutex.h" /> | 224 | <ClInclude Include="hle\kernel\mutex.h" /> |
| 222 | <ClInclude Include="hle\kernel\thread.h" /> | 225 | <ClInclude Include="hle\kernel\thread.h" /> |
| 223 | <ClInclude Include="hle\service\apt.h" /> | 226 | <ClInclude Include="hle\service\apt.h" /> |
| 224 | <ClInclude Include="hle\service\gsp.h" /> | 227 | <ClInclude Include="hle\service\gsp.h" /> |
| 225 | <ClInclude Include="hle\service\hid.h" /> | 228 | <ClInclude Include="hle\service\hid.h" /> |
| 229 | <ClInclude Include="hle\service\ndm.h" /> | ||
| 226 | <ClInclude Include="hle\service\service.h" /> | 230 | <ClInclude Include="hle\service\service.h" /> |
| 227 | <ClInclude Include="hle\service\srv.h" /> | 231 | <ClInclude Include="hle\service\srv.h" /> |
| 228 | <ClInclude Include="hle\svc.h" /> | 232 | <ClInclude Include="hle\svc.h" /> |
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index f7b342f98..da781f816 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters | |||
| @@ -165,6 +165,12 @@ | |||
| 165 | <ClCompile Include="arm\interpreter\armcopro.cpp"> | 165 | <ClCompile Include="arm\interpreter\armcopro.cpp"> |
| 166 | <Filter>arm\interpreter</Filter> | 166 | <Filter>arm\interpreter</Filter> |
| 167 | </ClCompile> | 167 | </ClCompile> |
| 168 | <ClCompile Include="hle\kernel\event.cpp"> | ||
| 169 | <Filter>hle\kernel</Filter> | ||
| 170 | </ClCompile> | ||
| 171 | <ClCompile Include="hle\service\ndm.cpp"> | ||
| 172 | <Filter>hle\service</Filter> | ||
| 173 | </ClCompile> | ||
| 168 | </ItemGroup> | 174 | </ItemGroup> |
| 169 | <ItemGroup> | 175 | <ItemGroup> |
| 170 | <ClInclude Include="arm\disassembler\arm_disasm.h"> | 176 | <ClInclude Include="arm\disassembler\arm_disasm.h"> |
| @@ -295,6 +301,12 @@ | |||
| 295 | <ClInclude Include="hle\kernel\mutex.h"> | 301 | <ClInclude Include="hle\kernel\mutex.h"> |
| 296 | <Filter>hle\kernel</Filter> | 302 | <Filter>hle\kernel</Filter> |
| 297 | </ClInclude> | 303 | </ClInclude> |
| 304 | <ClInclude Include="hle\kernel\event.h"> | ||
| 305 | <Filter>hle\kernel</Filter> | ||
| 306 | </ClInclude> | ||
| 307 | <ClInclude Include="hle\service\ndm.h"> | ||
| 308 | <Filter>hle\service</Filter> | ||
| 309 | </ClInclude> | ||
| 298 | </ItemGroup> | 310 | </ItemGroup> |
| 299 | <ItemGroup> | 311 | <ItemGroup> |
| 300 | <Text Include="CMakeLists.txt" /> | 312 | <Text Include="CMakeLists.txt" /> |
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 48aa878cc..8c898b265 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp | |||
| @@ -55,7 +55,7 @@ inline void Read(T &var, const u32 addr) { | |||
| 55 | break; | 55 | break; |
| 56 | 56 | ||
| 57 | default: | 57 | default: |
| 58 | ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); | 58 | ERROR_LOG(HLE, "unknown addr=0x%08X", addr); |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | 61 | ||
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp index 39674ee64..9a5b0deda 100644 --- a/src/core/hle/coprocessor.cpp +++ b/src/core/hle/coprocessor.cpp | |||
| @@ -25,7 +25,7 @@ s32 CallMRC(u32 instruction) { | |||
| 25 | return GetThreadCommandBuffer(); | 25 | return GetThreadCommandBuffer(); |
| 26 | 26 | ||
| 27 | default: | 27 | default: |
| 28 | //DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); | 28 | DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); |
| 29 | break; | 29 | break; |
| 30 | } | 30 | } |
| 31 | return -1; | 31 | return -1; |
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 801865d49..0bed78653 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -1,19 +1,6 @@ | |||
| 1 | // Copyright (c) 2012- PPSSPP Project. | 1 | // Copyright 2014 Citra Emulator Project |
| 2 | 2 | // Licensed under GPLv2 | |
| 3 | // This program is free software: you can redistribute it and/or modify | 3 | // Refer to the license.txt file included. |
| 4 | // it under the terms of the GNU General Public License as published by | ||
| 5 | // the Free Software Foundation, version 2.0 or later versions. | ||
| 6 | |||
| 7 | // This program is distributed in the hope that it will be useful, | ||
| 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 10 | // GNU General Public License 2.0 for more details. | ||
| 11 | |||
| 12 | // A copy of the GPL 2.0 should have been included with the program. | ||
| 13 | // If not, see http://www.gnu.org/licenses/ | ||
| 14 | |||
| 15 | // Official git repository and contact information can be found at | ||
| 16 | // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. | ||
| 17 | 4 | ||
| 18 | #pragma once | 5 | #pragma once |
| 19 | 6 | ||
| @@ -21,725 +8,107 @@ | |||
| 21 | #include "core/mem_map.h" | 8 | #include "core/mem_map.h" |
| 22 | #include "core/hle/hle.h" | 9 | #include "core/hle/hle.h" |
| 23 | 10 | ||
| 24 | // For easy parameter parsing and return value processing. | 11 | namespace HLE { |
| 25 | |||
| 26 | //32bit wrappers | ||
| 27 | template<void func()> void WrapV_V() { | ||
| 28 | func(); | ||
| 29 | } | ||
| 30 | |||
| 31 | template<u32 func()> void WrapU_V() { | ||
| 32 | RETURN(func()); | ||
| 33 | } | ||
| 34 | |||
| 35 | template<int func(void *, const char *)> void WrapI_VC() { | ||
| 36 | u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1))); | ||
| 37 | RETURN(retval); | ||
| 38 | } | ||
| 39 | |||
| 40 | template<u32 func(int, void *, int)> void WrapU_IVI() { | ||
| 41 | u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2)); | ||
| 42 | RETURN(retval); | ||
| 43 | } | ||
| 44 | |||
| 45 | template<int func(const char *, int, int, u32)> void WrapI_CIIU() { | ||
| 46 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); | ||
| 47 | RETURN(retval); | ||
| 48 | } | ||
| 49 | |||
| 50 | template<int func(int, const char *, u32, void *, void *, u32, int)> void WrapI_ICUVVUI() { | ||
| 51 | u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)),Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); | ||
| 52 | RETURN(retval); | ||
| 53 | } | ||
| 54 | |||
| 55 | // Hm, do so many params get passed in registers? | ||
| 56 | template<int func(const char *, int, const char *, int, int, int, int, int)> void WrapI_CICIIIII() { | ||
| 57 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), Memory::GetCharPointer(PARAM(2)), | ||
| 58 | PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7)); | ||
| 59 | RETURN(retval); | ||
| 60 | } | ||
| 61 | |||
| 62 | // Hm, do so many params get passed in registers? | ||
| 63 | template<int func(const char *, int, int, int, int, int, int)> void WrapI_CIIIIII() { | ||
| 64 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 65 | PARAM(3), PARAM(4), PARAM(5), PARAM(6)); | ||
| 66 | RETURN(retval); | ||
| 67 | } | ||
| 68 | |||
| 69 | // Hm, do so many params get passed in registers? | ||
| 70 | template<int func(int, int, int, int, int, int, u32)> void WrapI_IIIIIIU() { | ||
| 71 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); | ||
| 72 | RETURN(retval); | ||
| 73 | } | ||
| 74 | |||
| 75 | // Hm, do so many params get passed in registers? | ||
| 76 | template<int func(int, int, int, int, int, int, int, int, u32)> void WrapI_IIIIIIIIU() { | ||
| 77 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7), PARAM(8)); | ||
| 78 | RETURN(retval); | ||
| 79 | } | ||
| 80 | |||
| 81 | template<u32 func(int, void *)> void WrapU_IV() { | ||
| 82 | u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1))); | ||
| 83 | RETURN(retval); | ||
| 84 | } | ||
| 85 | |||
| 86 | template<u32 func(u32)> void WrapU_U() { | ||
| 87 | u32 retval = func(PARAM(0)); | ||
| 88 | RETURN(retval); | ||
| 89 | } | ||
| 90 | |||
| 91 | template<u32 func(u32, int)> void WrapU_UI() { | ||
| 92 | u32 retval = func(PARAM(0), PARAM(1)); | ||
| 93 | RETURN(retval); | ||
| 94 | } | ||
| 95 | |||
| 96 | template<int func(u32)> void WrapI_U() { | ||
| 97 | int retval = func(PARAM(0)); | ||
| 98 | RETURN(retval); | ||
| 99 | } | ||
| 100 | |||
| 101 | template<int func(u32, int)> void WrapI_UI() { | ||
| 102 | int retval = func(PARAM(0), PARAM(1)); | ||
| 103 | RETURN(retval); | ||
| 104 | } | ||
| 105 | |||
| 106 | template<int func(u32, int, int, u32)> void WrapI_UIIU() { | ||
| 107 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 108 | RETURN(retval); | ||
| 109 | } | ||
| 110 | |||
| 111 | template<u32 func(int, u32, int)> void WrapU_IUI() { | ||
| 112 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 113 | RETURN(retval); | ||
| 114 | } | ||
| 115 | |||
| 116 | template<int func(u32, u32)> void WrapI_UU() { | ||
| 117 | int retval = func(PARAM(0), PARAM(1)); | ||
| 118 | RETURN(retval); | ||
| 119 | } | ||
| 120 | |||
| 121 | template<int func(u32, u32, u32)> void WrapI_UUU() { | ||
| 122 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 123 | RETURN(retval); | ||
| 124 | } | ||
| 125 | |||
| 126 | template<int func(u32, u32, u32, int)> void WrapI_UUUI() { | ||
| 127 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 128 | RETURN(retval); | ||
| 129 | } | ||
| 130 | |||
| 131 | template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() { | ||
| 132 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); | ||
| 133 | RETURN(retval); | ||
| 134 | } | ||
| 135 | |||
| 136 | template<int func(u32, u32, u32, u32)> void WrapI_UUUU() { | ||
| 137 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 138 | RETURN(retval); | ||
| 139 | } | ||
| 140 | |||
| 141 | template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() { | ||
| 142 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 143 | RETURN(retval); | ||
| 144 | } | ||
| 145 | |||
| 146 | template<int func(void*)> void WrapI_V() { | ||
| 147 | u32 retval = func(Memory::GetPointer(PARAM(0))); | ||
| 148 | RETURN(retval); | ||
| 149 | } | ||
| 150 | |||
| 151 | template<u32 func(int)> void WrapU_I() { | ||
| 152 | u32 retval = func(PARAM(0)); | ||
| 153 | RETURN(retval); | ||
| 154 | } | ||
| 155 | |||
| 156 | template<u32 func(int, int, u32)> void WrapU_IIU() { | ||
| 157 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 158 | RETURN(retval); | ||
| 159 | } | ||
| 160 | |||
| 161 | template<int func(int)> void WrapI_I() { | ||
| 162 | int retval = func(PARAM(0)); | ||
| 163 | RETURN(retval); | ||
| 164 | } | ||
| 165 | |||
| 166 | template<void func(u32)> void WrapV_U() { | ||
| 167 | func(PARAM(0)); | ||
| 168 | } | ||
| 169 | |||
| 170 | template<void func(int)> void WrapV_I() { | ||
| 171 | func(PARAM(0)); | ||
| 172 | } | ||
| 173 | |||
| 174 | template<void func(u32, u32)> void WrapV_UU() { | ||
| 175 | func(PARAM(0), PARAM(1)); | ||
| 176 | } | ||
| 177 | |||
| 178 | template<void func(int, int)> void WrapV_II() { | ||
| 179 | func(PARAM(0), PARAM(1)); | ||
| 180 | } | ||
| 181 | |||
| 182 | template<void func(u32, const char *)> void WrapV_UC() { | ||
| 183 | func(PARAM(0), Memory::GetCharPointer(PARAM(1))); | ||
| 184 | } | ||
| 185 | |||
| 186 | template<int func(u32, const char *)> void WrapI_UC() { | ||
| 187 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); | ||
| 188 | RETURN(retval); | ||
| 189 | } | ||
| 190 | |||
| 191 | template<int func(u32, const char *, int)> void WrapI_UCI() { | ||
| 192 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2)); | ||
| 193 | RETURN(retval); | ||
| 194 | } | ||
| 195 | |||
| 196 | template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() { | ||
| 197 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); | ||
| 198 | RETURN(retval); | ||
| 199 | } | ||
| 200 | |||
| 201 | template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() { | ||
| 202 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 203 | RETURN(retval); | ||
| 204 | } | ||
| 205 | |||
| 206 | template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() { | ||
| 207 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); | ||
| 208 | RETURN(retval); | ||
| 209 | } | ||
| 210 | |||
| 211 | template<u32 func(u32, u32)> void WrapU_UU() { | ||
| 212 | u32 retval = func(PARAM(0), PARAM(1)); | ||
| 213 | RETURN(retval); | ||
| 214 | } | ||
| 215 | |||
| 216 | template<u32 func(u32, u32, int)> void WrapU_UUI() { | ||
| 217 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 218 | RETURN(retval); | ||
| 219 | } | ||
| 220 | |||
| 221 | template<u32 func(u32, u32, int, int)> void WrapU_UUII() { | ||
| 222 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 223 | RETURN(retval); | ||
| 224 | } | ||
| 225 | |||
| 226 | template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() { | ||
| 227 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); | ||
| 228 | RETURN(retval); | ||
| 229 | } | ||
| 230 | |||
| 231 | template<void func(u32, int, u32, int, int)> void WrapV_UIUII() { | ||
| 232 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 233 | } | ||
| 234 | |||
| 235 | template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() { | ||
| 236 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 237 | RETURN(retval); | ||
| 238 | } | ||
| 239 | |||
| 240 | template<int func(u32, int, u32, int, int)> void WrapI_UIUII() { | ||
| 241 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 242 | RETURN(retval); | ||
| 243 | } | ||
| 244 | |||
| 245 | template<u32 func(u32, int, u32, int)> void WrapU_UIUI() { | ||
| 246 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 247 | RETURN(retval); | ||
| 248 | } | ||
| 249 | |||
| 250 | template<int func(u32, int, u32, int)> void WrapI_UIUI() { | ||
| 251 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 252 | RETURN(retval); | ||
| 253 | } | ||
| 254 | |||
| 255 | template<u32 func(u32, int, u32)> void WrapU_UIU() { | ||
| 256 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 257 | RETURN(retval); | ||
| 258 | } | ||
| 259 | |||
| 260 | template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() { | ||
| 261 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 262 | RETURN(retval); | ||
| 263 | } | ||
| 264 | |||
| 265 | template<u32 func(u32, int, int)> void WrapU_UII() { | ||
| 266 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 267 | RETURN(retval); | ||
| 268 | } | ||
| 269 | |||
| 270 | template<u32 func(u32, int, int, u32)> void WrapU_UIIU() { | ||
| 271 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 272 | RETURN(retval); | ||
| 273 | } | ||
| 274 | |||
| 275 | template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() { | ||
| 276 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 277 | RETURN(retval); | ||
| 278 | } | ||
| 279 | |||
| 280 | template<int func(u32, u32, int, int)> void WrapI_UUII() { | ||
| 281 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 282 | RETURN(retval); | ||
| 283 | } | ||
| 284 | |||
| 285 | template<int func(u32, u32, int, int, int)> void WrapI_UUIII() { | ||
| 286 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 287 | RETURN(retval); | ||
| 288 | } | ||
| 289 | |||
| 290 | template<void func(u32, int, int, int)> void WrapV_UIII() { | ||
| 291 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 292 | } | ||
| 293 | |||
| 294 | template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() { | ||
| 295 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); | ||
| 296 | } | ||
| 297 | |||
| 298 | template<void func(u32, int, int)> void WrapV_UII() { | ||
| 299 | func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 300 | } | ||
| 301 | 12 | ||
| 302 | template<u32 func(int, u32)> void WrapU_IU() { | 13 | #define PARAM(n) Core::g_app_core->GetReg(n) |
| 303 | int retval = func(PARAM(0), PARAM(1)); | 14 | #define RETURN(n) Core::g_app_core->SetReg(0, n) |
| 304 | RETURN(retval); | ||
| 305 | } | ||
| 306 | 15 | ||
| 307 | template<int func(int, u32)> void WrapI_IU() { | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 308 | int retval = func(PARAM(0), PARAM(1)); | 17 | // Function wrappers that return type s32 |
| 309 | RETURN(retval); | ||
| 310 | } | ||
| 311 | 18 | ||
| 312 | template<int func(u32, u32, int)> void WrapI_UUI() { | 19 | template<s32 func(u32, u32, u32, u32)> void Wrap() { |
| 313 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | 20 | RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3))); |
| 314 | RETURN(retval); | ||
| 315 | } | 21 | } |
| 316 | 22 | ||
| 317 | template<int func(u32, u32, int, u32)> void WrapI_UUIU() { | 23 | template<s32 func(u32, u32, u32, u32, u32)> void Wrap() { |
| 318 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | 24 | RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4))); |
| 319 | RETURN(retval); | ||
| 320 | } | 25 | } |
| 321 | 26 | ||
| 322 | template<int func(int, int)> void WrapI_II() { | 27 | template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ |
| 323 | int retval = func(PARAM(0), PARAM(1)); | 28 | u32 param_1 = 0; |
| 29 | u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 30 | Core::g_app_core->SetReg(1, param_1); | ||
| 324 | RETURN(retval); | 31 | RETURN(retval); |
| 325 | } | 32 | } |
| 326 | 33 | ||
| 327 | template<int func(int, int, int)> void WrapI_III() { | 34 | template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { |
| 328 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | 35 | s32 param_1 = 0; |
| 36 | s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), | ||
| 37 | (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); | ||
| 38 | Core::g_app_core->SetReg(1, (u32)param_1); | ||
| 329 | RETURN(retval); | 39 | RETURN(retval); |
| 330 | } | 40 | } |
| 331 | 41 | ||
| 332 | template<int func(int, u32, int)> void WrapI_IUI() { | 42 | // TODO(bunnei): Is this correct? Probably not |
| 333 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | 43 | template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { |
| 334 | RETURN(retval); | 44 | RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0)))); |
| 335 | } | 45 | } |
| 336 | 46 | ||
| 337 | template<int func(int, int, int, int)> void WrapI_IIII() { | 47 | template<s32 func(u32, s64)> void Wrap() { |
| 338 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | 48 | RETURN(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2)))); |
| 339 | RETURN(retval); | ||
| 340 | } | 49 | } |
| 341 | 50 | ||
| 342 | template<int func(u32, int, int, int)> void WrapI_UIII() { | 51 | template<s32 func(void*, void*, u32)> void Wrap(){ |
| 343 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | 52 | RETURN(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2))); |
| 344 | RETURN(retval); | ||
| 345 | } | 53 | } |
| 346 | 54 | ||
| 347 | template<int func(int, int, int, u32, int)> void WrapI_IIIUI() { | 55 | template<s32 func(s32*, u32)> void Wrap(){ |
| 348 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | 56 | s32 param_1 = 0; |
| 57 | u32 retval = func(¶m_1, PARAM(1)); | ||
| 58 | Core::g_app_core->SetReg(1, param_1); | ||
| 349 | RETURN(retval); | 59 | RETURN(retval); |
| 350 | } | 60 | } |
| 351 | 61 | ||
| 352 | template<int func(int, u32, u32, int, int)> void WrapI_IUUII() { | 62 | template<s32 func(u32, s32)> void Wrap() { |
| 353 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | 63 | RETURN(func(PARAM(0), (s32)PARAM(1))); |
| 354 | RETURN(retval); | ||
| 355 | } | 64 | } |
| 356 | 65 | ||
| 357 | template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() { | 66 | template<s32 func(u32*, u32)> void Wrap(){ |
| 358 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); | 67 | u32 param_1 = 0; |
| 68 | u32 retval = func(¶m_1, PARAM(1)); | ||
| 69 | Core::g_app_core->SetReg(1, param_1); | ||
| 359 | RETURN(retval); | 70 | RETURN(retval); |
| 360 | } | 71 | } |
| 361 | 72 | ||
| 362 | template<int func(int, int, u32)> void WrapI_IIU() { | 73 | template<s32 func(u32)> void Wrap() { |
| 363 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | 74 | RETURN(func(PARAM(0))); |
| 364 | RETURN(retval); | ||
| 365 | } | 75 | } |
| 366 | 76 | ||
| 367 | template<void func(int, u32)> void WrapV_IU() { | 77 | template<s32 func(void*)> void Wrap() { |
| 368 | func(PARAM(0), PARAM(1)); | 78 | RETURN(func(Memory::GetPointer(PARAM(0)))); |
| 369 | } | 79 | } |
| 370 | 80 | ||
| 371 | template<void func(u32, int)> void WrapV_UI() { | 81 | template<s32 func(s64*, u32, void*, s32)> void Wrap(){ |
| 372 | func(PARAM(0), PARAM(1)); | 82 | RETURN(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), |
| 83 | (s32)PARAM(3))); | ||
| 373 | } | 84 | } |
| 374 | 85 | ||
| 375 | template<u32 func(const char *)> void WrapU_C() { | 86 | template<s32 func(u32*, const char*)> void Wrap() { |
| 376 | u32 retval = func(Memory::GetCharPointer(PARAM(0))); | 87 | u32 param_1 = 0; |
| 88 | u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))); | ||
| 89 | Core::g_app_core->SetReg(1, param_1); | ||
| 377 | RETURN(retval); | 90 | RETURN(retval); |
| 378 | } | 91 | } |
| 379 | 92 | ||
| 380 | template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() { | 93 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 381 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), | 94 | // Function wrappers that return type u32 |
| 382 | Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), | ||
| 383 | PARAM(3)); | ||
| 384 | RETURN(retval); | ||
| 385 | } | ||
| 386 | |||
| 387 | template<int func(const char *)> void WrapI_C() { | ||
| 388 | int retval = func(Memory::GetCharPointer(PARAM(0))); | ||
| 389 | RETURN(retval); | ||
| 390 | } | ||
| 391 | |||
| 392 | template<int func(const char *, u32)> void WrapI_CU() { | ||
| 393 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); | ||
| 394 | RETURN(retval); | ||
| 395 | } | ||
| 396 | |||
| 397 | template<int func(const char *, u32, int)> void WrapI_CUI() { | ||
| 398 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 399 | RETURN(retval); | ||
| 400 | } | ||
| 401 | 95 | ||
| 402 | template<int func(int, const char *, int, u32)> void WrapI_ICIU() { | 96 | template<u32 func()> void Wrap() { |
| 403 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); | 97 | RETURN(func()); |
| 404 | RETURN(retval); | ||
| 405 | } | ||
| 406 | |||
| 407 | template<int func(const char *, int, u32)> void WrapI_CIU() { | ||
| 408 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 409 | RETURN(retval); | ||
| 410 | } | ||
| 411 | |||
| 412 | template<int func(const char *, u32, u32)> void WrapI_CUU() { | ||
| 413 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 414 | RETURN(retval); | ||
| 415 | } | ||
| 416 | |||
| 417 | template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() { | ||
| 418 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 419 | PARAM(3)); | ||
| 420 | RETURN(retval); | ||
| 421 | } | ||
| 422 | |||
| 423 | template<int func(const char *, const char*, int, int)> void WrapI_CCII() { | ||
| 424 | int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); | ||
| 425 | RETURN(retval); | ||
| 426 | } | ||
| 427 | |||
| 428 | template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() { | ||
| 429 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 430 | PARAM(3), PARAM(4), PARAM(5)); | ||
| 431 | RETURN(retval); | ||
| 432 | } | ||
| 433 | |||
| 434 | template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() { | ||
| 435 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 436 | PARAM(3), PARAM(4), PARAM(5)); | ||
| 437 | RETURN(retval); | ||
| 438 | } | ||
| 439 | |||
| 440 | template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() { | ||
| 441 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 442 | PARAM(3), PARAM(4)); | ||
| 443 | RETURN(retval); | ||
| 444 | } | ||
| 445 | |||
| 446 | template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() { | ||
| 447 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 448 | PARAM(3), PARAM(4), PARAM(5)); | ||
| 449 | RETURN(retval); | ||
| 450 | } | ||
| 451 | |||
| 452 | template<u32 func(const char *, u32)> void WrapU_CU() { | ||
| 453 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); | ||
| 454 | RETURN((u32) retval); | ||
| 455 | } | ||
| 456 | |||
| 457 | template<u32 func(u32, const char *)> void WrapU_UC() { | ||
| 458 | u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); | ||
| 459 | RETURN(retval); | ||
| 460 | } | ||
| 461 | |||
| 462 | template<u32 func(const char *, u32, u32)> void WrapU_CUU() { | ||
| 463 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 464 | RETURN((u32) retval); | ||
| 465 | } | ||
| 466 | |||
| 467 | template<u32 func(int, int, int)> void WrapU_III() { | ||
| 468 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 469 | RETURN(retval); | ||
| 470 | } | ||
| 471 | |||
| 472 | template<u32 func(int, int)> void WrapU_II() { | ||
| 473 | u32 retval = func(PARAM(0), PARAM(1)); | ||
| 474 | RETURN(retval); | ||
| 475 | } | ||
| 476 | |||
| 477 | template<u32 func(int, int, int, int)> void WrapU_IIII() { | ||
| 478 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 479 | RETURN(retval); | ||
| 480 | } | ||
| 481 | |||
| 482 | template<u32 func(int, u32, u32)> void WrapU_IUU() { | ||
| 483 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 484 | RETURN(retval); | ||
| 485 | } | ||
| 486 | |||
| 487 | template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() { | ||
| 488 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 489 | RETURN(retval); | ||
| 490 | } | ||
| 491 | |||
| 492 | template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() { | ||
| 493 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 494 | RETURN(retval); | ||
| 495 | } | ||
| 496 | |||
| 497 | template<u32 func(u32, u32, u32)> void WrapU_UUU() { | ||
| 498 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 499 | RETURN(retval); | ||
| 500 | } | ||
| 501 | |||
| 502 | template<void func(int, u32, u32)> void WrapV_IUU() { | ||
| 503 | func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 504 | } | ||
| 505 | |||
| 506 | template<void func(int, int, u32)> void WrapV_IIU() { | ||
| 507 | func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 508 | } | ||
| 509 | |||
| 510 | template<void func(u32, int, u32)> void WrapV_UIU() { | ||
| 511 | func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 512 | } | ||
| 513 | |||
| 514 | template<int func(u32, int, u32)> void WrapI_UIU() { | ||
| 515 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 516 | RETURN(retval); | ||
| 517 | } | ||
| 518 | |||
| 519 | template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() { | ||
| 520 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 521 | } | ||
| 522 | |||
| 523 | template<void func(u32, u32, u32)> void WrapV_UUU() { | ||
| 524 | func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 525 | } | ||
| 526 | |||
| 527 | template<void func(u32, u32, u32, u32)> void WrapV_UUUU() { | ||
| 528 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 529 | } | ||
| 530 | |||
| 531 | template<void func(const char *, u32, int, u32)> void WrapV_CUIU() { | ||
| 532 | func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); | ||
| 533 | } | ||
| 534 | |||
| 535 | template<int func(const char *, u32, int, u32)> void WrapI_CUIU() { | ||
| 536 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3)); | ||
| 537 | RETURN(retval); | ||
| 538 | } | ||
| 539 | |||
| 540 | template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() { | ||
| 541 | func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), | ||
| 542 | PARAM(4)); | ||
| 543 | } | ||
| 544 | |||
| 545 | template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() { | ||
| 546 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), | ||
| 547 | PARAM(3), PARAM(4)); | ||
| 548 | RETURN(retval); | ||
| 549 | } | ||
| 550 | |||
| 551 | template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() { | ||
| 552 | func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), | ||
| 553 | PARAM(4)); | ||
| 554 | } | ||
| 555 | |||
| 556 | template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() { | ||
| 557 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 558 | PARAM(3), PARAM(4)); | ||
| 559 | RETURN(retval); | ||
| 560 | } | ||
| 561 | |||
| 562 | template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() { | ||
| 563 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 564 | RETURN(retval); | ||
| 565 | } | ||
| 566 | |||
| 567 | template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() { | ||
| 568 | u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); | ||
| 569 | RETURN(retval); | ||
| 570 | } | ||
| 571 | |||
| 572 | template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() { | ||
| 573 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 574 | RETURN(retval); | ||
| 575 | } | ||
| 576 | |||
| 577 | template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() { | ||
| 578 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 579 | RETURN(retval); | ||
| 580 | } | ||
| 581 | |||
| 582 | template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() { | ||
| 583 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); | ||
| 584 | RETURN(retval); | ||
| 585 | } | ||
| 586 | |||
| 587 | template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() { | ||
| 588 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 589 | RETURN(retval); | ||
| 590 | } | ||
| 591 | |||
| 592 | template<u32 func(u32, int, int, int)> void WrapU_UIII() { | ||
| 593 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 594 | RETURN(retval); | ||
| 595 | } | ||
| 596 | |||
| 597 | template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() { | ||
| 598 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 599 | RETURN(retval); | ||
| 600 | } | ||
| 601 | |||
| 602 | template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() { | ||
| 603 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); | ||
| 604 | RETURN(retval); | ||
| 605 | } | ||
| 606 | |||
| 607 | template<int func(int, u32, int, int)> void WrapI_IUII() { | ||
| 608 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 609 | RETURN(retval); | ||
| 610 | } | ||
| 611 | template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() { | ||
| 612 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 613 | RETURN(retval); | ||
| 614 | } | 98 | } |
| 615 | 99 | ||
| 616 | template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() { | 100 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 617 | func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | 101 | /// Function wrappers that return type void |
| 618 | } | ||
| 619 | 102 | ||
| 620 | template<u32 func(const char *, const char *)> void WrapU_CC() { | 103 | template<void func(s64)> void Wrap() { |
| 621 | int retval = func(Memory::GetCharPointer(PARAM(0)), | 104 | func(((s64)PARAM(1) << 32) | PARAM(0)); |
| 622 | Memory::GetCharPointer(PARAM(1))); | ||
| 623 | RETURN(retval); | ||
| 624 | } | 105 | } |
| 625 | 106 | ||
| 626 | template<void func(const char*)> void WrapV_C() { | 107 | template<void func(const char*)> void Wrap() { |
| 627 | func(Memory::GetCharPointer(PARAM(0))); | 108 | func(Memory::GetCharPointer(PARAM(0))); |
| 628 | } | 109 | } |
| 629 | 110 | ||
| 630 | template<void func(const char *, int)> void WrapV_CI() { | 111 | #undef PARAM |
| 631 | func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); | 112 | #undef RETURN |
| 632 | } | ||
| 633 | |||
| 634 | template<u32 func(const char *, int)> void WrapU_CI() { | ||
| 635 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); | ||
| 636 | RETURN(retval); | ||
| 637 | } | ||
| 638 | |||
| 639 | template<u32 func(const char *, int, int)> void WrapU_CII() { | ||
| 640 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 641 | RETURN(retval); | ||
| 642 | } | ||
| 643 | 113 | ||
| 644 | template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() { | 114 | } // namespace HLE |
| 645 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 646 | PARAM(3), PARAM(4)); | ||
| 647 | RETURN(retval); | ||
| 648 | } | ||
| 649 | |||
| 650 | template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() { | ||
| 651 | u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), | ||
| 652 | PARAM(3), PARAM(4), PARAM(5)); | ||
| 653 | RETURN(retval); | ||
| 654 | } | ||
| 655 | |||
| 656 | template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() { | ||
| 657 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), | ||
| 658 | PARAM(5)); | ||
| 659 | RETURN(retval); | ||
| 660 | } | ||
| 661 | |||
| 662 | template<int func(int, u32, u32, u32)> void WrapI_IUUU() { | ||
| 663 | int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 664 | RETURN(retval); | ||
| 665 | } | ||
| 666 | |||
| 667 | template<int func(int, u32, u32)> void WrapI_IUU() { | ||
| 668 | int retval = func(PARAM(0), PARAM(1), PARAM(2)); | ||
| 669 | RETURN(retval); | ||
| 670 | } | ||
| 671 | |||
| 672 | template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() { | ||
| 673 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6)); | ||
| 674 | RETURN(retval); | ||
| 675 | } | ||
| 676 | |||
| 677 | template<int func(u32, int, u32, u32)> void WrapI_UIUU() { | ||
| 678 | u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); | ||
| 679 | RETURN(retval); | ||
| 680 | } | ||
| 681 | |||
| 682 | template<int func(int, const char *)> void WrapI_IC() { | ||
| 683 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1))); | ||
| 684 | RETURN(retval); | ||
| 685 | } | ||
| 686 | |||
| 687 | template <int func(int, const char *, const char *, u32, int)> void WrapI_ICCUI() { | ||
| 688 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3), PARAM(4)); | ||
| 689 | RETURN(retval); | ||
| 690 | } | ||
| 691 | |||
| 692 | template <int func(int, const char *, const char *, int)> void WrapI_ICCI() { | ||
| 693 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3)); | ||
| 694 | RETURN(retval); | ||
| 695 | } | ||
| 696 | |||
| 697 | template <int func(const char *, int, int)> void WrapI_CII() { | ||
| 698 | int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); | ||
| 699 | RETURN(retval); | ||
| 700 | } | ||
| 701 | |||
| 702 | template <int func(int, const char *, int)> void WrapI_ICI() { | ||
| 703 | int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2)); | ||
| 704 | RETURN(retval); | ||
| 705 | } | ||
| 706 | |||
| 707 | template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){ | ||
| 708 | u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); | ||
| 709 | RETURN(retval); | ||
| 710 | } | ||
| 711 | |||
| 712 | template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){ | ||
| 713 | u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); | ||
| 714 | RETURN(retval); | ||
| 715 | } | ||
| 716 | |||
| 717 | template<int func(void*, u32)> void WrapI_VU(){ | ||
| 718 | u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1)); | ||
| 719 | RETURN(retval); | ||
| 720 | } | ||
| 721 | |||
| 722 | template<int func(void*, void*, u32)> void WrapI_VVU(){ | ||
| 723 | u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)); | ||
| 724 | RETURN(retval); | ||
| 725 | } | ||
| 726 | |||
| 727 | template<int func(void*, u32, void*, int)> void WrapI_VUVI(){ | ||
| 728 | u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3)); | ||
| 729 | RETURN(retval); | ||
| 730 | } | ||
| 731 | |||
| 732 | template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){ | ||
| 733 | u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | ||
| 734 | RETURN(retval); | ||
| 735 | } | ||
| 736 | |||
| 737 | template<int func(u32, s64)> void WrapI_US64() { | ||
| 738 | int retval = func(PARAM(0), PARAM64(1)); | ||
| 739 | RETURN(retval); | ||
| 740 | } | ||
| 741 | |||
| 742 | template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() { | ||
| 743 | int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); | ||
| 744 | RETURN(retval); | ||
| 745 | } | ||
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 080c36abf..53cda4a61 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/mem_map.h" | 7 | #include "core/mem_map.h" |
| 8 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 9 | #include "core/hle/svc.h" | 9 | #include "core/hle/svc.h" |
| 10 | #include "core/hle/kernel/thread.h" | ||
| 10 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 11 | 12 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -15,11 +16,13 @@ namespace HLE { | |||
| 15 | 16 | ||
| 16 | static std::vector<ModuleDef> g_module_db; | 17 | static std::vector<ModuleDef> g_module_db; |
| 17 | 18 | ||
| 19 | bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread | ||
| 20 | |||
| 18 | const FunctionDef* GetSVCInfo(u32 opcode) { | 21 | const FunctionDef* GetSVCInfo(u32 opcode) { |
| 19 | u32 func_num = opcode & 0xFFFFFF; // 8 bits | 22 | u32 func_num = opcode & 0xFFFFFF; // 8 bits |
| 20 | if (func_num > 0xFF) { | 23 | if (func_num > 0xFF) { |
| 21 | ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num); | 24 | ERROR_LOG(HLE,"unknown svc=0x%02X", func_num); |
| 22 | return NULL; | 25 | return nullptr; |
| 23 | } | 26 | } |
| 24 | return &g_module_db[0].func_table[func_num]; | 27 | return &g_module_db[0].func_table[func_num]; |
| 25 | } | 28 | } |
| @@ -33,19 +36,16 @@ void CallSVC(u32 opcode) { | |||
| 33 | if (info->func) { | 36 | if (info->func) { |
| 34 | info->func(); | 37 | info->func(); |
| 35 | } else { | 38 | } else { |
| 36 | ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); | 39 | ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str()); |
| 37 | } | 40 | } |
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | void EatCycles(u32 cycles) { | 43 | void Reschedule(const char *reason) { |
| 41 | // TODO: ImplementMe | ||
| 42 | } | ||
| 43 | |||
| 44 | void ReSchedule(const char *reason) { | ||
| 45 | #ifdef _DEBUG | 44 | #ifdef _DEBUG |
| 46 | _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason."); | 45 | _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason."); |
| 47 | #endif | 46 | #endif |
| 48 | // TODO: ImplementMe | 47 | Core::g_app_core->PrepareReschedule(); |
| 48 | g_reschedule = true; | ||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { | 51 | void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { |
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index c075147c3..bf4d84575 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h | |||
| @@ -9,14 +9,10 @@ | |||
| 9 | 9 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 11 | 11 | ||
| 12 | #define PARAM(n) Core::g_app_core->GetReg(n) | ||
| 13 | #define PARAM64(n) (Core::g_app_core->GetReg(n) | ((u64)Core::g_app_core->GetReg(n + 1) << 32)) | ||
| 14 | #define RETURN(n) Core::g_app_core->SetReg(0, n) | ||
| 15 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 17 | |||
| 18 | namespace HLE { | 12 | namespace HLE { |
| 19 | 13 | ||
| 14 | extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread | ||
| 15 | |||
| 20 | typedef u32 Addr; | 16 | typedef u32 Addr; |
| 21 | typedef void (*Func)(); | 17 | typedef void (*Func)(); |
| 22 | 18 | ||
| @@ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func | |||
| 36 | 32 | ||
| 37 | void CallSVC(u32 opcode); | 33 | void CallSVC(u32 opcode); |
| 38 | 34 | ||
| 39 | void EatCycles(u32 cycles); | 35 | void Reschedule(const char *reason); |
| 40 | |||
| 41 | void ReSchedule(const char *reason); | ||
| 42 | 36 | ||
| 43 | void Init(); | 37 | void Init(); |
| 44 | 38 | ||
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp new file mode 100644 index 000000000..127c0cfc6 --- /dev/null +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <map> | ||
| 6 | #include <algorithm> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/common.h" | ||
| 10 | |||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/event.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | class Event : public Object { | ||
| 18 | public: | ||
| 19 | const char* GetTypeName() const { return "Event"; } | ||
| 20 | const char* GetName() const { return name.c_str(); } | ||
| 21 | |||
| 22 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } | ||
| 23 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } | ||
| 24 | |||
| 25 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization | ||
| 26 | ResetType reset_type; ///< Current ResetType | ||
| 27 | |||
| 28 | bool locked; ///< Event signal wait | ||
| 29 | bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) | ||
| 30 | std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event | ||
| 31 | std::string name; ///< Name of event (optional) | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Wait for kernel object to synchronize | ||
| 35 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 36 | * @return Result of operation, 0 on success, otherwise error code | ||
| 37 | */ | ||
| 38 | Result WaitSynchronization(bool* wait) { | ||
| 39 | *wait = locked; | ||
| 40 | if (locked) { | ||
| 41 | Handle thread = GetCurrentThreadHandle(); | ||
| 42 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 43 | waiting_threads.push_back(thread); | ||
| 44 | } | ||
| 45 | Kernel::WaitCurrentThread(WAITTYPE_EVENT); | ||
| 46 | } | ||
| 47 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | ||
| 48 | locked = true; | ||
| 49 | } | ||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Hackish function to set an events permanent lock state, used to pass through synch blocks | ||
| 56 | * @param handle Handle to event to change | ||
| 57 | * @param permanent_locked Boolean permanent locked value to set event | ||
| 58 | * @return Result of operation, 0 on success, otherwise error code | ||
| 59 | */ | ||
| 60 | Result SetPermanentLock(Handle handle, const bool permanent_locked) { | ||
| 61 | Event* evt = g_object_pool.GetFast<Event>(handle); | ||
| 62 | _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||
| 63 | |||
| 64 | evt->permanent_locked = permanent_locked; | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Changes whether an event is locked or not | ||
| 70 | * @param handle Handle to event to change | ||
| 71 | * @param locked Boolean locked value to set event | ||
| 72 | * @return Result of operation, 0 on success, otherwise error code | ||
| 73 | */ | ||
| 74 | Result SetEventLocked(const Handle handle, const bool locked) { | ||
| 75 | Event* evt = g_object_pool.GetFast<Event>(handle); | ||
| 76 | _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||
| 77 | |||
| 78 | if (!evt->permanent_locked) { | ||
| 79 | evt->locked = locked; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Signals an event | ||
| 86 | * @param handle Handle to event to signal | ||
| 87 | * @return Result of operation, 0 on success, otherwise error code | ||
| 88 | */ | ||
| 89 | Result SignalEvent(const Handle handle) { | ||
| 90 | Event* evt = g_object_pool.GetFast<Event>(handle); | ||
| 91 | _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||
| 92 | |||
| 93 | // Resume threads waiting for event to signal | ||
| 94 | bool event_caught = false; | ||
| 95 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { | ||
| 96 | ResumeThreadFromWait( evt->waiting_threads[i]); | ||
| 97 | |||
| 98 | // If any thread is signalled awake by this event, assume the event was "caught" and reset | ||
| 99 | // the event. This will result in the next thread waiting on the event to block. Otherwise, | ||
| 100 | // the event will not be reset, and the next thread to call WaitSynchronization on it will | ||
| 101 | // not block. Not sure if this is correct behavior, but it seems to work. | ||
| 102 | event_caught = true; | ||
| 103 | } | ||
| 104 | evt->waiting_threads.clear(); | ||
| 105 | |||
| 106 | if (!evt->permanent_locked) { | ||
| 107 | evt->locked = event_caught; | ||
| 108 | } | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Clears an event | ||
| 114 | * @param handle Handle to event to clear | ||
| 115 | * @return Result of operation, 0 on success, otherwise error code | ||
| 116 | */ | ||
| 117 | Result ClearEvent(Handle handle) { | ||
| 118 | Event* evt = g_object_pool.GetFast<Event>(handle); | ||
| 119 | _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); | ||
| 120 | |||
| 121 | if (!evt->permanent_locked) { | ||
| 122 | evt->locked = true; | ||
| 123 | } | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Creates an event | ||
| 129 | * @param handle Reference to handle for the newly created mutex | ||
| 130 | * @param reset_type ResetType describing how to create event | ||
| 131 | * @param name Optional name of event | ||
| 132 | * @return Newly created Event object | ||
| 133 | */ | ||
| 134 | Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 135 | Event* evt = new Event; | ||
| 136 | |||
| 137 | handle = Kernel::g_object_pool.Create(evt); | ||
| 138 | |||
| 139 | evt->locked = true; | ||
| 140 | evt->permanent_locked = false; | ||
| 141 | evt->reset_type = evt->intitial_reset_type = reset_type; | ||
| 142 | evt->name = name; | ||
| 143 | |||
| 144 | return evt; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Creates an event | ||
| 149 | * @param reset_type ResetType describing how to create event | ||
| 150 | * @param name Optional name of event | ||
| 151 | * @return Handle to newly created Event object | ||
| 152 | */ | ||
| 153 | Handle CreateEvent(const ResetType reset_type, const std::string& name) { | ||
| 154 | Handle handle; | ||
| 155 | Event* evt = CreateEvent(handle, reset_type, name); | ||
| 156 | return handle; | ||
| 157 | } | ||
| 158 | |||
| 159 | } // namespace | ||
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h new file mode 100644 index 000000000..c39b33180 --- /dev/null +++ b/src/core/hle/kernel/event.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/hle/kernel/kernel.h" | ||
| 10 | #include "core/hle/svc.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Changes whether an event is locked or not | ||
| 16 | * @param handle Handle to event to change | ||
| 17 | * @param locked Boolean locked value to set event | ||
| 18 | * @return Result of operation, 0 on success, otherwise error code | ||
| 19 | */ | ||
| 20 | Result SetEventLocked(const Handle handle, const bool locked); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Hackish function to set an events permanent lock state, used to pass through synch blocks | ||
| 24 | * @param handle Handle to event to change | ||
| 25 | * @param permanent_locked Boolean permanent locked value to set event | ||
| 26 | * @return Result of operation, 0 on success, otherwise error code | ||
| 27 | */ | ||
| 28 | Result SetPermanentLock(Handle handle, const bool permanent_locked); | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Signals an event | ||
| 32 | * @param handle Handle to event to signal | ||
| 33 | * @return Result of operation, 0 on success, otherwise error code | ||
| 34 | */ | ||
| 35 | Result SignalEvent(const Handle handle); | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Clears an event | ||
| 39 | * @param handle Handle to event to clear | ||
| 40 | * @return Result of operation, 0 on success, otherwise error code | ||
| 41 | */ | ||
| 42 | Result ClearEvent(Handle handle); | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Creates an event | ||
| 46 | * @param reset_type ResetType describing how to create event | ||
| 47 | * @param name Optional name of event | ||
| 48 | * @return Handle to newly created Event object | ||
| 49 | */ | ||
| 50 | Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); | ||
| 51 | |||
| 52 | } // namespace | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index de80de893..cda183add 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | // Licensed under GPLv2 | 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string.h> | 5 | #include <string.h> |
| 8 | 6 | ||
| 9 | #include "common/common.h" | 7 | #include "common/common.h" |
| @@ -14,6 +12,7 @@ | |||
| 14 | 12 | ||
| 15 | namespace Kernel { | 13 | namespace Kernel { |
| 16 | 14 | ||
| 15 | Handle g_main_thread = 0; | ||
| 17 | ObjectPool g_object_pool; | 16 | ObjectPool g_object_pool; |
| 18 | 17 | ||
| 19 | ObjectPool::ObjectPool() { | 18 | ObjectPool::ObjectPool() { |
| @@ -127,16 +126,20 @@ Object* ObjectPool::CreateByIDType(int type) { | |||
| 127 | 126 | ||
| 128 | default: | 127 | default: |
| 129 | ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); | 128 | ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); |
| 130 | return NULL; | 129 | return nullptr; |
| 131 | } | 130 | } |
| 132 | } | 131 | } |
| 133 | 132 | ||
| 133 | /// Initialize the kernel | ||
| 134 | void Init() { | 134 | void Init() { |
| 135 | Kernel::ThreadingInit(); | 135 | Kernel::ThreadingInit(); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | /// Shutdown the kernel | ||
| 138 | void Shutdown() { | 139 | void Shutdown() { |
| 139 | Kernel::ThreadingShutdown(); | 140 | Kernel::ThreadingShutdown(); |
| 141 | |||
| 142 | g_object_pool.Clear(); // Free all kernel objects | ||
| 140 | } | 143 | } |
| 141 | 144 | ||
| 142 | /** | 145 | /** |
| @@ -150,7 +153,7 @@ bool LoadExec(u32 entry_point) { | |||
| 150 | Core::g_app_core->SetPC(entry_point); | 153 | Core::g_app_core->SetPC(entry_point); |
| 151 | 154 | ||
| 152 | // 0x30 is the typical main thread priority I've seen used so far | 155 | // 0x30 is the typical main thread priority I've seen used so far |
| 153 | Handle thread = Kernel::SetupMainThread(0x30); | 156 | g_main_thread = Kernel::SetupMainThread(0x30); |
| 154 | 157 | ||
| 155 | return true; | 158 | return true; |
| 156 | } | 159 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7cd79c2c4..3f15da0ac 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -11,6 +11,11 @@ typedef s32 Result; | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | enum KernelHandle { | ||
| 15 | CurrentThread = 0xFFFF8000, | ||
| 16 | CurrentProcess = 0xFFFF8001, | ||
| 17 | }; | ||
| 18 | |||
| 14 | enum class HandleType : u32 { | 19 | enum class HandleType : u32 { |
| 15 | Unknown = 0, | 20 | Unknown = 0, |
| 16 | Port = 1, | 21 | Port = 1, |
| @@ -39,9 +44,26 @@ class Object : NonCopyable { | |||
| 39 | public: | 44 | public: |
| 40 | virtual ~Object() {} | 45 | virtual ~Object() {} |
| 41 | Handle GetHandle() const { return handle; } | 46 | Handle GetHandle() const { return handle; } |
| 42 | virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } | 47 | virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } |
| 43 | virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } | 48 | virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } |
| 44 | virtual Kernel::HandleType GetHandleType() const = 0; | 49 | virtual Kernel::HandleType GetHandleType() const = 0; |
| 50 | |||
| 51 | /** | ||
| 52 | * Synchronize kernel object | ||
| 53 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 54 | * @return Result of operation, 0 on success, otherwise error code | ||
| 55 | */ | ||
| 56 | virtual Result SyncRequest(bool* wait) { | ||
| 57 | ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); | ||
| 58 | return -1; | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Wait for kernel object to synchronize | ||
| 63 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 64 | * @return Result of operation, 0 on success, otherwise error code | ||
| 65 | */ | ||
| 66 | virtual Result WaitSynchronization(bool* wait) = 0; | ||
| 45 | }; | 67 | }; |
| 46 | 68 | ||
| 47 | class ObjectPool : NonCopyable { | 69 | class ObjectPool : NonCopyable { |
| @@ -143,6 +165,13 @@ private: | |||
| 143 | }; | 165 | }; |
| 144 | 166 | ||
| 145 | extern ObjectPool g_object_pool; | 167 | extern ObjectPool g_object_pool; |
| 168 | extern Handle g_main_thread; | ||
| 169 | |||
| 170 | /// Initialize the kernel | ||
| 171 | void Init(); | ||
| 172 | |||
| 173 | /// Shutdown the kernel | ||
| 174 | void Shutdown(); | ||
| 146 | 175 | ||
| 147 | /** | 176 | /** |
| 148 | * Loads executable stored at specified address | 177 | * Loads executable stored at specified address |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 019efbc78..1ccf1eb73 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -8,21 +8,51 @@ | |||
| 8 | #include "common/common.h" | 8 | #include "common/common.h" |
| 9 | 9 | ||
| 10 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/mutex.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| 14 | 15 | ||
| 15 | class Mutex : public Object { | 16 | class Mutex : public Object { |
| 16 | public: | 17 | public: |
| 17 | const char* GetTypeName() { return "Mutex"; } | 18 | const char* GetTypeName() const { return "Mutex"; } |
| 19 | const char* GetName() const { return name.c_str(); } | ||
| 18 | 20 | ||
| 19 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } | 21 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } |
| 20 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } | 22 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } |
| 21 | 23 | ||
| 22 | bool initial_locked; ///< Initial lock state when mutex was created | 24 | bool initial_locked; ///< Initial lock state when mutex was created |
| 23 | bool locked; ///< Current locked state | 25 | bool locked; ///< Current locked state |
| 24 | Handle lock_thread; ///< Handle to thread that currently has mutex | 26 | Handle lock_thread; ///< Handle to thread that currently has mutex |
| 25 | std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex | 27 | std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex |
| 28 | std::string name; ///< Name of mutex (optional) | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Synchronize kernel object | ||
| 32 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 33 | * @return Result of operation, 0 on success, otherwise error code | ||
| 34 | */ | ||
| 35 | Result SyncRequest(bool* wait) { | ||
| 36 | // TODO(bunnei): ImplementMe | ||
| 37 | locked = true; | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Wait for kernel object to synchronize | ||
| 43 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 44 | * @return Result of operation, 0 on success, otherwise error code | ||
| 45 | */ | ||
| 46 | Result WaitSynchronization(bool* wait) { | ||
| 47 | // TODO(bunnei): ImplementMe | ||
| 48 | *wait = locked; | ||
| 49 | |||
| 50 | if (locked) { | ||
| 51 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX); | ||
| 52 | } | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | } | ||
| 26 | }; | 56 | }; |
| 27 | 57 | ||
| 28 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 58 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -70,10 +100,10 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { | |||
| 70 | bool ReleaseMutex(Mutex* mutex) { | 100 | bool ReleaseMutex(Mutex* mutex) { |
| 71 | MutexEraseLock(mutex); | 101 | MutexEraseLock(mutex); |
| 72 | bool woke_threads = false; | 102 | bool woke_threads = false; |
| 73 | auto iter = mutex->waiting_threads.begin(); | ||
| 74 | 103 | ||
| 75 | // Find the next waiting thread for the mutex... | 104 | // Find the next waiting thread for the mutex... |
| 76 | while (!woke_threads && !mutex->waiting_threads.empty()) { | 105 | while (!woke_threads && !mutex->waiting_threads.empty()) { |
| 106 | std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); | ||
| 77 | woke_threads |= ReleaseMutexForThread(mutex, *iter); | 107 | woke_threads |= ReleaseMutexForThread(mutex, *iter); |
| 78 | mutex->waiting_threads.erase(iter); | 108 | mutex->waiting_threads.erase(iter); |
| 79 | } | 109 | } |
| @@ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) { | |||
| 91 | */ | 121 | */ |
| 92 | Result ReleaseMutex(Handle handle) { | 122 | Result ReleaseMutex(Handle handle) { |
| 93 | Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); | 123 | Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); |
| 124 | |||
| 125 | _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!"); | ||
| 126 | |||
| 94 | if (!ReleaseMutex(mutex)) { | 127 | if (!ReleaseMutex(mutex)) { |
| 95 | return -1; | 128 | return -1; |
| 96 | } | 129 | } |
| @@ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) { | |||
| 101 | * Creates a mutex | 134 | * Creates a mutex |
| 102 | * @param handle Reference to handle for the newly created mutex | 135 | * @param handle Reference to handle for the newly created mutex |
| 103 | * @param initial_locked Specifies if the mutex should be locked initially | 136 | * @param initial_locked Specifies if the mutex should be locked initially |
| 137 | * @param name Optional name of mutex | ||
| 138 | * @return Pointer to new Mutex object | ||
| 104 | */ | 139 | */ |
| 105 | Mutex* CreateMutex(Handle& handle, bool initial_locked) { | 140 | Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { |
| 106 | Mutex* mutex = new Mutex; | 141 | Mutex* mutex = new Mutex; |
| 107 | handle = Kernel::g_object_pool.Create(mutex); | 142 | handle = Kernel::g_object_pool.Create(mutex); |
| 108 | 143 | ||
| 109 | mutex->locked = mutex->initial_locked = initial_locked; | 144 | mutex->locked = mutex->initial_locked = initial_locked; |
| 145 | mutex->name = name; | ||
| 110 | 146 | ||
| 111 | // Acquire mutex with current thread if initialized as locked... | 147 | // Acquire mutex with current thread if initialized as locked... |
| 112 | if (mutex->locked) { | 148 | if (mutex->locked) { |
| @@ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) { | |||
| 122 | /** | 158 | /** |
| 123 | * Creates a mutex | 159 | * Creates a mutex |
| 124 | * @param initial_locked Specifies if the mutex should be locked initially | 160 | * @param initial_locked Specifies if the mutex should be locked initially |
| 161 | * @param name Optional name of mutex | ||
| 162 | * @return Handle to newly created object | ||
| 125 | */ | 163 | */ |
| 126 | Handle CreateMutex(bool initial_locked) { | 164 | Handle CreateMutex(bool initial_locked, const std::string& name) { |
| 127 | Handle handle; | 165 | Handle handle; |
| 128 | Mutex* mutex = CreateMutex(handle, initial_locked); | 166 | Mutex* mutex = CreateMutex(handle, initial_locked, name); |
| 129 | return handle; | 167 | return handle; |
| 130 | } | 168 | } |
| 131 | 169 | ||
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 871e2e562..7d7b5137e 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h | |||
| @@ -13,14 +13,16 @@ namespace Kernel { | |||
| 13 | /** | 13 | /** |
| 14 | * Releases a mutex | 14 | * Releases a mutex |
| 15 | * @param handle Handle to mutex to release | 15 | * @param handle Handle to mutex to release |
| 16 | * @return Result of operation, 0 on success, otherwise error code | ||
| 16 | */ | 17 | */ |
| 17 | Result ReleaseMutex(Handle handle); | 18 | Result ReleaseMutex(Handle handle); |
| 18 | 19 | ||
| 19 | /** | 20 | /** |
| 20 | * Creates a mutex | 21 | * Creates a mutex |
| 21 | * @param handle Reference to handle for the newly created mutex | ||
| 22 | * @param initial_locked Specifies if the mutex should be locked initially | 22 | * @param initial_locked Specifies if the mutex should be locked initially |
| 23 | * @param name Optional name of mutex | ||
| 24 | * @return Handle to newly created object | ||
| 23 | */ | 25 | */ |
| 24 | Handle CreateMutex(bool initial_locked); | 26 | Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); |
| 25 | 27 | ||
| 26 | } // namespace | 28 | } // namespace |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bf4c8353c..ab5a5559e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | 6 | ||
| 7 | #include <list> | 7 | #include <list> |
| 8 | #include <algorithm> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include <map> | 10 | #include <map> |
| 10 | #include <string> | 11 | #include <string> |
| @@ -24,10 +25,10 @@ namespace Kernel { | |||
| 24 | class Thread : public Kernel::Object { | 25 | class Thread : public Kernel::Object { |
| 25 | public: | 26 | public: |
| 26 | 27 | ||
| 27 | const char* GetName() { return name; } | 28 | const char* GetName() const { return name; } |
| 28 | const char* GetTypeName() { return "Thread"; } | 29 | const char* GetTypeName() const { return "Thread"; } |
| 29 | 30 | ||
| 30 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } | 31 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } |
| 31 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } | 32 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } |
| 32 | 33 | ||
| 33 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } | 34 | inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } |
| @@ -36,6 +37,23 @@ public: | |||
| 36 | inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | 37 | inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } |
| 37 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | 38 | inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |
| 38 | 39 | ||
| 40 | /** | ||
| 41 | * Wait for kernel object to synchronize | ||
| 42 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 43 | * @return Result of operation, 0 on success, otherwise error code | ||
| 44 | */ | ||
| 45 | Result WaitSynchronization(bool* wait) { | ||
| 46 | if (status != THREADSTATUS_DORMANT) { | ||
| 47 | Handle thread = GetCurrentThreadHandle(); | ||
| 48 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 49 | waiting_threads.push_back(thread); | ||
| 50 | } | ||
| 51 | WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); | ||
| 52 | *wait = true; | ||
| 53 | } | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 39 | ThreadContext context; | 57 | ThreadContext context; |
| 40 | 58 | ||
| 41 | u32 status; | 59 | u32 status; |
| @@ -49,6 +67,9 @@ public: | |||
| 49 | s32 processor_id; | 67 | s32 processor_id; |
| 50 | 68 | ||
| 51 | WaitType wait_type; | 69 | WaitType wait_type; |
| 70 | Handle wait_handle; | ||
| 71 | |||
| 72 | std::vector<Handle> waiting_threads; | ||
| 52 | 73 | ||
| 53 | char name[Kernel::MAX_NAME_LENGTH + 1]; | 74 | char name[Kernel::MAX_NAME_LENGTH + 1]; |
| 54 | }; | 75 | }; |
| @@ -62,7 +83,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue; | |||
| 62 | Handle g_current_thread_handle; | 83 | Handle g_current_thread_handle; |
| 63 | Thread* g_current_thread; | 84 | Thread* g_current_thread; |
| 64 | 85 | ||
| 65 | |||
| 66 | /// Gets the current thread | 86 | /// Gets the current thread |
| 67 | inline Thread* GetCurrentThread() { | 87 | inline Thread* GetCurrentThread() { |
| 68 | return g_current_thread; | 88 | return g_current_thread; |
| @@ -94,15 +114,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { | |||
| 94 | memset(&t->context, 0, sizeof(ThreadContext)); | 114 | memset(&t->context, 0, sizeof(ThreadContext)); |
| 95 | 115 | ||
| 96 | t->context.cpu_registers[0] = arg; | 116 | t->context.cpu_registers[0] = arg; |
| 97 | t->context.pc = t->entry_point; | 117 | t->context.pc = t->context.reg_15 = t->entry_point; |
| 98 | t->context.sp = t->stack_top; | 118 | t->context.sp = t->stack_top; |
| 99 | t->context.cpsr = 0x1F; // Usermode | 119 | t->context.cpsr = 0x1F; // Usermode |
| 100 | 120 | ||
| 101 | if (t->current_priority < lowest_priority) { | 121 | if (t->current_priority < lowest_priority) { |
| 102 | t->current_priority = t->initial_priority; | 122 | t->current_priority = t->initial_priority; |
| 103 | } | 123 | } |
| 104 | |||
| 105 | t->wait_type = WAITTYPE_NONE; | 124 | t->wait_type = WAITTYPE_NONE; |
| 125 | t->wait_handle = 0; | ||
| 106 | } | 126 | } |
| 107 | 127 | ||
| 108 | /// Change a thread to "ready" state | 128 | /// Change a thread to "ready" state |
| @@ -122,6 +142,37 @@ void ChangeReadyState(Thread* t, bool ready) { | |||
| 122 | } | 142 | } |
| 123 | } | 143 | } |
| 124 | 144 | ||
| 145 | /// Verify that a thread has not been released from waiting | ||
| 146 | inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { | ||
| 147 | Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||
| 148 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 149 | |||
| 150 | if (type != thread->wait_type || wait_handle != thread->wait_handle) | ||
| 151 | return false; | ||
| 152 | |||
| 153 | return true; | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Stops the current thread | ||
| 157 | void StopThread(Handle handle, const char* reason) { | ||
| 158 | Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||
| 159 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 160 | |||
| 161 | ChangeReadyState(thread, false); | ||
| 162 | thread->status = THREADSTATUS_DORMANT; | ||
| 163 | for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { | ||
| 164 | const Handle waiting_thread = thread->waiting_threads[i]; | ||
| 165 | if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | ||
| 166 | ResumeThreadFromWait(waiting_thread); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | thread->waiting_threads.clear(); | ||
| 170 | |||
| 171 | // Stopped threads are never waiting. | ||
| 172 | thread->wait_type = WAITTYPE_NONE; | ||
| 173 | thread->wait_handle = 0; | ||
| 174 | } | ||
| 175 | |||
| 125 | /// Changes a threads state | 176 | /// Changes a threads state |
| 126 | void ChangeThreadState(Thread* t, ThreadStatus new_status) { | 177 | void ChangeThreadState(Thread* t, ThreadStatus new_status) { |
| 127 | if (!t || t->status == new_status) { | 178 | if (!t || t->status == new_status) { |
| @@ -132,7 +183,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 132 | 183 | ||
| 133 | if (new_status == THREADSTATUS_WAIT) { | 184 | if (new_status == THREADSTATUS_WAIT) { |
| 134 | if (t->wait_type == WAITTYPE_NONE) { | 185 | if (t->wait_type == WAITTYPE_NONE) { |
| 135 | printf("ERROR: Waittype none not allowed here\n"); | 186 | ERROR_LOG(KERNEL, "Waittype none not allowed"); |
| 136 | } | 187 | } |
| 137 | } | 188 | } |
| 138 | } | 189 | } |
| @@ -166,7 +217,7 @@ void SwitchContext(Thread* t) { | |||
| 166 | t->wait_type = WAITTYPE_NONE; | 217 | t->wait_type = WAITTYPE_NONE; |
| 167 | LoadContext(t->context); | 218 | LoadContext(t->context); |
| 168 | } else { | 219 | } else { |
| 169 | SetCurrentThread(NULL); | 220 | SetCurrentThread(nullptr); |
| 170 | } | 221 | } |
| 171 | } | 222 | } |
| 172 | 223 | ||
| @@ -181,26 +232,43 @@ Thread* NextThread() { | |||
| 181 | next = g_thread_ready_queue.pop_first(); | 232 | next = g_thread_ready_queue.pop_first(); |
| 182 | } | 233 | } |
| 183 | if (next == 0) { | 234 | if (next == 0) { |
| 184 | return NULL; | 235 | return nullptr; |
| 185 | } | 236 | } |
| 186 | return Kernel::g_object_pool.GetFast<Thread>(next); | 237 | return Kernel::g_object_pool.GetFast<Thread>(next); |
| 187 | } | 238 | } |
| 188 | 239 | ||
| 189 | /// Puts the current thread in the wait state for the given type | 240 | /// Puts the current thread in the wait state for the given type |
| 190 | void WaitCurrentThread(WaitType wait_type) { | 241 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { |
| 191 | Thread* t = GetCurrentThread(); | 242 | Thread* thread = GetCurrentThread(); |
| 192 | t->wait_type = wait_type; | 243 | thread->wait_type = wait_type; |
| 193 | ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); | 244 | thread->wait_handle = wait_handle; |
| 245 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | ||
| 194 | } | 246 | } |
| 195 | 247 | ||
| 196 | /// Resumes a thread from waiting by marking it as "ready" | 248 | /// Resumes a thread from waiting by marking it as "ready" |
| 197 | void ResumeThreadFromWait(Handle handle) { | 249 | void ResumeThreadFromWait(Handle handle) { |
| 198 | u32 error; | 250 | u32 error; |
| 199 | Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error); | 251 | Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error); |
| 200 | if (t) { | 252 | if (thread) { |
| 201 | t->status &= ~THREADSTATUS_WAIT; | 253 | thread->status &= ~THREADSTATUS_WAIT; |
| 202 | if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 254 | if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 203 | ChangeReadyState(t, true); | 255 | ChangeReadyState(thread, true); |
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | /// Prints the thread queue for debugging purposes | ||
| 261 | void DebugThreadQueue() { | ||
| 262 | Thread* thread = GetCurrentThread(); | ||
| 263 | if (!thread) { | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); | ||
| 267 | for (u32 i = 0; i < g_thread_queue.size(); i++) { | ||
| 268 | Handle handle = g_thread_queue[i]; | ||
| 269 | s32 priority = g_thread_ready_queue.contains(handle); | ||
| 270 | if (priority != -1) { | ||
| 271 | INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); | ||
| 204 | } | 272 | } |
| 205 | } | 273 | } |
| 206 | } | 274 | } |
| @@ -212,32 +280,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio | |||
| 212 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), | 280 | _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), |
| 213 | "CreateThread priority=%d, outside of allowable range!", priority) | 281 | "CreateThread priority=%d, outside of allowable range!", priority) |
| 214 | 282 | ||
| 215 | Thread* t = new Thread; | 283 | Thread* thread = new Thread; |
| 216 | 284 | ||
| 217 | handle = Kernel::g_object_pool.Create(t); | 285 | handle = Kernel::g_object_pool.Create(thread); |
| 218 | 286 | ||
| 219 | g_thread_queue.push_back(handle); | 287 | g_thread_queue.push_back(handle); |
| 220 | g_thread_ready_queue.prepare(priority); | 288 | g_thread_ready_queue.prepare(priority); |
| 221 | 289 | ||
| 222 | t->status = THREADSTATUS_DORMANT; | 290 | thread->status = THREADSTATUS_DORMANT; |
| 223 | t->entry_point = entry_point; | 291 | thread->entry_point = entry_point; |
| 224 | t->stack_top = stack_top; | 292 | thread->stack_top = stack_top; |
| 225 | t->stack_size = stack_size; | 293 | thread->stack_size = stack_size; |
| 226 | t->initial_priority = t->current_priority = priority; | 294 | thread->initial_priority = thread->current_priority = priority; |
| 227 | t->processor_id = processor_id; | 295 | thread->processor_id = processor_id; |
| 228 | t->wait_type = WAITTYPE_NONE; | 296 | thread->wait_type = WAITTYPE_NONE; |
| 229 | 297 | thread->wait_handle = 0; | |
| 230 | strncpy(t->name, name, Kernel::MAX_NAME_LENGTH); | 298 | |
| 231 | t->name[Kernel::MAX_NAME_LENGTH] = '\0'; | 299 | strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH); |
| 232 | 300 | thread->name[Kernel::MAX_NAME_LENGTH] = '\0'; | |
| 233 | return t; | 301 | |
| 302 | return thread; | ||
| 234 | } | 303 | } |
| 235 | 304 | ||
| 236 | /// Creates a new thread - wrapper for external user | 305 | /// Creates a new thread - wrapper for external user |
| 237 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, | 306 | Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, |
| 238 | u32 stack_top, int stack_size) { | 307 | u32 stack_top, int stack_size) { |
| 239 | if (name == NULL) { | 308 | |
| 240 | ERROR_LOG(KERNEL, "CreateThread(): NULL name"); | 309 | if (name == nullptr) { |
| 310 | ERROR_LOG(KERNEL, "CreateThread(): nullptr name"); | ||
| 241 | return -1; | 311 | return -1; |
| 242 | } | 312 | } |
| 243 | if ((u32)stack_size < 0x200) { | 313 | if ((u32)stack_size < 0x200) { |
| @@ -258,20 +328,56 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 | |||
| 258 | return -1; | 328 | return -1; |
| 259 | } | 329 | } |
| 260 | Handle handle; | 330 | Handle handle; |
| 261 | Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, | 331 | Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, |
| 262 | stack_size); | 332 | stack_size); |
| 263 | 333 | ||
| 264 | ResetThread(t, arg, 0); | 334 | ResetThread(thread, arg, 0); |
| 335 | CallThread(thread); | ||
| 336 | |||
| 337 | return handle; | ||
| 338 | } | ||
| 265 | 339 | ||
| 266 | HLE::EatCycles(32000); | 340 | /// Get the priority of the thread specified by handle |
| 341 | u32 GetThreadPriority(const Handle handle) { | ||
| 342 | Thread* thread = g_object_pool.GetFast<Thread>(handle); | ||
| 343 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 344 | return thread->current_priority; | ||
| 345 | } | ||
| 267 | 346 | ||
| 268 | // This won't schedule to the new thread, but it may to one woken from eating cycles. | 347 | /// Set the priority of the thread specified by handle |
| 269 | // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. | 348 | Result SetThreadPriority(Handle handle, s32 priority) { |
| 270 | HLE::ReSchedule("thread created"); | 349 | Thread* thread = nullptr; |
| 350 | if (!handle) { | ||
| 351 | thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? | ||
| 352 | } else { | ||
| 353 | thread = g_object_pool.GetFast<Thread>(handle); | ||
| 354 | } | ||
| 355 | _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||
| 271 | 356 | ||
| 272 | CallThread(t); | 357 | // If priority is invalid, clamp to valid range |
| 273 | 358 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | |
| 274 | return handle; | 359 | s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| 360 | WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); | ||
| 361 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | ||
| 362 | // validity of this | ||
| 363 | priority = new_priority; | ||
| 364 | } | ||
| 365 | |||
| 366 | // Change thread priority | ||
| 367 | s32 old = thread->current_priority; | ||
| 368 | g_thread_ready_queue.remove(old, handle); | ||
| 369 | thread->current_priority = priority; | ||
| 370 | g_thread_ready_queue.prepare(thread->current_priority); | ||
| 371 | |||
| 372 | // Change thread status to "ready" and push to ready queue | ||
| 373 | if (thread->IsRunning()) { | ||
| 374 | thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; | ||
| 375 | } | ||
| 376 | if (thread->IsReady()) { | ||
| 377 | g_thread_ready_queue.push_back(thread->current_priority, handle); | ||
| 378 | } | ||
| 379 | |||
| 380 | return 0; | ||
| 275 | } | 381 | } |
| 276 | 382 | ||
| 277 | /// Sets up the primary application thread | 383 | /// Sets up the primary application thread |
| @@ -279,10 +385,10 @@ Handle SetupMainThread(s32 priority, int stack_size) { | |||
| 279 | Handle handle; | 385 | Handle handle; |
| 280 | 386 | ||
| 281 | // Initialize new "main" thread | 387 | // Initialize new "main" thread |
| 282 | Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, | 388 | Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, |
| 283 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); | 389 | THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); |
| 284 | 390 | ||
| 285 | ResetThread(t, 0, 0); | 391 | ResetThread(thread, 0, 0); |
| 286 | 392 | ||
| 287 | // If running another thread already, set it to "ready" state | 393 | // If running another thread already, set it to "ready" state |
| 288 | Thread* cur = GetCurrentThread(); | 394 | Thread* cur = GetCurrentThread(); |
| @@ -291,24 +397,31 @@ Handle SetupMainThread(s32 priority, int stack_size) { | |||
| 291 | } | 397 | } |
| 292 | 398 | ||
| 293 | // Run new "main" thread | 399 | // Run new "main" thread |
| 294 | SetCurrentThread(t); | 400 | SetCurrentThread(thread); |
| 295 | t->status = THREADSTATUS_RUNNING; | 401 | thread->status = THREADSTATUS_RUNNING; |
| 296 | LoadContext(t->context); | 402 | LoadContext(thread->context); |
| 297 | 403 | ||
| 298 | return handle; | 404 | return handle; |
| 299 | } | 405 | } |
| 300 | 406 | ||
| 407 | |||
| 301 | /// Reschedules to the next available thread (call after current thread is suspended) | 408 | /// Reschedules to the next available thread (call after current thread is suspended) |
| 302 | void Reschedule() { | 409 | void Reschedule() { |
| 303 | Thread* prev = GetCurrentThread(); | 410 | Thread* prev = GetCurrentThread(); |
| 304 | Thread* next = NextThread(); | 411 | Thread* next = NextThread(); |
| 412 | HLE::g_reschedule = false; | ||
| 305 | if (next > 0) { | 413 | if (next > 0) { |
| 414 | INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||
| 415 | |||
| 306 | SwitchContext(next); | 416 | SwitchContext(next); |
| 307 | 417 | ||
| 308 | // Hack - automatically change previous thread (which would have been in "wait" state) to | 418 | // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep |
| 309 | // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to | 419 | // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. |
| 310 | // actually wait for whatever event it is supposed to be waiting on. | 420 | // This results in the current thread yielding on a VBLANK once, and then it will be |
| 311 | ChangeReadyState(prev, true); | 421 | // immediately placed back in the queue for execution. |
| 422 | if (prev->wait_type == WAITTYPE_VBLANK) { | ||
| 423 | ResumeThreadFromWait(prev->GetHandle()); | ||
| 424 | } | ||
| 312 | } | 425 | } |
| 313 | } | 426 | } |
| 314 | 427 | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9628f165d..04914ba90 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -34,7 +34,7 @@ enum WaitType { | |||
| 34 | WAITTYPE_NONE, | 34 | WAITTYPE_NONE, |
| 35 | WAITTYPE_SLEEP, | 35 | WAITTYPE_SLEEP, |
| 36 | WAITTYPE_SEMA, | 36 | WAITTYPE_SEMA, |
| 37 | WAITTYPE_EVENTFLAG, | 37 | WAITTYPE_EVENT, |
| 38 | WAITTYPE_THREADEND, | 38 | WAITTYPE_THREADEND, |
| 39 | WAITTYPE_VBLANK, | 39 | WAITTYPE_VBLANK, |
| 40 | WAITTYPE_MUTEX, | 40 | WAITTYPE_MUTEX, |
| @@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); | |||
| 53 | /// Reschedules to the next available thread (call after current thread is suspended) | 53 | /// Reschedules to the next available thread (call after current thread is suspended) |
| 54 | void Reschedule(); | 54 | void Reschedule(); |
| 55 | 55 | ||
| 56 | /// Puts the current thread in the wait state for the given type | 56 | /// Stops the current thread |
| 57 | void WaitCurrentThread(WaitType wait_type); | 57 | void StopThread(Handle thread, const char* reason); |
| 58 | 58 | ||
| 59 | /// Resumes a thread from waiting by marking it as "ready" | 59 | /// Resumes a thread from waiting by marking it as "ready" |
| 60 | void ResumeThreadFromWait(Handle handle); | 60 | void ResumeThreadFromWait(Handle handle); |
| @@ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle); | |||
| 62 | /// Gets the current thread handle | 62 | /// Gets the current thread handle |
| 63 | Handle GetCurrentThreadHandle(); | 63 | Handle GetCurrentThreadHandle(); |
| 64 | 64 | ||
| 65 | /// Puts the current thread in the wait state for the given type | ||
| 66 | void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | ||
| 67 | |||
| 65 | /// Put current thread in a wait state - on WaitSynchronization | 68 | /// Put current thread in a wait state - on WaitSynchronization |
| 66 | void WaitThread_Synchronization(); | 69 | void WaitThread_Synchronization(); |
| 67 | 70 | ||
| 71 | /// Get the priority of the thread specified by handle | ||
| 72 | u32 GetThreadPriority(const Handle handle); | ||
| 73 | |||
| 74 | /// Set the priority of the thread specified by handle | ||
| 75 | Result SetThreadPriority(Handle handle, s32 priority); | ||
| 76 | |||
| 68 | /// Initialize threading | 77 | /// Initialize threading |
| 69 | void ThreadingInit(); | 78 | void ThreadingInit(); |
| 70 | 79 | ||
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp index 32759a087..a0012b5dd 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/common.h" | 6 | #include "common/common.h" |
| 7 | 7 | ||
| 8 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 9 | #include "core/hle/kernel/event.h" | ||
| 9 | #include "core/hle/kernel/mutex.h" | 10 | #include "core/hle/kernel/mutex.h" |
| 10 | #include "core/hle/service/apt.h" | 11 | #include "core/hle/service/apt.h" |
| 11 | 12 | ||
| @@ -15,96 +16,120 @@ | |||
| 15 | namespace APT_U { | 16 | namespace APT_U { |
| 16 | 17 | ||
| 17 | void Initialize(Service::Interface* self) { | 18 | void Initialize(Service::Interface* self) { |
| 18 | NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize"); | 19 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 20 | DEBUG_LOG(KERNEL, "called"); | ||
| 21 | |||
| 22 | cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle | ||
| 23 | cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle | ||
| 24 | |||
| 25 | Kernel::SetEventLocked(cmd_buff[3], true); | ||
| 26 | Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event | ||
| 27 | |||
| 28 | cmd_buff[1] = 0; // No error | ||
| 19 | } | 29 | } |
| 20 | 30 | ||
| 21 | void GetLockHandle(Service::Interface* self) { | 31 | void GetLockHandle(Service::Interface* self) { |
| 22 | u32* cmd_buff = Service::GetCommandBuffer(); | 32 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 23 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field | 33 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field |
| 24 | cmd_buff[1] = 0; // No error | 34 | cmd_buff[1] = 0; // No error |
| 25 | cmd_buff[5] = Kernel::CreateMutex(false); | 35 | cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); |
| 26 | DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]); | 36 | DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); |
| 37 | } | ||
| 38 | |||
| 39 | void Enable(Service::Interface* self) { | ||
| 40 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 41 | u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? | ||
| 42 | cmd_buff[1] = 0; // No error | ||
| 43 | ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk); | ||
| 44 | } | ||
| 45 | |||
| 46 | void InquireNotification(Service::Interface* self) { | ||
| 47 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 48 | u32 app_id = cmd_buff[2]; | ||
| 49 | cmd_buff[1] = 0; // No error | ||
| 50 | cmd_buff[3] = 0; // Signal type | ||
| 51 | ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id); | ||
| 27 | } | 52 | } |
| 28 | 53 | ||
| 29 | const Interface::FunctionInfo FunctionTable[] = { | 54 | const Interface::FunctionInfo FunctionTable[] = { |
| 30 | {0x00010040, GetLockHandle, "GetLockHandle"}, | 55 | {0x00010040, GetLockHandle, "GetLockHandle"}, |
| 31 | {0x00020080, Initialize, "Initialize"}, | 56 | {0x00020080, Initialize, "Initialize"}, |
| 32 | {0x00030040, NULL, "Enable"}, | 57 | {0x00030040, Enable, "Enable"}, |
| 33 | {0x00040040, NULL, "Finalize"}, | 58 | {0x00040040, nullptr, "Finalize"}, |
| 34 | {0x00050040, NULL, "GetAppletManInfo"}, | 59 | {0x00050040, nullptr, "GetAppletManInfo"}, |
| 35 | {0x00060040, NULL, "GetAppletInfo"}, | 60 | {0x00060040, nullptr, "GetAppletInfo"}, |
| 36 | {0x00070000, NULL, "GetLastSignaledAppletId"}, | 61 | {0x00070000, nullptr, "GetLastSignaledAppletId"}, |
| 37 | {0x00080000, NULL, "CountRegisteredApplet"}, | 62 | {0x00080000, nullptr, "CountRegisteredApplet"}, |
| 38 | {0x00090040, NULL, "IsRegistered"}, | 63 | {0x00090040, nullptr, "IsRegistered"}, |
| 39 | {0x000A0040, NULL, "GetAttribute"}, | 64 | {0x000A0040, nullptr, "GetAttribute"}, |
| 40 | {0x000B0040, NULL, "InquireNotification"}, | 65 | {0x000B0040, InquireNotification, "InquireNotification"}, |
| 41 | {0x000C0104, NULL, "SendParameter"}, | 66 | {0x000C0104, nullptr, "SendParameter"}, |
| 42 | {0x000D0080, NULL, "ReceiveParameter"}, | 67 | {0x000D0080, nullptr, "ReceiveParameter"}, |
| 43 | {0x000E0080, NULL, "GlanceParameter"}, | 68 | {0x000E0080, nullptr, "GlanceParameter"}, |
| 44 | {0x000F0100, NULL, "CancelParameter"}, | 69 | {0x000F0100, nullptr, "CancelParameter"}, |
| 45 | {0x001000C2, NULL, "DebugFunc"}, | 70 | {0x001000C2, nullptr, "DebugFunc"}, |
| 46 | {0x001100C0, NULL, "MapProgramIdForDebug"}, | 71 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, |
| 47 | {0x00120040, NULL, "SetHomeMenuAppletIdForDebug"}, | 72 | {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, |
| 48 | {0x00130000, NULL, "GetPreparationState"}, | 73 | {0x00130000, nullptr, "GetPreparationState"}, |
| 49 | {0x00140040, NULL, "SetPreparationState"}, | 74 | {0x00140040, nullptr, "SetPreparationState"}, |
| 50 | {0x00150140, NULL, "PrepareToStartApplication"}, | 75 | {0x00150140, nullptr, "PrepareToStartApplication"}, |
| 51 | {0x00160040, NULL, "PreloadLibraryApplet"}, | 76 | {0x00160040, nullptr, "PreloadLibraryApplet"}, |
| 52 | {0x00170040, NULL, "FinishPreloadingLibraryApplet"}, | 77 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, |
| 53 | {0x00180040, NULL, "PrepareToStartLibraryApplet"}, | 78 | {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, |
| 54 | {0x00190040, NULL, "PrepareToStartSystemApplet"}, | 79 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, |
| 55 | {0x001A0000, NULL, "PrepareToStartNewestHomeMenu"}, | 80 | {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, |
| 56 | {0x001B00C4, NULL, "StartApplication"}, | 81 | {0x001B00C4, nullptr, "StartApplication"}, |
| 57 | {0x001C0000, NULL, "WakeupApplication"}, | 82 | {0x001C0000, nullptr, "WakeupApplication"}, |
| 58 | {0x001D0000, NULL, "CancelApplication"}, | 83 | {0x001D0000, nullptr, "CancelApplication"}, |
| 59 | {0x001E0084, NULL, "StartLibraryApplet"}, | 84 | {0x001E0084, nullptr, "StartLibraryApplet"}, |
| 60 | {0x001F0084, NULL, "StartSystemApplet"}, | 85 | {0x001F0084, nullptr, "StartSystemApplet"}, |
| 61 | {0x00200044, NULL, "StartNewestHomeMenu"}, | 86 | {0x00200044, nullptr, "StartNewestHomeMenu"}, |
| 62 | {0x00210000, NULL, "OrderToCloseApplication"}, | 87 | {0x00210000, nullptr, "OrderToCloseApplication"}, |
| 63 | {0x00220040, NULL, "PrepareToCloseApplication"}, | 88 | {0x00220040, nullptr, "PrepareToCloseApplication"}, |
| 64 | {0x00230040, NULL, "PrepareToJumpToApplication"}, | 89 | {0x00230040, nullptr, "PrepareToJumpToApplication"}, |
| 65 | {0x00240044, NULL, "JumpToApplication"}, | 90 | {0x00240044, nullptr, "JumpToApplication"}, |
| 66 | {0x002500C0, NULL, "PrepareToCloseLibraryApplet"}, | 91 | {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, |
| 67 | {0x00260000, NULL, "PrepareToCloseSystemApplet"}, | 92 | {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, |
| 68 | {0x00270044, NULL, "CloseApplication"}, | 93 | {0x00270044, nullptr, "CloseApplication"}, |
| 69 | {0x00280044, NULL, "CloseLibraryApplet"}, | 94 | {0x00280044, nullptr, "CloseLibraryApplet"}, |
| 70 | {0x00290044, NULL, "CloseSystemApplet"}, | 95 | {0x00290044, nullptr, "CloseSystemApplet"}, |
| 71 | {0x002A0000, NULL, "OrderToCloseSystemApplet"}, | 96 | {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, |
| 72 | {0x002B0000, NULL, "PrepareToJumpToHomeMenu"}, | 97 | {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, |
| 73 | {0x002C0044, NULL, "JumpToHomeMenu"}, | 98 | {0x002C0044, nullptr, "JumpToHomeMenu"}, |
| 74 | {0x002D0000, NULL, "PrepareToLeaveHomeMenu"}, | 99 | {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, |
| 75 | {0x002E0044, NULL, "LeaveHomeMenu"}, | 100 | {0x002E0044, nullptr, "LeaveHomeMenu"}, |
| 76 | {0x002F0040, NULL, "PrepareToLeaveResidentApplet"}, | 101 | {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, |
| 77 | {0x00300044, NULL, "LeaveResidentApplet"}, | 102 | {0x00300044, nullptr, "LeaveResidentApplet"}, |
| 78 | {0x00310100, NULL, "PrepareToDoApplicationJump"}, | 103 | {0x00310100, nullptr, "PrepareToDoApplicationJump"}, |
| 79 | {0x00320084, NULL, "DoApplicationJump"}, | 104 | {0x00320084, nullptr, "DoApplicationJump"}, |
| 80 | {0x00330000, NULL, "GetProgramIdOnApplicationJump"}, | 105 | {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, |
| 81 | {0x00340084, NULL, "SendDeliverArg"}, | 106 | {0x00340084, nullptr, "SendDeliverArg"}, |
| 82 | {0x00350080, NULL, "ReceiveDeliverArg"}, | 107 | {0x00350080, nullptr, "ReceiveDeliverArg"}, |
| 83 | {0x00360040, NULL, "LoadSysMenuArg"}, | 108 | {0x00360040, nullptr, "LoadSysMenuArg"}, |
| 84 | {0x00370042, NULL, "StoreSysMenuArg"}, | 109 | {0x00370042, nullptr, "StoreSysMenuArg"}, |
| 85 | {0x00380040, NULL, "PreloadResidentApplet"}, | 110 | {0x00380040, nullptr, "PreloadResidentApplet"}, |
| 86 | {0x00390040, NULL, "PrepareToStartResidentApplet"}, | 111 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, |
| 87 | {0x003A0044, NULL, "StartResidentApplet"}, | 112 | {0x003A0044, nullptr, "StartResidentApplet"}, |
| 88 | {0x003B0040, NULL, "CancelLibraryApplet"}, | 113 | {0x003B0040, nullptr, "CancelLibraryApplet"}, |
| 89 | {0x003C0042, NULL, "SendDspSleep"}, | 114 | {0x003C0042, nullptr, "SendDspSleep"}, |
| 90 | {0x003D0042, NULL, "SendDspWakeUp"}, | 115 | {0x003D0042, nullptr, "SendDspWakeUp"}, |
| 91 | {0x003E0080, NULL, "ReplySleepQuery"}, | 116 | {0x003E0080, nullptr, "ReplySleepQuery"}, |
| 92 | {0x003F0040, NULL, "ReplySleepNotificationComplete"}, | 117 | {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, |
| 93 | {0x00400042, NULL, "SendCaptureBufferInfo"}, | 118 | {0x00400042, nullptr, "SendCaptureBufferInfo"}, |
| 94 | {0x00410040, NULL, "ReceiveCaptureBufferInfo"}, | 119 | {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, |
| 95 | {0x00420080, NULL, "SleepSystem"}, | 120 | {0x00420080, nullptr, "SleepSystem"}, |
| 96 | {0x00430040, NULL, "NotifyToWait"}, | 121 | {0x00430040, nullptr, "NotifyToWait"}, |
| 97 | {0x00440000, NULL, "GetSharedFont"}, | 122 | {0x00440000, nullptr, "GetSharedFont"}, |
| 98 | {0x00450040, NULL, "GetWirelessRebootInfo"}, | 123 | {0x00450040, nullptr, "GetWirelessRebootInfo"}, |
| 99 | {0x00460104, NULL, "Wrap"}, | 124 | {0x00460104, nullptr, "Wrap"}, |
| 100 | {0x00470104, NULL, "Unwrap"}, | 125 | {0x00470104, nullptr, "Unwrap"}, |
| 101 | {0x00480100, NULL, "GetProgramInfo"}, | 126 | {0x00480100, nullptr, "GetProgramInfo"}, |
| 102 | {0x00490180, NULL, "Reboot"}, | 127 | {0x00490180, nullptr, "Reboot"}, |
| 103 | {0x004A0040, NULL, "GetCaptureInfo"}, | 128 | {0x004A0040, nullptr, "GetCaptureInfo"}, |
| 104 | {0x004B00C2, NULL, "AppletUtility"}, | 129 | {0x004B00C2, nullptr, "AppletUtility"}, |
| 105 | {0x004C0000, NULL, "SetFatalErrDispMode"}, | 130 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, |
| 106 | {0x004D0080, NULL, "GetAppletProgramInfo"}, | 131 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, |
| 107 | {0x004E0000, NULL, "HardwareResetAsync"}, | 132 | {0x004E0000, nullptr, "HardwareResetAsync"}, |
| 108 | }; | 133 | }; |
| 109 | 134 | ||
| 110 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 135 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index aabcb48db..f75ba75c2 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "core/mem_map.h" | 9 | #include "core/mem_map.h" |
| 10 | #include "core/hle/hle.h" | 10 | #include "core/hle/hle.h" |
| 11 | #include "core/hle/kernel/event.h" | ||
| 11 | #include "core/hle/service/gsp.h" | 12 | #include "core/hle/service/gsp.h" |
| 12 | 13 | ||
| 13 | #include "core/hw/gpu.h" | 14 | #include "core/hw/gpu.h" |
| @@ -60,6 +61,7 @@ void GX_FinishCommand(u32 thread_id) { | |||
| 60 | 61 | ||
| 61 | namespace GSP_GPU { | 62 | namespace GSP_GPU { |
| 62 | 63 | ||
| 64 | Handle g_event_handle = 0; | ||
| 63 | u32 g_thread_id = 0; | 65 | u32 g_thread_id = 0; |
| 64 | 66 | ||
| 65 | enum { | 67 | enum { |
| @@ -96,7 +98,7 @@ void ReadHWRegs(Service::Interface* self) { | |||
| 96 | break; | 98 | break; |
| 97 | 99 | ||
| 98 | default: | 100 | default: |
| 99 | ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); | 101 | ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr); |
| 100 | } | 102 | } |
| 101 | 103 | ||
| 102 | } | 104 | } |
| @@ -104,7 +106,19 @@ void ReadHWRegs(Service::Interface* self) { | |||
| 104 | void RegisterInterruptRelayQueue(Service::Interface* self) { | 106 | void RegisterInterruptRelayQueue(Service::Interface* self) { |
| 105 | u32* cmd_buff = Service::GetCommandBuffer(); | 107 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 106 | u32 flags = cmd_buff[1]; | 108 | u32 flags = cmd_buff[1]; |
| 107 | u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling | 109 | u32 event_handle = cmd_buff[3]; |
| 110 | |||
| 111 | _assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!"); | ||
| 112 | |||
| 113 | g_event_handle = event_handle; | ||
| 114 | |||
| 115 | Kernel::SetEventLocked(event_handle, false); | ||
| 116 | |||
| 117 | // Hack - This function will permanently set the state of the GSP event such that GPU command | ||
| 118 | // synchronization barriers always passthrough. Correct solution would be to set this after the | ||
| 119 | // GPU as processed all queued up commands, but due to the emulator being single-threaded they | ||
| 120 | // will always be ready. | ||
| 121 | Kernel::SetPermanentLock(event_handle, true); | ||
| 108 | 122 | ||
| 109 | cmd_buff[2] = g_thread_id; // ThreadID | 123 | cmd_buff[2] = g_thread_id; // ThreadID |
| 110 | } | 124 | } |
| @@ -150,43 +164,43 @@ void TriggerCmdReqQueue(Service::Interface* self) { | |||
| 150 | } | 164 | } |
| 151 | 165 | ||
| 152 | default: | 166 | default: |
| 153 | ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); | 167 | ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]); |
| 154 | } | 168 | } |
| 155 | 169 | ||
| 156 | GX_FinishCommand(g_thread_id); | 170 | GX_FinishCommand(g_thread_id); |
| 157 | } | 171 | } |
| 158 | 172 | ||
| 159 | const Interface::FunctionInfo FunctionTable[] = { | 173 | const Interface::FunctionInfo FunctionTable[] = { |
| 160 | {0x00010082, NULL, "WriteHWRegs"}, | 174 | {0x00010082, nullptr, "WriteHWRegs"}, |
| 161 | {0x00020084, NULL, "WriteHWRegsWithMask"}, | 175 | {0x00020084, nullptr, "WriteHWRegsWithMask"}, |
| 162 | {0x00030082, NULL, "WriteHWRegRepeat"}, | 176 | {0x00030082, nullptr, "WriteHWRegRepeat"}, |
| 163 | {0x00040080, ReadHWRegs, "ReadHWRegs"}, | 177 | {0x00040080, ReadHWRegs, "ReadHWRegs"}, |
| 164 | {0x00050200, NULL, "SetBufferSwap"}, | 178 | {0x00050200, nullptr, "SetBufferSwap"}, |
| 165 | {0x00060082, NULL, "SetCommandList"}, | 179 | {0x00060082, nullptr, "SetCommandList"}, |
| 166 | {0x000700C2, NULL, "RequestDma"}, | 180 | {0x000700C2, nullptr, "RequestDma"}, |
| 167 | {0x00080082, NULL, "FlushDataCache"}, | 181 | {0x00080082, nullptr, "FlushDataCache"}, |
| 168 | {0x00090082, NULL, "InvalidateDataCache"}, | 182 | {0x00090082, nullptr, "InvalidateDataCache"}, |
| 169 | {0x000A0044, NULL, "RegisterInterruptEvents"}, | 183 | {0x000A0044, nullptr, "RegisterInterruptEvents"}, |
| 170 | {0x000B0040, NULL, "SetLcdForceBlack"}, | 184 | {0x000B0040, nullptr, "SetLcdForceBlack"}, |
| 171 | {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, | 185 | {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, |
| 172 | {0x000D0140, NULL, "SetDisplayTransfer"}, | 186 | {0x000D0140, nullptr, "SetDisplayTransfer"}, |
| 173 | {0x000E0180, NULL, "SetTextureCopy"}, | 187 | {0x000E0180, nullptr, "SetTextureCopy"}, |
| 174 | {0x000F0200, NULL, "SetMemoryFill"}, | 188 | {0x000F0200, nullptr, "SetMemoryFill"}, |
| 175 | {0x00100040, NULL, "SetAxiConfigQoSMode"}, | 189 | {0x00100040, nullptr, "SetAxiConfigQoSMode"}, |
| 176 | {0x00110040, NULL, "SetPerfLogMode"}, | 190 | {0x00110040, nullptr, "SetPerfLogMode"}, |
| 177 | {0x00120000, NULL, "GetPerfLog"}, | 191 | {0x00120000, nullptr, "GetPerfLog"}, |
| 178 | {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, | 192 | {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, |
| 179 | {0x00140000, NULL, "UnregisterInterruptRelayQueue"}, | 193 | {0x00140000, nullptr, "UnregisterInterruptRelayQueue"}, |
| 180 | {0x00150002, NULL, "TryAcquireRight"}, | 194 | {0x00150002, nullptr, "TryAcquireRight"}, |
| 181 | {0x00160042, NULL, "AcquireRight"}, | 195 | {0x00160042, nullptr, "AcquireRight"}, |
| 182 | {0x00170000, NULL, "ReleaseRight"}, | 196 | {0x00170000, nullptr, "ReleaseRight"}, |
| 183 | {0x00180000, NULL, "ImportDisplayCaptureInfo"}, | 197 | {0x00180000, nullptr, "ImportDisplayCaptureInfo"}, |
| 184 | {0x00190000, NULL, "SaveVramSysArea"}, | 198 | {0x00190000, nullptr, "SaveVramSysArea"}, |
| 185 | {0x001A0000, NULL, "RestoreVramSysArea"}, | 199 | {0x001A0000, nullptr, "RestoreVramSysArea"}, |
| 186 | {0x001B0000, NULL, "ResetGpuCore"}, | 200 | {0x001B0000, nullptr, "ResetGpuCore"}, |
| 187 | {0x001C0040, NULL, "SetLedForceOff"}, | 201 | {0x001C0040, nullptr, "SetLedForceOff"}, |
| 188 | {0x001D0040, NULL, "SetTestCommand"}, | 202 | {0x001D0040, nullptr, "SetTestCommand"}, |
| 189 | {0x001E0080, NULL, "SetInternalPriorities"}, | 203 | {0x001E0080, nullptr, "SetInternalPriorities"}, |
| 190 | }; | 204 | }; |
| 191 | 205 | ||
| 192 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 206 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp index 5542e5bf2..ab78f47d7 100644 --- a/src/core/hle/service/hid.cpp +++ b/src/core/hle/service/hid.cpp | |||
| @@ -13,11 +13,11 @@ | |||
| 13 | namespace HID_User { | 13 | namespace HID_User { |
| 14 | 14 | ||
| 15 | const Interface::FunctionInfo FunctionTable[] = { | 15 | const Interface::FunctionInfo FunctionTable[] = { |
| 16 | {0x000A0000, NULL, "GetIPCHandles"}, | 16 | {0x000A0000, nullptr, "GetIPCHandles"}, |
| 17 | {0x00110000, NULL, "EnableAccelerometer"}, | 17 | {0x00110000, nullptr, "EnableAccelerometer"}, |
| 18 | {0x00130000, NULL, "EnableGyroscopeLow"}, | 18 | {0x00130000, nullptr, "EnableGyroscopeLow"}, |
| 19 | {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, | 19 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, |
| 20 | {0x00160000, NULL, "GetGyroscopeLowCalibrateParam"}, | 20 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm.cpp new file mode 100644 index 000000000..48755b6a7 --- /dev/null +++ b/src/core/hle/service/ndm.cpp | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/log.h" | ||
| 6 | |||
| 7 | #include "core/hle/hle.h" | ||
| 8 | #include "core/hle/service/ndm.h" | ||
| 9 | |||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 11 | // Namespace NDM_U | ||
| 12 | |||
| 13 | namespace NDM_U { | ||
| 14 | |||
| 15 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 16 | {0x00060040, nullptr, "SuspendDaemons"}, | ||
| 17 | {0x00080040, nullptr, "DisableWifiUsage"}, | ||
| 18 | {0x00090000, nullptr, "EnableWifiUsage"}, | ||
| 19 | {0x00140040, nullptr, "OverrideDefaultDaemons"}, | ||
| 20 | }; | ||
| 21 | |||
| 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 23 | // Interface class | ||
| 24 | |||
| 25 | Interface::Interface() { | ||
| 26 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||
| 27 | } | ||
| 28 | |||
| 29 | Interface::~Interface() { | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace | ||
diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm.h new file mode 100644 index 000000000..fbe88fb8f --- /dev/null +++ b/src/core/hle/service/ndm.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // Namespace NDM | ||
| 11 | |||
| 12 | // No idea what this is | ||
| 13 | |||
| 14 | namespace NDM_U { | ||
| 15 | |||
| 16 | class Interface : public Service::Interface { | ||
| 17 | public: | ||
| 18 | |||
| 19 | Interface(); | ||
| 20 | |||
| 21 | ~Interface(); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Gets the string port name used by CTROS for the service | ||
| 25 | * @return Port name of service | ||
| 26 | */ | ||
| 27 | const char *GetPortName() const { | ||
| 28 | return "ndm:u"; | ||
| 29 | } | ||
| 30 | |||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 08d0c43ff..4a1ac857e 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -12,13 +12,14 @@ | |||
| 12 | #include "core/hle/service/apt.h" | 12 | #include "core/hle/service/apt.h" |
| 13 | #include "core/hle/service/gsp.h" | 13 | #include "core/hle/service/gsp.h" |
| 14 | #include "core/hle/service/hid.h" | 14 | #include "core/hle/service/hid.h" |
| 15 | #include "core/hle/service/ndm.h" | ||
| 15 | #include "core/hle/service/srv.h" | 16 | #include "core/hle/service/srv.h" |
| 16 | 17 | ||
| 17 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 18 | 19 | ||
| 19 | namespace Service { | 20 | namespace Service { |
| 20 | 21 | ||
| 21 | Manager* g_manager = NULL; ///< Service manager | 22 | Manager* g_manager = nullptr; ///< Service manager |
| 22 | 23 | ||
| 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 24 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 24 | // Service Manager class | 25 | // Service Manager class |
| @@ -55,7 +56,7 @@ Interface* Manager::FetchFromHandle(Handle handle) { | |||
| 55 | Interface* Manager::FetchFromPortName(std::string port_name) { | 56 | Interface* Manager::FetchFromPortName(std::string port_name) { |
| 56 | auto itr = m_port_map.find(port_name); | 57 | auto itr = m_port_map.find(port_name); |
| 57 | if (itr == m_port_map.end()) { | 58 | if (itr == m_port_map.end()) { |
| 58 | return NULL; | 59 | return nullptr; |
| 59 | } | 60 | } |
| 60 | return FetchFromHandle(itr->second); | 61 | return FetchFromHandle(itr->second); |
| 61 | } | 62 | } |
| @@ -72,14 +73,15 @@ void Init() { | |||
| 72 | g_manager->AddService(new APT_U::Interface); | 73 | g_manager->AddService(new APT_U::Interface); |
| 73 | g_manager->AddService(new GSP_GPU::Interface); | 74 | g_manager->AddService(new GSP_GPU::Interface); |
| 74 | g_manager->AddService(new HID_User::Interface); | 75 | g_manager->AddService(new HID_User::Interface); |
| 76 | g_manager->AddService(new NDM_U::Interface); | ||
| 75 | 77 | ||
| 76 | NOTICE_LOG(HLE, "Services initialized OK"); | 78 | NOTICE_LOG(HLE, "initialized OK"); |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 79 | /// Shutdown ServiceManager | 81 | /// Shutdown ServiceManager |
| 80 | void Shutdown() { | 82 | void Shutdown() { |
| 81 | delete g_manager; | 83 | delete g_manager; |
| 82 | NOTICE_LOG(HLE, "Services shutdown OK"); | 84 | NOTICE_LOG(HLE, "shutdown OK"); |
| 83 | } | 85 | } |
| 84 | 86 | ||
| 85 | 87 | ||
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index fab51753f..dcd525727 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -39,8 +39,8 @@ class Interface : public Kernel::Object { | |||
| 39 | friend class Manager; | 39 | friend class Manager; |
| 40 | public: | 40 | public: |
| 41 | 41 | ||
| 42 | const char *GetName() { return GetPortName(); } | 42 | const char *GetName() const { return GetPortName(); } |
| 43 | const char *GetTypeName() { return GetPortName(); } | 43 | const char *GetTypeName() const { return GetPortName(); } |
| 44 | 44 | ||
| 45 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } | 45 | static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } |
| 46 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } | 46 | Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } |
| @@ -76,22 +76,31 @@ public: | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | /** | 78 | /** |
| 79 | * Called when svcSendSyncRequest is called, loads command buffer and executes comand | 79 | * Synchronize kernel object |
| 80 | * @return Return result of svcSendSyncRequest passed back to user app | 80 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 81 | * @return Result of operation, 0 on success, otherwise error code | ||
| 81 | */ | 82 | */ |
| 82 | Result Sync() { | 83 | Result SyncRequest(bool* wait) { |
| 83 | u32* cmd_buff = GetCommandBuffer(); | 84 | u32* cmd_buff = GetCommandBuffer(); |
| 84 | auto itr = m_functions.find(cmd_buff[0]); | 85 | auto itr = m_functions.find(cmd_buff[0]); |
| 85 | 86 | ||
| 86 | if (itr == m_functions.end()) { | 87 | if (itr == m_functions.end()) { |
| 87 | ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!", | 88 | ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X", |
| 88 | GetPortName(), cmd_buff[0]); | 89 | GetPortName(), cmd_buff[0]); |
| 89 | return -1; | 90 | |
| 91 | // TODO(bunnei): Hack - ignore error | ||
| 92 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 93 | cmd_buff[1] = 0; | ||
| 94 | return 0; | ||
| 90 | } | 95 | } |
| 91 | if (itr->second.func == NULL) { | 96 | if (itr->second.func == nullptr) { |
| 92 | ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!", | 97 | ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", |
| 93 | GetPortName(), itr->second.name.c_str()); | 98 | GetPortName(), itr->second.name.c_str()); |
| 94 | return -1; | 99 | |
| 100 | // TODO(bunnei): Hack - ignore error | ||
| 101 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 102 | cmd_buff[1] = 0; | ||
| 103 | return 0; | ||
| 95 | } | 104 | } |
| 96 | 105 | ||
| 97 | itr->second.func(this); | 106 | itr->second.func(this); |
| @@ -99,6 +108,17 @@ public: | |||
| 99 | return 0; // TODO: Implement return from actual function | 108 | return 0; // TODO: Implement return from actual function |
| 100 | } | 109 | } |
| 101 | 110 | ||
| 111 | /** | ||
| 112 | * Wait for kernel object to synchronize | ||
| 113 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 114 | * @return Result of operation, 0 on success, otherwise error code | ||
| 115 | */ | ||
| 116 | Result WaitSynchronization(bool* wait) { | ||
| 117 | // TODO(bunnei): ImplementMe | ||
| 118 | ERROR_LOG(OSHLE, "unimplemented function"); | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 102 | protected: | 122 | protected: |
| 103 | 123 | ||
| 104 | /** | 124 | /** |
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index ff6da8f1c..f45c0efc2 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp | |||
| @@ -5,21 +5,28 @@ | |||
| 5 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 6 | #include "core/hle/service/srv.h" | 6 | #include "core/hle/service/srv.h" |
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | #include "core/hle/kernel/mutex.h" | |
| 9 | 9 | ||
| 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 11 | // Namespace SRV | 11 | // Namespace SRV |
| 12 | 12 | ||
| 13 | namespace SRV { | 13 | namespace SRV { |
| 14 | 14 | ||
| 15 | Handle g_mutex = 0; | ||
| 16 | |||
| 15 | void Initialize(Service::Interface* self) { | 17 | void Initialize(Service::Interface* self) { |
| 16 | NOTICE_LOG(OSHLE, "SRV::Sync - Initialize"); | 18 | DEBUG_LOG(OSHLE, "called"); |
| 19 | if (!g_mutex) { | ||
| 20 | g_mutex = Kernel::CreateMutex(true, "SRV:Lock"); | ||
| 21 | } | ||
| 17 | } | 22 | } |
| 18 | 23 | ||
| 19 | void GetProcSemaphore(Service::Interface* self) { | 24 | void GetProcSemaphore(Service::Interface* self) { |
| 25 | DEBUG_LOG(OSHLE, "called"); | ||
| 20 | // Get process semaphore? | 26 | // Get process semaphore? |
| 21 | u32* cmd_buff = Service::GetCommandBuffer(); | 27 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 22 | cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception | 28 | cmd_buff[1] = 0; // No error |
| 29 | cmd_buff[3] = g_mutex; // Return something... 0 == nullptr, raises an exception | ||
| 23 | } | 30 | } |
| 24 | 31 | ||
| 25 | void GetServiceHandle(Service::Interface* self) { | 32 | void GetServiceHandle(Service::Interface* self) { |
| @@ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) { | |||
| 29 | std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); | 36 | std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); |
| 30 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | 37 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |
| 31 | 38 | ||
| 32 | NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(), | 39 | if (nullptr != service) { |
| 33 | service->GetHandle()); | ||
| 34 | |||
| 35 | if (NULL != service) { | ||
| 36 | cmd_buff[3] = service->GetHandle(); | 40 | cmd_buff[3] = service->GetHandle(); |
| 41 | DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | ||
| 37 | } else { | 42 | } else { |
| 38 | ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str()); | 43 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); |
| 39 | res = -1; | 44 | res = -1; |
| 40 | } | 45 | } |
| 41 | cmd_buff[1] = res; | 46 | cmd_buff[1] = res; |
| 42 | |||
| 43 | //return res; | ||
| 44 | } | 47 | } |
| 45 | 48 | ||
| 46 | const Interface::FunctionInfo FunctionTable[] = { | 49 | const Interface::FunctionInfo FunctionTable[] = { |
| 47 | {0x00010002, Initialize, "Initialize"}, | 50 | {0x00010002, Initialize, "Initialize"}, |
| 48 | {0x00020000, GetProcSemaphore, "GetProcSemaphore"}, | 51 | {0x00020000, GetProcSemaphore, "GetProcSemaphore"}, |
| 49 | {0x00030100, NULL, "RegisterService"}, | 52 | {0x00030100, nullptr, "RegisterService"}, |
| 50 | {0x000400C0, NULL, "UnregisterService"}, | 53 | {0x000400C0, nullptr, "UnregisterService"}, |
| 51 | {0x00050100, GetServiceHandle, "GetServiceHandle"}, | 54 | {0x00050100, GetServiceHandle, "GetServiceHandle"}, |
| 52 | }; | 55 | }; |
| 53 | 56 | ||
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 1e35032ba..81109a2a8 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h | |||
| @@ -26,12 +26,6 @@ public: | |||
| 26 | return "srv:"; | 26 | return "srv:"; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | /** | ||
| 30 | * Called when svcSendSyncRequest is called, loads command buffer and executes comand | ||
| 31 | * @return Return result of svcSendSyncRequest passed back to user app | ||
| 32 | */ | ||
| 33 | Result Sync(); | ||
| 34 | |||
| 35 | }; | 29 | }; |
| 36 | 30 | ||
| 37 | } // namespace | 31 | } // namespace |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 90c05cb74..441d8ce8d 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "core/mem_map.h" | 10 | #include "core/mem_map.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/kernel/event.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/mutex.h" | 14 | #include "core/hle/kernel/mutex.h" |
| 14 | #include "core/hle/kernel/thread.h" | 15 | #include "core/hle/kernel/thread.h" |
| @@ -16,7 +17,6 @@ | |||
| 16 | #include "core/hle/function_wrappers.h" | 17 | #include "core/hle/function_wrappers.h" |
| 17 | #include "core/hle/svc.h" | 18 | #include "core/hle/svc.h" |
| 18 | #include "core/hle/service/service.h" | 19 | #include "core/hle/service/service.h" |
| 19 | #include "core/hle/kernel/thread.h" | ||
| 20 | 20 | ||
| 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 22 | // Namespace SVC | 22 | // Namespace SVC |
| @@ -34,40 +34,32 @@ enum MapMemoryPermission { | |||
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | /// Map application or GSP heap memory | 36 | /// Map application or GSP heap memory |
| 37 | Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | 37 | Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { |
| 38 | u32* outaddr = (u32*)_outaddr; | 38 | DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", |
| 39 | u32 virtual_address = 0x00000000; | ||
| 40 | |||
| 41 | DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | ||
| 42 | operation, addr0, addr1, size, permissions); | 39 | operation, addr0, addr1, size, permissions); |
| 43 | 40 | ||
| 44 | switch (operation) { | 41 | switch (operation) { |
| 45 | 42 | ||
| 46 | // Map normal heap memory | 43 | // Map normal heap memory |
| 47 | case MEMORY_OPERATION_HEAP: | 44 | case MEMORY_OPERATION_HEAP: |
| 48 | virtual_address = Memory::MapBlock_Heap(size, operation, permissions); | 45 | *out_addr = Memory::MapBlock_Heap(size, operation, permissions); |
| 49 | break; | 46 | break; |
| 50 | 47 | ||
| 51 | // Map GSP heap memory | 48 | // Map GSP heap memory |
| 52 | case MEMORY_OPERATION_GSP_HEAP: | 49 | case MEMORY_OPERATION_GSP_HEAP: |
| 53 | virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); | 50 | *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions); |
| 54 | break; | 51 | break; |
| 55 | 52 | ||
| 56 | // Unknown ControlMemory operation | 53 | // Unknown ControlMemory operation |
| 57 | default: | 54 | default: |
| 58 | ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); | 55 | ERROR_LOG(SVC, "unknown operation=0x%08X", operation); |
| 59 | } | 56 | } |
| 60 | if (NULL != outaddr) { | ||
| 61 | *outaddr = virtual_address; | ||
| 62 | } | ||
| 63 | Core::g_app_core->SetReg(1, virtual_address); | ||
| 64 | |||
| 65 | return 0; | 57 | return 0; |
| 66 | } | 58 | } |
| 67 | 59 | ||
| 68 | /// Maps a memory block to specified address | 60 | /// Maps a memory block to specified address |
| 69 | Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { | 61 | Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { |
| 70 | DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | 62 | DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", |
| 71 | memblock, addr, mypermissions, otherpermission); | 63 | memblock, addr, mypermissions, otherpermission); |
| 72 | switch (mypermissions) { | 64 | switch (mypermissions) { |
| 73 | case MEMORY_PERMISSION_NORMAL: | 65 | case MEMORY_PERMISSION_NORMAL: |
| @@ -76,88 +68,146 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper | |||
| 76 | Memory::MapBlock_Shared(memblock, addr, mypermissions); | 68 | Memory::MapBlock_Shared(memblock, addr, mypermissions); |
| 77 | break; | 69 | break; |
| 78 | default: | 70 | default: |
| 79 | ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); | 71 | ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions); |
| 80 | } | 72 | } |
| 81 | return 0; | 73 | return 0; |
| 82 | } | 74 | } |
| 83 | 75 | ||
| 84 | /// Connect to an OS service given the port name, returns the handle to the port to out | 76 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 85 | Result ConnectToPort(void* out, const char* port_name) { | 77 | Result ConnectToPort(Handle* out, const char* port_name) { |
| 86 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | 78 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |
| 87 | if (service) { | 79 | |
| 88 | Core::g_app_core->SetReg(1, service->GetHandle()); | 80 | DEBUG_LOG(SVC, "called port_name=%s", port_name); |
| 89 | } else { | 81 | _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!"); |
| 90 | PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name); | 82 | |
| 91 | } | 83 | *out = service->GetHandle(); |
| 92 | DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); | 84 | |
| 93 | return 0; | 85 | return 0; |
| 94 | } | 86 | } |
| 95 | 87 | ||
| 96 | /// Synchronize to an OS service | 88 | /// Synchronize to an OS service |
| 97 | Result SendSyncRequest(Handle handle) { | 89 | Result SendSyncRequest(Handle handle) { |
| 98 | DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); | 90 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |
| 99 | Service::Interface* service = Service::g_manager->FetchFromHandle(handle); | 91 | |
| 100 | service->Sync(); | 92 | _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); |
| 101 | return 0; | 93 | DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName()); |
| 94 | |||
| 95 | bool wait = false; | ||
| 96 | Result res = object->SyncRequest(&wait); | ||
| 97 | if (wait) { | ||
| 98 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||
| 99 | } | ||
| 100 | |||
| 101 | return res; | ||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /// Close a handle | 104 | /// Close a handle |
| 105 | Result CloseHandle(Handle handle) { | 105 | Result CloseHandle(Handle handle) { |
| 106 | // ImplementMe | 106 | // ImplementMe |
| 107 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); | 107 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); |
| 108 | return 0; | 108 | return 0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | 111 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds |
| 112 | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | 112 | Result WaitSynchronization1(Handle handle, s64 nano_seconds) { |
| 113 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", | 113 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this |
| 114 | handle, nano_seconds); | 114 | bool wait = false; |
| 115 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | 115 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated |
| 116 | return 0; | 116 | |
| 117 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | ||
| 118 | |||
| 119 | DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(), | ||
| 120 | object->GetName(), nano_seconds); | ||
| 121 | |||
| 122 | _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); | ||
| 123 | |||
| 124 | Result res = object->WaitSynchronization(&wait); | ||
| 125 | |||
| 126 | // Check for next thread to schedule | ||
| 127 | if (wait) { | ||
| 128 | HLE::Reschedule(__func__); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | return res; | ||
| 117 | } | 133 | } |
| 118 | 134 | ||
| 119 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 135 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 120 | Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { | 136 | Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, |
| 121 | s32* out = (s32*)_out; | 137 | s64 nano_seconds) { |
| 122 | Handle* handles = (Handle*)_handles; | 138 | // TODO(bunnei): Do something with nano_seconds, currently ignoring this |
| 139 | bool unlock_all = true; | ||
| 140 | bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | ||
| 123 | 141 | ||
| 124 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", | 142 | DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", |
| 125 | handle_count, (wait_all ? "true" : "false"), nano_seconds); | 143 | handle_count, (wait_all ? "true" : "false"), nano_seconds); |
| 126 | 144 | ||
| 127 | for (u32 i = 0; i < handle_count; i++) { | 145 | // Iterate through each handle, synchronize kernel object |
| 128 | DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); | 146 | for (s32 i = 0; i < handle_count; i++) { |
| 147 | bool wait = false; | ||
| 148 | Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); | ||
| 149 | |||
| 150 | _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object " | ||
| 151 | "is nullptr!", handles[i]); | ||
| 152 | |||
| 153 | DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(), | ||
| 154 | object->GetName()); | ||
| 155 | |||
| 156 | Result res = object->WaitSynchronization(&wait); | ||
| 157 | |||
| 158 | if (!wait && !wait_all) { | ||
| 159 | *out = i; | ||
| 160 | return 0; | ||
| 161 | } else { | ||
| 162 | unlock_all = false; | ||
| 163 | } | ||
| 129 | } | 164 | } |
| 130 | Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | 165 | |
| 166 | if (wait_all && unlock_all) { | ||
| 167 | *out = handle_count; | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | // Check for next thread to schedule | ||
| 172 | HLE::Reschedule(__func__); | ||
| 173 | |||
| 131 | return 0; | 174 | return 0; |
| 132 | } | 175 | } |
| 133 | 176 | ||
| 134 | /// Create an address arbiter (to allocate access to shared resources) | 177 | /// Create an address arbiter (to allocate access to shared resources) |
| 135 | Result CreateAddressArbiter(void* arbiter) { | 178 | Result CreateAddressArbiter(void* arbiter) { |
| 136 | // ImplementMe | 179 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); |
| 137 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); | ||
| 138 | Core::g_app_core->SetReg(1, 0xFABBDADD); | 180 | Core::g_app_core->SetReg(1, 0xFABBDADD); |
| 139 | return 0; | 181 | return 0; |
| 140 | } | 182 | } |
| 141 | 183 | ||
| 184 | /// Arbitrate address | ||
| 185 | Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) { | ||
| 186 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called"); | ||
| 187 | ArbitrationType type = (ArbitrationType)_type; | ||
| 188 | Memory::Write32(addr, type); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 142 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 192 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| 143 | void OutputDebugString(const char* string) { | 193 | void OutputDebugString(const char* string) { |
| 144 | NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); | 194 | OS_LOG(SVC, "%s", string); |
| 145 | } | 195 | } |
| 146 | 196 | ||
| 147 | /// Get resource limit | 197 | /// Get resource limit |
| 148 | Result GetResourceLimit(void* resource_limit, Handle process) { | 198 | Result GetResourceLimit(Handle* resource_limit, Handle process) { |
| 149 | // With regards to proceess values: | 199 | // With regards to proceess values: |
| 150 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for | 200 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for |
| 151 | // the current KThread. | 201 | // the current KThread. |
| 152 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); | 202 | *resource_limit = 0xDEADBEEF; |
| 153 | Core::g_app_core->SetReg(1, 0xDEADBEEF); | 203 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process); |
| 154 | return 0; | 204 | return 0; |
| 155 | } | 205 | } |
| 156 | 206 | ||
| 157 | /// Get resource limit current values | 207 | /// Get resource limit current values |
| 158 | Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { | 208 | Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, |
| 159 | //s64* values = (s64*)_values; | 209 | s32 name_count) { |
| 160 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", | 210 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", |
| 161 | resource_limit, names, name_count); | 211 | resource_limit, names, name_count); |
| 162 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now | 212 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now |
| 163 | return 0; | 213 | return 0; |
| @@ -180,179 +230,234 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p | |||
| 180 | 230 | ||
| 181 | Core::g_app_core->SetReg(1, thread); | 231 | Core::g_app_core->SetReg(1, thread); |
| 182 | 232 | ||
| 183 | DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 233 | DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 184 | "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point, | 234 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |
| 185 | name.c_str(), arg, stack_top, priority, processor_id, thread); | 235 | name.c_str(), arg, stack_top, priority, processor_id, thread); |
| 186 | 236 | ||
| 187 | return 0; | 237 | return 0; |
| 188 | } | 238 | } |
| 189 | 239 | ||
| 240 | /// Called when a thread exits | ||
| 241 | u32 ExitThread() { | ||
| 242 | Handle thread = Kernel::GetCurrentThreadHandle(); | ||
| 243 | |||
| 244 | DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C | ||
| 245 | |||
| 246 | Kernel::StopThread(thread, __func__); | ||
| 247 | HLE::Reschedule(__func__); | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /// Gets the priority for the specified thread | ||
| 252 | Result GetThreadPriority(s32* priority, Handle handle) { | ||
| 253 | *priority = Kernel::GetThreadPriority(handle); | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Sets the priority for the specified thread | ||
| 258 | Result SetThreadPriority(Handle handle, s32 priority) { | ||
| 259 | return Kernel::SetThreadPriority(handle, priority); | ||
| 260 | } | ||
| 261 | |||
| 190 | /// Create a mutex | 262 | /// Create a mutex |
| 191 | Result CreateMutex(void* _mutex, u32 initial_locked) { | 263 | Result CreateMutex(Handle* mutex, u32 initial_locked) { |
| 192 | Handle* mutex = (Handle*)_mutex; | ||
| 193 | *mutex = Kernel::CreateMutex((initial_locked != 0)); | 264 | *mutex = Kernel::CreateMutex((initial_locked != 0)); |
| 194 | Core::g_app_core->SetReg(1, *mutex); | 265 | DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X", |
| 195 | DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X", | ||
| 196 | initial_locked ? "true" : "false", *mutex); | 266 | initial_locked ? "true" : "false", *mutex); |
| 197 | return 0; | 267 | return 0; |
| 198 | } | 268 | } |
| 199 | 269 | ||
| 200 | /// Release a mutex | 270 | /// Release a mutex |
| 201 | Result ReleaseMutex(Handle handle) { | 271 | Result ReleaseMutex(Handle handle) { |
| 202 | DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); | 272 | DEBUG_LOG(SVC, "called handle=0x%08X", handle); |
| 273 | _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); | ||
| 203 | Kernel::ReleaseMutex(handle); | 274 | Kernel::ReleaseMutex(handle); |
| 204 | return 0; | 275 | return 0; |
| 205 | } | 276 | } |
| 206 | 277 | ||
| 207 | /// Get current thread ID | 278 | /// Get current thread ID |
| 208 | Result GetThreadId(void* thread_id, u32 thread) { | 279 | Result GetThreadId(u32* thread_id, Handle thread) { |
| 209 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); | 280 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread); |
| 210 | return 0; | 281 | return 0; |
| 211 | } | 282 | } |
| 212 | 283 | ||
| 213 | /// Query memory | 284 | /// Query memory |
| 214 | Result QueryMemory(void *_info, void *_out, u32 addr) { | 285 | Result QueryMemory(void* info, void* out, u32 addr) { |
| 215 | MemoryInfo* info = (MemoryInfo*) _info; | 286 | ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); |
| 216 | PageInfo* out = (PageInfo*) _out; | ||
| 217 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr); | ||
| 218 | return 0; | 287 | return 0; |
| 219 | } | 288 | } |
| 220 | 289 | ||
| 221 | /// Create an event | 290 | /// Create an event |
| 222 | Result CreateEvent(void* _event, u32 reset_type) { | 291 | Result CreateEvent(Handle* evt, u32 reset_type) { |
| 223 | Handle* event = (Handle*)_event; | 292 | *evt = Kernel::CreateEvent((ResetType)reset_type); |
| 224 | DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); | 293 | DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X", |
| 225 | Core::g_app_core->SetReg(1, 0xBADC0DE0); | 294 | reset_type, *evt); |
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | /// Duplicates a kernel handle | ||
| 299 | Result DuplicateHandle(Handle* out, Handle handle) { | ||
| 300 | DEBUG_LOG(SVC, "called handle=0x%08X", handle); | ||
| 301 | |||
| 302 | // Translate kernel handles -> real handles | ||
| 303 | if (handle == Kernel::CurrentThread) { | ||
| 304 | handle = Kernel::GetCurrentThreadHandle(); | ||
| 305 | } | ||
| 306 | _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), | ||
| 307 | "(UNIMPLEMENTED) process handle duplication!"); | ||
| 308 | |||
| 309 | // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate. | ||
| 310 | *out = handle; | ||
| 311 | |||
| 226 | return 0; | 312 | return 0; |
| 227 | } | 313 | } |
| 228 | 314 | ||
| 315 | /// Signals an event | ||
| 316 | Result SignalEvent(Handle evt) { | ||
| 317 | Result res = Kernel::SignalEvent(evt); | ||
| 318 | DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||
| 319 | return res; | ||
| 320 | } | ||
| 321 | |||
| 322 | /// Clears an event | ||
| 323 | Result ClearEvent(Handle evt) { | ||
| 324 | Result res = Kernel::ClearEvent(evt); | ||
| 325 | DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||
| 326 | return res; | ||
| 327 | } | ||
| 328 | |||
| 329 | /// Sleep the current thread | ||
| 330 | void SleepThread(s64 nanoseconds) { | ||
| 331 | DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); | ||
| 332 | } | ||
| 333 | |||
| 229 | const HLE::FunctionDef SVC_Table[] = { | 334 | const HLE::FunctionDef SVC_Table[] = { |
| 230 | {0x00, NULL, "Unknown"}, | 335 | {0x00, nullptr, "Unknown"}, |
| 231 | {0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"}, | 336 | {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"}, |
| 232 | {0x02, WrapI_VVU<QueryMemory>, "QueryMemory"}, | 337 | {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"}, |
| 233 | {0x03, NULL, "ExitProcess"}, | 338 | {0x03, nullptr, "ExitProcess"}, |
| 234 | {0x04, NULL, "GetProcessAffinityMask"}, | 339 | {0x04, nullptr, "GetProcessAffinityMask"}, |
| 235 | {0x05, NULL, "SetProcessAffinityMask"}, | 340 | {0x05, nullptr, "SetProcessAffinityMask"}, |
| 236 | {0x06, NULL, "GetProcessIdealProcessor"}, | 341 | {0x06, nullptr, "GetProcessIdealProcessor"}, |
| 237 | {0x07, NULL, "SetProcessIdealProcessor"}, | 342 | {0x07, nullptr, "SetProcessIdealProcessor"}, |
| 238 | {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, | 343 | {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, |
| 239 | {0x09, NULL, "ExitThread"}, | 344 | {0x09, HLE::Wrap<ExitThread>, "ExitThread"}, |
| 240 | {0x0A, NULL, "SleepThread"}, | 345 | {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, |
| 241 | {0x0B, NULL, "GetThreadPriority"}, | 346 | {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, |
| 242 | {0x0C, NULL, "SetThreadPriority"}, | 347 | {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, |
| 243 | {0x0D, NULL, "GetThreadAffinityMask"}, | 348 | {0x0D, nullptr, "GetThreadAffinityMask"}, |
| 244 | {0x0E, NULL, "SetThreadAffinityMask"}, | 349 | {0x0E, nullptr, "SetThreadAffinityMask"}, |
| 245 | {0x0F, NULL, "GetThreadIdealProcessor"}, | 350 | {0x0F, nullptr, "GetThreadIdealProcessor"}, |
| 246 | {0x10, NULL, "SetThreadIdealProcessor"}, | 351 | {0x10, nullptr, "SetThreadIdealProcessor"}, |
| 247 | {0x11, NULL, "GetCurrentProcessorNumber"}, | 352 | {0x11, nullptr, "GetCurrentProcessorNumber"}, |
| 248 | {0x12, NULL, "Run"}, | 353 | {0x12, nullptr, "Run"}, |
| 249 | {0x13, WrapI_VU<CreateMutex>, "CreateMutex"}, | 354 | {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"}, |
| 250 | {0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"}, | 355 | {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, |
| 251 | {0x15, NULL, "CreateSemaphore"}, | 356 | {0x15, nullptr, "CreateSemaphore"}, |
| 252 | {0x16, NULL, "ReleaseSemaphore"}, | 357 | {0x16, nullptr, "ReleaseSemaphore"}, |
| 253 | {0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, | 358 | {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, |
| 254 | {0x18, NULL, "SignalEvent"}, | 359 | {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, |
| 255 | {0x19, NULL, "ClearEvent"}, | 360 | {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, |
| 256 | {0x1A, NULL, "CreateTimer"}, | 361 | {0x1A, nullptr, "CreateTimer"}, |
| 257 | {0x1B, NULL, "SetTimer"}, | 362 | {0x1B, nullptr, "SetTimer"}, |
| 258 | {0x1C, NULL, "CancelTimer"}, | 363 | {0x1C, nullptr, "CancelTimer"}, |
| 259 | {0x1D, NULL, "ClearTimer"}, | 364 | {0x1D, nullptr, "ClearTimer"}, |
| 260 | {0x1E, NULL, "CreateMemoryBlock"}, | 365 | {0x1E, nullptr, "CreateMemoryBlock"}, |
| 261 | {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, | 366 | {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, |
| 262 | {0x20, NULL, "UnmapMemoryBlock"}, | 367 | {0x20, nullptr, "UnmapMemoryBlock"}, |
| 263 | {0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"}, | 368 | {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, |
| 264 | {0x22, NULL, "ArbitrateAddress"}, | 369 | {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"}, |
| 265 | {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, | 370 | {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"}, |
| 266 | {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, | 371 | {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, |
| 267 | {0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"}, | 372 | {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"}, |
| 268 | {0x26, NULL, "SignalAndWait"}, | 373 | {0x26, nullptr, "SignalAndWait"}, |
| 269 | {0x27, NULL, "DuplicateHandle"}, | 374 | {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, |
| 270 | {0x28, NULL, "GetSystemTick"}, | 375 | {0x28, nullptr, "GetSystemTick"}, |
| 271 | {0x29, NULL, "GetHandleInfo"}, | 376 | {0x29, nullptr, "GetHandleInfo"}, |
| 272 | {0x2A, NULL, "GetSystemInfo"}, | 377 | {0x2A, nullptr, "GetSystemInfo"}, |
| 273 | {0x2B, NULL, "GetProcessInfo"}, | 378 | {0x2B, nullptr, "GetProcessInfo"}, |
| 274 | {0x2C, NULL, "GetThreadInfo"}, | 379 | {0x2C, nullptr, "GetThreadInfo"}, |
| 275 | {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, | 380 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, |
| 276 | {0x2E, NULL, "SendSyncRequest1"}, | 381 | {0x2E, nullptr, "SendSyncRequest1"}, |
| 277 | {0x2F, NULL, "SendSyncRequest2"}, | 382 | {0x2F, nullptr, "SendSyncRequest2"}, |
| 278 | {0x30, NULL, "SendSyncRequest3"}, | 383 | {0x30, nullptr, "SendSyncRequest3"}, |
| 279 | {0x31, NULL, "SendSyncRequest4"}, | 384 | {0x31, nullptr, "SendSyncRequest4"}, |
| 280 | {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, | 385 | {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, |
| 281 | {0x33, NULL, "OpenProcess"}, | 386 | {0x33, nullptr, "OpenProcess"}, |
| 282 | {0x34, NULL, "OpenThread"}, | 387 | {0x34, nullptr, "OpenThread"}, |
| 283 | {0x35, NULL, "GetProcessId"}, | 388 | {0x35, nullptr, "GetProcessId"}, |
| 284 | {0x36, NULL, "GetProcessIdOfThread"}, | 389 | {0x36, nullptr, "GetProcessIdOfThread"}, |
| 285 | {0x37, WrapI_VU<GetThreadId>, "GetThreadId"}, | 390 | {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, |
| 286 | {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, | 391 | {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, |
| 287 | {0x39, NULL, "GetResourceLimitLimitValues"}, | 392 | {0x39, nullptr, "GetResourceLimitLimitValues"}, |
| 288 | {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, | 393 | {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, |
| 289 | {0x3B, NULL, "GetThreadContext"}, | 394 | {0x3B, nullptr, "GetThreadContext"}, |
| 290 | {0x3C, NULL, "Break"}, | 395 | {0x3C, nullptr, "Break"}, |
| 291 | {0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"}, | 396 | {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, |
| 292 | {0x3E, NULL, "ControlPerformanceCounter"}, | 397 | {0x3E, nullptr, "ControlPerformanceCounter"}, |
| 293 | {0x3F, NULL, "Unknown"}, | 398 | {0x3F, nullptr, "Unknown"}, |
| 294 | {0x40, NULL, "Unknown"}, | 399 | {0x40, nullptr, "Unknown"}, |
| 295 | {0x41, NULL, "Unknown"}, | 400 | {0x41, nullptr, "Unknown"}, |
| 296 | {0x42, NULL, "Unknown"}, | 401 | {0x42, nullptr, "Unknown"}, |
| 297 | {0x43, NULL, "Unknown"}, | 402 | {0x43, nullptr, "Unknown"}, |
| 298 | {0x44, NULL, "Unknown"}, | 403 | {0x44, nullptr, "Unknown"}, |
| 299 | {0x45, NULL, "Unknown"}, | 404 | {0x45, nullptr, "Unknown"}, |
| 300 | {0x46, NULL, "Unknown"}, | 405 | {0x46, nullptr, "Unknown"}, |
| 301 | {0x47, NULL, "CreatePort"}, | 406 | {0x47, nullptr, "CreatePort"}, |
| 302 | {0x48, NULL, "CreateSessionToPort"}, | 407 | {0x48, nullptr, "CreateSessionToPort"}, |
| 303 | {0x49, NULL, "CreateSession"}, | 408 | {0x49, nullptr, "CreateSession"}, |
| 304 | {0x4A, NULL, "AcceptSession"}, | 409 | {0x4A, nullptr, "AcceptSession"}, |
| 305 | {0x4B, NULL, "ReplyAndReceive1"}, | 410 | {0x4B, nullptr, "ReplyAndReceive1"}, |
| 306 | {0x4C, NULL, "ReplyAndReceive2"}, | 411 | {0x4C, nullptr, "ReplyAndReceive2"}, |
| 307 | {0x4D, NULL, "ReplyAndReceive3"}, | 412 | {0x4D, nullptr, "ReplyAndReceive3"}, |
| 308 | {0x4E, NULL, "ReplyAndReceive4"}, | 413 | {0x4E, nullptr, "ReplyAndReceive4"}, |
| 309 | {0x4F, NULL, "ReplyAndReceive"}, | 414 | {0x4F, nullptr, "ReplyAndReceive"}, |
| 310 | {0x50, NULL, "BindInterrupt"}, | 415 | {0x50, nullptr, "BindInterrupt"}, |
| 311 | {0x51, NULL, "UnbindInterrupt"}, | 416 | {0x51, nullptr, "UnbindInterrupt"}, |
| 312 | {0x52, NULL, "InvalidateProcessDataCache"}, | 417 | {0x52, nullptr, "InvalidateProcessDataCache"}, |
| 313 | {0x53, NULL, "StoreProcessDataCache"}, | 418 | {0x53, nullptr, "StoreProcessDataCache"}, |
| 314 | {0x54, NULL, "FlushProcessDataCache"}, | 419 | {0x54, nullptr, "FlushProcessDataCache"}, |
| 315 | {0x55, NULL, "StartInterProcessDma"}, | 420 | {0x55, nullptr, "StartInterProcessDma"}, |
| 316 | {0x56, NULL, "StopDma"}, | 421 | {0x56, nullptr, "StopDma"}, |
| 317 | {0x57, NULL, "GetDmaState"}, | 422 | {0x57, nullptr, "GetDmaState"}, |
| 318 | {0x58, NULL, "RestartDma"}, | 423 | {0x58, nullptr, "RestartDma"}, |
| 319 | {0x59, NULL, "Unknown"}, | 424 | {0x59, nullptr, "Unknown"}, |
| 320 | {0x5A, NULL, "Unknown"}, | 425 | {0x5A, nullptr, "Unknown"}, |
| 321 | {0x5B, NULL, "Unknown"}, | 426 | {0x5B, nullptr, "Unknown"}, |
| 322 | {0x5C, NULL, "Unknown"}, | 427 | {0x5C, nullptr, "Unknown"}, |
| 323 | {0x5D, NULL, "Unknown"}, | 428 | {0x5D, nullptr, "Unknown"}, |
| 324 | {0x5E, NULL, "Unknown"}, | 429 | {0x5E, nullptr, "Unknown"}, |
| 325 | {0x5F, NULL, "Unknown"}, | 430 | {0x5F, nullptr, "Unknown"}, |
| 326 | {0x60, NULL, "DebugActiveProcess"}, | 431 | {0x60, nullptr, "DebugActiveProcess"}, |
| 327 | {0x61, NULL, "BreakDebugProcess"}, | 432 | {0x61, nullptr, "BreakDebugProcess"}, |
| 328 | {0x62, NULL, "TerminateDebugProcess"}, | 433 | {0x62, nullptr, "TerminateDebugProcess"}, |
| 329 | {0x63, NULL, "GetProcessDebugEvent"}, | 434 | {0x63, nullptr, "GetProcessDebugEvent"}, |
| 330 | {0x64, NULL, "ContinueDebugEvent"}, | 435 | {0x64, nullptr, "ContinueDebugEvent"}, |
| 331 | {0x65, NULL, "GetProcessList"}, | 436 | {0x65, nullptr, "GetProcessList"}, |
| 332 | {0x66, NULL, "GetThreadList"}, | 437 | {0x66, nullptr, "GetThreadList"}, |
| 333 | {0x67, NULL, "GetDebugThreadContext"}, | 438 | {0x67, nullptr, "GetDebugThreadContext"}, |
| 334 | {0x68, NULL, "SetDebugThreadContext"}, | 439 | {0x68, nullptr, "SetDebugThreadContext"}, |
| 335 | {0x69, NULL, "QueryDebugProcessMemory"}, | 440 | {0x69, nullptr, "QueryDebugProcessMemory"}, |
| 336 | {0x6A, NULL, "ReadProcessMemory"}, | 441 | {0x6A, nullptr, "ReadProcessMemory"}, |
| 337 | {0x6B, NULL, "WriteProcessMemory"}, | 442 | {0x6B, nullptr, "WriteProcessMemory"}, |
| 338 | {0x6C, NULL, "SetHardwareBreakPoint"}, | 443 | {0x6C, nullptr, "SetHardwareBreakPoint"}, |
| 339 | {0x6D, NULL, "GetDebugThreadParam"}, | 444 | {0x6D, nullptr, "GetDebugThreadParam"}, |
| 340 | {0x6E, NULL, "Unknown"}, | 445 | {0x6E, nullptr, "Unknown"}, |
| 341 | {0x6F, NULL, "Unknown"}, | 446 | {0x6F, nullptr, "Unknown"}, |
| 342 | {0x70, NULL, "ControlProcessMemory"}, | 447 | {0x70, nullptr, "ControlProcessMemory"}, |
| 343 | {0x71, NULL, "MapProcessMemory"}, | 448 | {0x71, nullptr, "MapProcessMemory"}, |
| 344 | {0x72, NULL, "UnmapProcessMemory"}, | 449 | {0x72, nullptr, "UnmapProcessMemory"}, |
| 345 | {0x73, NULL, "Unknown"}, | 450 | {0x73, nullptr, "Unknown"}, |
| 346 | {0x74, NULL, "Unknown"}, | 451 | {0x74, nullptr, "Unknown"}, |
| 347 | {0x75, NULL, "Unknown"}, | 452 | {0x75, nullptr, "Unknown"}, |
| 348 | {0x76, NULL, "TerminateProcess"}, | 453 | {0x76, nullptr, "TerminateProcess"}, |
| 349 | {0x77, NULL, "Unknown"}, | 454 | {0x77, nullptr, "Unknown"}, |
| 350 | {0x78, NULL, "CreateResourceLimit"}, | 455 | {0x78, nullptr, "CreateResourceLimit"}, |
| 351 | {0x79, NULL, "Unknown"}, | 456 | {0x79, nullptr, "Unknown"}, |
| 352 | {0x7A, NULL, "Unknown"}, | 457 | {0x7A, nullptr, "Unknown"}, |
| 353 | {0x7B, NULL, "Unknown"}, | 458 | {0x7B, nullptr, "Unknown"}, |
| 354 | {0x7C, NULL, "KernelSetState"}, | 459 | {0x7C, nullptr, "KernelSetState"}, |
| 355 | {0x7D, NULL, "QueryProcessMemory"}, | 460 | {0x7D, nullptr, "QueryProcessMemory"}, |
| 356 | }; | 461 | }; |
| 357 | 462 | ||
| 358 | void Register() { | 463 | void Register() { |
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index 5c35977d1..1d125faf6 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h | |||
| @@ -29,6 +29,10 @@ struct ThreadContext { | |||
| 29 | u32 fpu_registers[32]; | 29 | u32 fpu_registers[32]; |
| 30 | u32 fpscr; | 30 | u32 fpscr; |
| 31 | u32 fpexc; | 31 | u32 fpexc; |
| 32 | |||
| 33 | // These are not part of native ThreadContext, but needed by emu | ||
| 34 | u32 reg_15; | ||
| 35 | u32 mode; | ||
| 32 | }; | 36 | }; |
| 33 | 37 | ||
| 34 | enum ResetType { | 38 | enum ResetType { |
| @@ -38,6 +42,15 @@ enum ResetType { | |||
| 38 | RESETTYPE_MAX_BIT = (1u << 31), | 42 | RESETTYPE_MAX_BIT = (1u << 31), |
| 39 | }; | 43 | }; |
| 40 | 44 | ||
| 45 | enum ArbitrationType { | ||
| 46 | ARBITRATIONTYPE_SIGNAL, | ||
| 47 | ARBITRATIONTYPE_WAIT_IF_LESS_THAN, | ||
| 48 | ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN, | ||
| 49 | ARBITRATIONTYPE_WAIT_IF_LESS_THAN_WITH_TIMEOUT, | ||
| 50 | ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN_WITH_TIMEOUT, | ||
| 51 | ARBITRATIONTYPE_MAX_BIT = (1u << 31) | ||
| 52 | }; | ||
| 53 | |||
| 41 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 54 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 42 | // Namespace SVC | 55 | // Namespace SVC |
| 43 | 56 | ||
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index ec2d0e156..f0ca4eada 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -17,8 +17,6 @@ namespace GPU { | |||
| 17 | 17 | ||
| 18 | Registers g_regs; | 18 | Registers g_regs; |
| 19 | 19 | ||
| 20 | static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second | ||
| 21 | |||
| 22 | u64 g_last_ticks = 0; ///< Last CPU ticks | 20 | u64 g_last_ticks = 0; ///< Last CPU ticks |
| 23 | 21 | ||
| 24 | /** | 22 | /** |
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index f26f25e98..3314ba989 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h | |||
| @@ -8,6 +8,9 @@ | |||
| 8 | 8 | ||
| 9 | namespace GPU { | 9 | namespace GPU { |
| 10 | 10 | ||
| 11 | static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second | ||
| 12 | static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame | ||
| 13 | |||
| 11 | struct Registers { | 14 | struct Registers { |
| 12 | enum Id : u32 { | 15 | enum Id : u32 { |
| 13 | FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left | 16 | FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left |
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 86e9eaa20..ab014a596 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp | |||
| @@ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) { | |||
| 86 | var = *((const T*)&g_vram[vaddr & VRAM_MASK]); | 86 | var = *((const T*)&g_vram[vaddr & VRAM_MASK]); |
| 87 | 87 | ||
| 88 | } else { | 88 | } else { |
| 89 | //_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); | 89 | ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); |
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| @@ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) { | |||
| 136 | 136 | ||
| 137 | // Error out... | 137 | // Error out... |
| 138 | } else { | 138 | } else { |
| 139 | _assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, | 139 | ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); |
| 140 | data, vaddr); | ||
| 141 | } | 140 | } |
| 142 | } | 141 | } |
| 143 | 142 | ||
diff --git a/src/core/system.cpp b/src/core/system.cpp index c77092327..9b1e96888 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/system.h" | 8 | #include "core/system.h" |
| 9 | #include "core/hw/hw.h" | 9 | #include "core/hw/hw.h" |
| 10 | #include "core/hle/hle.h" | 10 | #include "core/hle/hle.h" |
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 11 | 12 | ||
| 12 | #include "video_core/video_core.h" | 13 | #include "video_core/video_core.h" |
| 13 | 14 | ||
| @@ -26,6 +27,7 @@ void Init(EmuWindow* emu_window) { | |||
| 26 | HLE::Init(); | 27 | HLE::Init(); |
| 27 | CoreTiming::Init(); | 28 | CoreTiming::Init(); |
| 28 | VideoCore::Init(emu_window); | 29 | VideoCore::Init(emu_window); |
| 30 | Kernel::Init(); | ||
| 29 | } | 31 | } |
| 30 | 32 | ||
| 31 | void RunLoopFor(int cycles) { | 33 | void RunLoopFor(int cycles) { |
| @@ -42,6 +44,7 @@ void Shutdown() { | |||
| 42 | HLE::Shutdown(); | 44 | HLE::Shutdown(); |
| 43 | CoreTiming::Shutdown(); | 45 | CoreTiming::Shutdown(); |
| 44 | VideoCore::Shutdown(); | 46 | VideoCore::Shutdown(); |
| 47 | Kernel::Shutdown(); | ||
| 45 | g_ctr_file_system.Shutdown(); | 48 | g_ctr_file_system.Shutdown(); |
| 46 | } | 49 | } |
| 47 | 50 | ||