Merge branch 'threading' of https://github.com/bunnei/citra into threading

Conflicts:
	src/core/hle/function_wrappers.h
This commit is contained in:
inspuration 2014-06-10 15:10:43 -04:00
commit df6e6a4f60
40 changed files with 1265 additions and 1233 deletions

View file

@ -48,7 +48,7 @@ void DisassemblerWidget::Init()
unsigned int curInstAddr = base_addr; unsigned int curInstAddr = base_addr;
char result[255]; char result[255];
for (int i = 0; i < 10000; i++) // fixed for now for (int i = 0; i < 20000; i++) // fixed for now
{ {
disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result);
model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0'))));

View file

@ -259,14 +259,17 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
switch (Level) switch (Level)
{ {
case OS_LEVEL: // light yellow
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case NOTICE_LEVEL: // light green case NOTICE_LEVEL: // light green
Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break; break;
case ERROR_LEVEL: // light red case ERROR_LEVEL: // light red
Color = FOREGROUND_RED | FOREGROUND_INTENSITY; Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
break; break;
case WARNING_LEVEL: // light yellow case WARNING_LEVEL: // light purple
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break; break;
case INFO_LEVEL: // cyan case INFO_LEVEL: // cyan
Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
@ -278,15 +281,8 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
break; break;
} }
if (strlen(Text) > 10)
{
// First 10 chars white
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL);
Text += 10;
}
SetConsoleTextAttribute(hConsole, Color); SetConsoleTextAttribute(hConsole, Color);
WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); printf(Text);
#else #else
char ColorAttr[16] = ""; char ColorAttr[16] = "";
char ResetAttr[16] = ""; char ResetAttr[16] = "";

View file

@ -7,11 +7,14 @@
#define LOGGING #define LOGGING
#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. enum {
#define ERROR_LEVEL 2 // Critical errors OS_LEVEL, // Printed by the emulated operating system
#define WARNING_LEVEL 3 // Something is suspicious. NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports.
#define INFO_LEVEL 4 // General information. ERROR_LEVEL, // Critical errors
#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. WARNING_LEVEL, // Something is suspicious.
INFO_LEVEL, // General information.
DEBUG_LEVEL, // Detailed debugging - might make things slow.
};
namespace LogTypes namespace LogTypes
{ {
@ -70,6 +73,7 @@ enum LOG_TYPE {
// FIXME: should this be removed? // FIXME: should this be removed?
enum LOG_LEVELS { enum LOG_LEVELS {
LOS = OS_LEVEL,
LNOTICE = NOTICE_LEVEL, LNOTICE = NOTICE_LEVEL,
LERROR = ERROR_LEVEL, LERROR = ERROR_LEVEL,
LWARNING = WARNING_LEVEL, LWARNING = WARNING_LEVEL,
@ -82,31 +86,34 @@ enum LOG_LEVELS {
} // namespace } // namespace
void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,
const char *file, int line, const char *fmt, ...) const char* function, const char* fmt, ...)
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((format(printf, 5, 6))) __attribute__((format(printf, 6, 7)))
#endif #endif
; ;
#if defined LOGGING || defined _DEBUG || defined DEBUGFAST #if defined LOGGING || defined _DEBUG || defined DEBUGFAST
#define MAX_LOGLEVEL DEBUG_LEVEL #define MAX_LOGLEVEL LDEBUG
#else #else
#ifndef MAX_LOGLEVEL #ifndef MAX_LOGLEVEL
#define MAX_LOGLEVEL WARNING_LEVEL #define MAX_LOGLEVEL LWARNING
#endif // loglevel #endif // loglevel
#endif // logging #endif // logging
#ifdef GEKKO #ifdef _WIN32
#define GENERIC_LOG(t, v, ...) #ifndef __func__
#else #define __func__ __FUNCTION__
// Let the compiler optimize this out #endif
#define GENERIC_LOG(t, v, ...) { \
if (v <= MAX_LOGLEVEL) \
GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \
}
#endif #endif
// Let the compiler optimize this out
#define GENERIC_LOG(t, v, ...) { \
if (v <= LogTypes::MAX_LOGLEVEL) \
GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \
}
#define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0)
#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) #define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0)
#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) #define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0)
#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) #define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0)

View file

@ -10,14 +10,16 @@
#include "common/thread.h" #include "common/thread.h"
#include "common/file_util.h" #include "common/file_util.h"
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
const char *file, int line, const char* fmt, ...) const char* function, const char* fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
if (LogManager::GetInstance())
if (LogManager::GetInstance()) {
LogManager::GetInstance()->Log(level, type, LogManager::GetInstance()->Log(level, type,
file, line, fmt, args); file, line, function, fmt, args);
}
va_end(args); va_end(args);
} }
@ -88,6 +90,8 @@ LogManager::LogManager()
m_Log[i]->AddListener(m_debuggerLog); m_Log[i]->AddListener(m_debuggerLog);
#endif #endif
} }
m_consoleLog->Open();
} }
LogManager::~LogManager() LogManager::~LogManager()
@ -107,8 +111,8 @@ LogManager::~LogManager()
delete m_debuggerLog; delete m_debuggerLog;
} }
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
const char *file, int line, const char *format, va_list args) int line, const char* function, const char *fmt, va_list args)
{ {
char temp[MAX_MSGLEN]; char temp[MAX_MSGLEN];
char msg[MAX_MSGLEN * 2]; char msg[MAX_MSGLEN * 2];
@ -117,17 +121,15 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
return; return;
CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
static const char level_to_char[7] = "ONEWID";
sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
level_to_char[(int)level], log->GetShortName(), function, temp);
static const char level_to_char[7] = "-NEWID";
sprintf(msg, "%s %s:%u %c[%s]: %s\n",
Common::Timer::GetTimeFormatted().c_str(),
file, line, level_to_char[(int)level],
log->GetShortName(), temp);
#ifdef ANDROID #ifdef ANDROID
Host_SysMessage(msg); Host_SysMessage(msg);
#endif #endif
printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this
log->Trigger(level, msg); log->Trigger(level, msg);
} }
@ -147,7 +149,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena
{ {
strncpy(m_fullName, fullName, 128); strncpy(m_fullName, fullName, 128);
strncpy(m_shortName, shortName, 32); strncpy(m_shortName, shortName, 32);
m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; m_level = LogTypes::MAX_LOGLEVEL;
} }
// LogContainer // LogContainer

View file

@ -97,10 +97,10 @@ private:
~LogManager(); ~LogManager();
public: public:
static u32 GetMaxLevel() { return MAX_LOGLEVEL; } static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; }
void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
const char *file, int line, const char *fmt, va_list args); const char* function, const char *fmt, va_list args);
void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
{ {

View file

@ -34,12 +34,14 @@ set(SRCS core.cpp
hle/config_mem.cpp hle/config_mem.cpp
hle/coprocessor.cpp hle/coprocessor.cpp
hle/svc.cpp hle/svc.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp hle/kernel/kernel.cpp
hle/kernel/mutex.cpp hle/kernel/mutex.cpp
hle/kernel/thread.cpp hle/kernel/thread.cpp
hle/service/apt.cpp hle/service/apt.cpp
hle/service/gsp.cpp hle/service/gsp.cpp
hle/service/hid.cpp hle/service/hid.cpp
hle/service/ndm.cpp
hle/service/service.cpp hle/service/service.cpp
hle/service/srv.cpp hle/service/srv.cpp
hw/hw.cpp hw/hw.cpp

View file

@ -89,6 +89,9 @@ public:
*/ */
virtual void LoadContext(const ThreadContext& ctx) = 0; virtual void LoadContext(const ThreadContext& ctx) = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
/// Getter for num_instructions /// Getter for num_instructions
u64 GetNumInstructions() { u64 GetNumInstructions() {
return num_instructions; return num_instructions;

View file

@ -98,7 +98,7 @@ u64 ARM_Interpreter::GetTicks() const {
* @param num_instructions Number of instructions to executes * @param num_instructions Number of instructions to executes
*/ */
void ARM_Interpreter::ExecuteInstructions(int num_instructions) { void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
state->NumInstrsToExecute = num_instructions; state->NumInstrsToExecute = num_instructions - 1;
ARMul_Emulate32(state); ARMul_Emulate32(state);
} }
@ -118,6 +118,9 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
ctx.fpscr = state->VFP[1]; ctx.fpscr = state->VFP[1];
ctx.fpexc = state->VFP[2]; ctx.fpexc = state->VFP[2];
ctx.reg_15 = state->Reg[15];
ctx.mode = state->NextInstr;
} }
/** /**
@ -137,6 +140,11 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
state->VFP[1] = ctx.fpscr; state->VFP[1] = ctx.fpscr;
state->VFP[2] = ctx.fpexc; state->VFP[2] = ctx.fpexc;
state->Reg[15] = ctx.pc; state->Reg[15] = ctx.reg_15;
state->NextInstr = RESUME; state->NextInstr = ctx.mode;
}
/// Prepare core for thread reschedule (if needed to correctly handle state)
void ARM_Interpreter::PrepareReschedule() {
state->NumInstrsToExecute = 0;
} }

View file

@ -72,6 +72,9 @@ public:
*/ */
void LoadContext(const ThreadContext& ctx); void LoadContext(const ThreadContext& ctx);
/// Prepare core for thread reschedule (if needed to correctly handle state)
void PrepareReschedule();
protected: protected:
/** /**

View file

@ -4456,6 +4456,7 @@ ARMul_Emulate26 (ARMul_State * state)
} }
/* Drop through. */ /* Drop through. */
case 0xe0:
case 0xe4: case 0xe4:
case 0xe6: case 0xe6:
case 0xe8: case 0xe8:
@ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state)
/* Co-Processor Register Transfers (MRC) and Data Ops. */ /* Co-Processor Register Transfers (MRC) and Data Ops. */
case 0xe0:
case 0xe1: case 0xe1:
case 0xe3: case 0xe3:
case 0xe5: case 0xe5:
@ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state)
case 0xfd: case 0xfd:
case 0xfe: case 0xfe:
case 0xff: case 0xff:
if (instr == ARMul_ABORTWORD
&& state->AbortAddr == pc) {
/* A prefetch abort. */
XScale_set_fsr_far (state,
ARMul_CP15_R5_MMU_EXCPT,
pc);
ARMul_Abort (state,
ARMul_PrefetchAbortV);
break;
}
//sky_pref_t* pref = get_skyeye_pref();
//if(pref->user_mode_sim){
// ARMul_OSHandleSWI (state, BITS (0, 23));
// break;
//}
HLE::CallSVC(instr); HLE::CallSVC(instr);
ARMul_Abort (state, ARMul_SWIV);
break; break;
} }
} }

View file

@ -9,21 +9,24 @@
#include "core/core.h" #include "core/core.h"
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/hw/hw.h" #include "core/hw/hw.h"
#include "core/hw/lcd.h"
#include "core/arm/disassembler/arm_disasm.h" #include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/interpreter/arm_interpreter.h" #include "core/arm/interpreter/arm_interpreter.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
namespace Core { namespace Core {
ARM_Disasm* g_disasm = NULL; ///< ARM disassembler u64 g_last_ticks = 0; ///< Last CPU ticks
ARM_Interface* g_app_core = NULL; ///< ARM11 application core ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler
ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core ARM_Interface* g_app_core = nullptr; ///< ARM11 application core
ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
/// Run the core CPU loop /// Run the core CPU loop
void RunLoop() { void RunLoop() {
for (;;){ for (;;){
g_app_core->Run(100); g_app_core->Run(LCD::kFrameTicks);
HW::Update(); HW::Update();
Kernel::Reschedule(); Kernel::Reschedule();
} }
@ -32,9 +35,15 @@ void RunLoop() {
/// Step the CPU one instruction /// Step the CPU one instruction
void SingleStep() { void SingleStep() {
g_app_core->Step(); g_app_core->Step();
// Update and reschedule after approx. 1 frame
u64 current_ticks = Core::g_app_core->GetTicks();
if ((current_ticks - g_last_ticks) >= LCD::kFrameTicks || HLE::g_reschedule) {
g_last_ticks = current_ticks;
HW::Update(); HW::Update();
Kernel::Reschedule(); Kernel::Reschedule();
} }
}
/// Halt the core /// Halt the core
void Halt(const char *msg) { void Halt(const char *msg) {
@ -54,6 +63,8 @@ int Init() {
g_app_core = new ARM_Interpreter(); g_app_core = new ARM_Interpreter();
g_sys_core = new ARM_Interpreter(); g_sys_core = new ARM_Interpreter();
g_last_ticks = Core::g_app_core->GetTicks();
return 0; return 0;
} }

View file

@ -168,12 +168,14 @@
<ClCompile Include="hle\config_mem.cpp" /> <ClCompile Include="hle\config_mem.cpp" />
<ClCompile Include="hle\coprocessor.cpp" /> <ClCompile Include="hle\coprocessor.cpp" />
<ClCompile Include="hle\hle.cpp" /> <ClCompile Include="hle\hle.cpp" />
<ClCompile Include="hle\kernel\event.cpp" />
<ClCompile Include="hle\kernel\kernel.cpp" /> <ClCompile Include="hle\kernel\kernel.cpp" />
<ClCompile Include="hle\kernel\mutex.cpp" /> <ClCompile Include="hle\kernel\mutex.cpp" />
<ClCompile Include="hle\kernel\thread.cpp" /> <ClCompile Include="hle\kernel\thread.cpp" />
<ClCompile Include="hle\service\apt.cpp" /> <ClCompile Include="hle\service\apt.cpp" />
<ClCompile Include="hle\service\gsp.cpp" /> <ClCompile Include="hle\service\gsp.cpp" />
<ClCompile Include="hle\service\hid.cpp" /> <ClCompile Include="hle\service\hid.cpp" />
<ClCompile Include="hle\service\ndm.cpp" />
<ClCompile Include="hle\service\service.cpp" /> <ClCompile Include="hle\service\service.cpp" />
<ClCompile Include="hle\service\srv.cpp" /> <ClCompile Include="hle\service\srv.cpp" />
<ClCompile Include="hle\svc.cpp" /> <ClCompile Include="hle\svc.cpp" />
@ -217,12 +219,14 @@
<ClInclude Include="hle\coprocessor.h" /> <ClInclude Include="hle\coprocessor.h" />
<ClInclude Include="hle\function_wrappers.h" /> <ClInclude Include="hle\function_wrappers.h" />
<ClInclude Include="hle\hle.h" /> <ClInclude Include="hle\hle.h" />
<ClInclude Include="hle\kernel\event.h" />
<ClInclude Include="hle\kernel\kernel.h" /> <ClInclude Include="hle\kernel\kernel.h" />
<ClInclude Include="hle\kernel\mutex.h" /> <ClInclude Include="hle\kernel\mutex.h" />
<ClInclude Include="hle\kernel\thread.h" /> <ClInclude Include="hle\kernel\thread.h" />
<ClInclude Include="hle\service\apt.h" /> <ClInclude Include="hle\service\apt.h" />
<ClInclude Include="hle\service\gsp.h" /> <ClInclude Include="hle\service\gsp.h" />
<ClInclude Include="hle\service\hid.h" /> <ClInclude Include="hle\service\hid.h" />
<ClInclude Include="hle\service\ndm.h" />
<ClInclude Include="hle\service\service.h" /> <ClInclude Include="hle\service\service.h" />
<ClInclude Include="hle\service\srv.h" /> <ClInclude Include="hle\service\srv.h" />
<ClInclude Include="hle\svc.h" /> <ClInclude Include="hle\svc.h" />

View file

@ -165,6 +165,12 @@
<ClCompile Include="arm\interpreter\armcopro.cpp"> <ClCompile Include="arm\interpreter\armcopro.cpp">
<Filter>arm\interpreter</Filter> <Filter>arm\interpreter</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="hle\kernel\event.cpp">
<Filter>hle\kernel</Filter>
</ClCompile>
<ClCompile Include="hle\service\ndm.cpp">
<Filter>hle\service</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="arm\disassembler\arm_disasm.h"> <ClInclude Include="arm\disassembler\arm_disasm.h">
@ -295,6 +301,12 @@
<ClInclude Include="hle\kernel\mutex.h"> <ClInclude Include="hle\kernel\mutex.h">
<Filter>hle\kernel</Filter> <Filter>hle\kernel</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="hle\kernel\event.h">
<Filter>hle\kernel</Filter>
</ClInclude>
<ClInclude Include="hle\service\ndm.h">
<Filter>hle\service</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="CMakeLists.txt" /> <Text Include="CMakeLists.txt" />

View file

@ -55,7 +55,7 @@ inline void Read(T &var, const u32 addr) {
break; break;
default: default:
ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); ERROR_LOG(HLE, "unknown addr=0x%08X", addr);
} }
} }

View file

@ -25,7 +25,7 @@ s32 CallMRC(u32 instruction) {
return GetThreadCommandBuffer(); return GetThreadCommandBuffer();
default: default:
//DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
break; break;
} }
return -1; return -1;

View file

@ -1,19 +1,6 @@
// Copyright (c) 2012- PPSSPP Project. // Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// This program is free software: you can redistribute it and/or modify // Refer to the license.txt file included.
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once #pragma once
@ -21,725 +8,107 @@
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/hle/hle.h" #include "core/hle/hle.h"
// For easy parameter parsing and return value processing. namespace HLE {
//32bit wrappers #define PARAM(n) Core::g_app_core->GetReg(n)
template<void func()> void WrapV_V() { #define RETURN(n) Core::g_app_core->SetReg(0, n)
func();
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type s32
template<s32 func(u32, u32, u32, u32)> void Wrap() {
RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)));
} }
template<u32 func()> void WrapU_V() { template<s32 func(u32, u32, u32, u32, u32)> void Wrap() {
RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)));
}
template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() {
s32 param_1 = 0;
s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)));
Core::g_app_core->SetReg(1, (u32)param_1);
RETURN(retval);
}
// TODO(bunnei): Is this correct? Probably not
template<s32 func(u32, u32, u32, u32, s64)> void Wrap() {
RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0))));
}
template<s32 func(u32, s64)> void Wrap() {
RETURN(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))));
}
template<s32 func(void*, void*, u32)> void Wrap(){
RETURN(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)));
}
template<s32 func(s32*, u32)> void Wrap(){
s32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1));
Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
template<s32 func(u32, s32)> void Wrap() {
RETURN(func(PARAM(0), (s32)PARAM(1)));
}
template<s32 func(u32*, u32)> void Wrap(){
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1));
Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
template<s32 func(u32)> void Wrap() {
RETURN(func(PARAM(0)));
}
template<s32 func(void*)> void Wrap() {
RETURN(func(Memory::GetPointer(PARAM(0))));
}
template<s32 func(s64*, u32, void*, s32)> void Wrap(){
RETURN(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),
(s32)PARAM(3)));
}
template<s32 func(u32*, const char*)> void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, Memory::GetCharPointer(PARAM(1)));
Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function wrappers that return type u32
template<u32 func()> void Wrap() {
RETURN(func()); RETURN(func());
} }
template<int func(void *, const char *)> void WrapI_VC() { ////////////////////////////////////////////////////////////////////////////////////////////////////
u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1))); /// Function wrappers that return type void
RETURN(retval);
}
template<u32 func(int, void *, int)> void WrapU_IVI() {
u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2));
RETURN(retval);
}
template<int func(const char *, int, int, u32)> void WrapI_CIIU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, const char *, u32, void *, void *, u32, int)> void WrapI_ICUVVUI() {
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)),Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) );
RETURN(retval);
}
// Hm, do so many params get passed in registers?
template<int func(const char *, int, const char *, int, int, int, int, int)> void WrapI_CICIIIII() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), Memory::GetCharPointer(PARAM(2)),
PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7));
RETURN(retval);
}
// Hm, do so many params get passed in registers?
template<int func(const char *, int, int, int, int, int, int)> void WrapI_CIIIIII() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
// Hm, do so many params get passed in registers?
template<int func(int, int, int, int, int, int, u32)> void WrapI_IIIIIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
// Hm, do so many params get passed in registers?
template<int func(int, int, int, int, int, int, int, int, u32)> void WrapI_IIIIIIIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7), PARAM(8));
RETURN(retval);
}
template<u32 func(int, void *)> void WrapU_IV() {
u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)));
RETURN(retval);
}
template<u32 func(u32)> void WrapU_U() {
u32 retval = func(PARAM(0));
RETURN(retval);
}
template<u32 func(u32, int)> void WrapU_UI() {
u32 retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(u32)> void WrapI_U() {
int retval = func(PARAM(0));
RETURN(retval);
}
template<int func(u32, int)> void WrapI_UI() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(u32, int, int, u32)> void WrapI_UIIU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(int, u32, int)> void WrapU_IUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(u32, u32)> void WrapI_UU() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(u32, u32, u32)> void WrapI_UUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(u32, u32, u32, int)> void WrapI_UUUI() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
template<int func(u32, u32, u32, u32)> void WrapI_UUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(void*)> void WrapI_V() {
u32 retval = func(Memory::GetPointer(PARAM(0)));
RETURN(retval);
}
template<u32 func(int)> void WrapU_I() {
u32 retval = func(PARAM(0));
RETURN(retval);
}
template<u32 func(int, int, u32)> void WrapU_IIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(int)> void WrapI_I() {
int retval = func(PARAM(0));
RETURN(retval);
}
template<void func(u32)> void WrapV_U() {
func(PARAM(0));
}
template<void func(int)> void WrapV_I() {
func(PARAM(0));
}
template<void func(u32, u32)> void WrapV_UU() {
func(PARAM(0), PARAM(1));
}
template<void func(int, int)> void WrapV_II() {
func(PARAM(0), PARAM(1));
}
template<void func(u32, const char *)> void WrapV_UC() {
func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
}
template<int func(u32, const char *)> void WrapI_UC() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
}
template<int func(u32, const char *, int)> void WrapI_UCI() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
RETURN(retval);
}
template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
template<u32 func(u32, u32)> void WrapU_UU() {
u32 retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<u32 func(u32, u32, int)> void WrapU_UUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(u32, u32, int, int)> void WrapU_UUII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<void func(u32, int, u32, int, int)> void WrapV_UIUII() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
}
template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(u32, int, u32, int, int)> void WrapI_UIUII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, int, u32, int)> void WrapU_UIUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, int, u32, int)> void WrapI_UIUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, int, u32)> void WrapU_UIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, int, int)> void WrapU_UII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(u32, int, int, u32)> void WrapU_UIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(u32, u32, int, int)> void WrapI_UUII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, u32, int, int, int)> void WrapI_UUIII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<void func(u32, int, int, int)> void WrapV_UIII() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
}
template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
}
template<void func(u32, int, int)> void WrapV_UII() {
func(PARAM(0), PARAM(1), PARAM(2));
}
template<u32 func(int, u32)> void WrapU_IU() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(int, u32)> void WrapI_IU() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(u32, u32, int)> void WrapI_UUI() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(u32, u32, int, u32)> void WrapI_UUIU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, int)> void WrapI_II() {
int retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<int func(int, int, int)> void WrapI_III() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(int, u32, int)> void WrapI_IUI() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(int, int, int, int)> void WrapI_IIII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(u32, int, int, int)> void WrapI_UIII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, int, int, u32, int)> void WrapI_IIIUI() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(int, u32, u32, int, int)> void WrapI_IUUII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(int, int, u32)> void WrapI_IIU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<void func(int, u32)> void WrapV_IU() {
func(PARAM(0), PARAM(1));
}
template<void func(u32, int)> void WrapV_UI() {
func(PARAM(0), PARAM(1));
}
template<u32 func(const char *)> void WrapU_C() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)));
RETURN(retval);
}
template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)),
Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)),
PARAM(3));
RETURN(retval);
}
template<int func(const char *)> void WrapI_C() {
int retval = func(Memory::GetCharPointer(PARAM(0)));
RETURN(retval);
}
template<int func(const char *, u32)> void WrapI_CU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN(retval);
}
template<int func(const char *, u32, int)> void WrapI_CUI() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(int, const char *, int, u32)> void WrapI_ICIU() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(const char *, int, u32)> void WrapI_CIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(const char *, u32, u32)> void WrapI_CUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3));
RETURN(retval);
}
template<int func(const char *, const char*, int, int)> void WrapI_CCII() {
int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<u32 func(const char *, u32)> void WrapU_CU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN((u32) retval);
}
template<u32 func(u32, const char *)> void WrapU_UC() {
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
}
template<u32 func(const char *, u32, u32)> void WrapU_CUU() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN((u32) retval);
}
template<u32 func(int, int, int)> void WrapU_III() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(int, int)> void WrapU_II() {
u32 retval = func(PARAM(0), PARAM(1));
RETURN(retval);
}
template<u32 func(int, int, int, int)> void WrapU_IIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(int, u32, u32)> void WrapU_IUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, u32, u32)> void WrapU_UUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<void func(int, u32, u32)> void WrapV_IUU() {
func(PARAM(0), PARAM(1), PARAM(2));
}
template<void func(int, int, u32)> void WrapV_IIU() {
func(PARAM(0), PARAM(1), PARAM(2));
}
template<void func(u32, int, u32)> void WrapV_UIU() {
func(PARAM(0), PARAM(1), PARAM(2));
}
template<int func(u32, int, u32)> void WrapI_UIU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
}
template<void func(u32, u32, u32)> void WrapV_UUU() {
func(PARAM(0), PARAM(1), PARAM(2));
}
template<void func(u32, u32, u32, u32)> void WrapV_UUUU() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
}
template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
}
template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
PARAM(4));
}
template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
PARAM(4));
}
template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() {
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, int, int, int)> void WrapU_UIII() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<int func(int, u32, int, int)> void WrapI_IUII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
}
template<u32 func(const char *, const char *)> void WrapU_CC() { template<void func(s64)> void Wrap() {
int retval = func(Memory::GetCharPointer(PARAM(0)), func(((s64)PARAM(1) << 32) | PARAM(0));
Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
} }
template<void func(const char*)> void WrapV_C() { template<void func(const char*)> void Wrap() {
func(Memory::GetCharPointer(PARAM(0))); func(Memory::GetCharPointer(PARAM(0)));
} }
template<void func(const char *, int)> void WrapV_CI() { #undef PARAM
func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); #undef RETURN
}
template<u32 func(const char *, int)> void WrapU_CI() { } // namespace HLE
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN(retval);
}
template<u32 func(const char *, int, int)> void WrapU_CII() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN(retval);
}
template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4));
RETURN(retval);
}
template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() {
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4),
PARAM(5));
RETURN(retval);
}
template<int func(int, u32, u32, u32)> void WrapI_IUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, u32, u32)> void WrapI_IUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2));
RETURN(retval);
}
template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
template<int func(u32, int, u32, u32)> void WrapI_UIUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);
}
template<int func(int, const char *)> void WrapI_IC() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
}
template <int func(int, const char *, const char *, u32, int)> void WrapI_ICCUI() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3), PARAM(4));
RETURN(retval);
}
template <int func(int, const char *, const char *, int)> void WrapI_ICCI() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3));
RETURN(retval);
}
template <int func(const char *, int, int)> void WrapI_CII() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
RETURN(retval);
}
template <int func(int, const char *, int)> void WrapI_ICI() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
RETURN(retval);
}
template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){
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) );
RETURN(retval);
}
template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6));
RETURN(retval);
}
template<int func(void*, u32)> void WrapI_VU(){
u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1));
RETURN(retval);
}
template<int func(void*, void*, u32)> void WrapI_VVU(){
u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2));
RETURN(retval);
}
template<int func(void*, u32, void*, int)> void WrapI_VUVI(){
u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3));
RETURN(retval);
}
template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){
u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<int func(u32, s64)> void WrapI_US64() {
int retval = func(PARAM(0), PARAM64(1));
RETURN(retval);
}
template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() {
int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}

View file

@ -7,6 +7,7 @@
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/hle/hle.h" #include "core/hle/hle.h"
#include "core/hle/svc.h" #include "core/hle/svc.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -15,11 +16,13 @@ namespace HLE {
static std::vector<ModuleDef> g_module_db; static std::vector<ModuleDef> g_module_db;
bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
const FunctionDef* GetSVCInfo(u32 opcode) { const FunctionDef* GetSVCInfo(u32 opcode) {
u32 func_num = opcode & 0xFFFFFF; // 8 bits u32 func_num = opcode & 0xFFFFFF; // 8 bits
if (func_num > 0xFF) { if (func_num > 0xFF) {
ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num); ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
return NULL; return nullptr;
} }
return &g_module_db[0].func_table[func_num]; return &g_module_db[0].func_table[func_num];
} }
@ -33,19 +36,16 @@ void CallSVC(u32 opcode) {
if (info->func) { if (info->func) {
info->func(); info->func();
} else { } else {
ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str());
} }
} }
void EatCycles(u32 cycles) { void Reschedule(const char *reason) {
// TODO: ImplementMe
}
void ReSchedule(const char *reason) {
#ifdef _DEBUG #ifdef _DEBUG
_dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason."); _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
#endif #endif
// TODO: ImplementMe Core::g_app_core->PrepareReschedule();
g_reschedule = true;
} }
void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {

View file

@ -9,14 +9,10 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
#define PARAM(n) Core::g_app_core->GetReg(n)
#define PARAM64(n) (Core::g_app_core->GetReg(n) | ((u64)Core::g_app_core->GetReg(n + 1) << 32))
#define RETURN(n) Core::g_app_core->SetReg(0, n)
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace HLE { namespace HLE {
extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
typedef u32 Addr; typedef u32 Addr;
typedef void (*Func)(); typedef void (*Func)();
@ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func
void CallSVC(u32 opcode); void CallSVC(u32 opcode);
void EatCycles(u32 cycles); void Reschedule(const char *reason);
void ReSchedule(const char *reason);
void Init(); void Init();

View file

@ -0,0 +1,158 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <map>
#include <vector>
#include "common/common.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
class Event : public Object {
public:
const char* GetTypeName() const { return "Event"; }
const char* GetName() const { return name.c_str(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
ResetType intitial_reset_type; ///< ResetType specified at Event initialization
ResetType reset_type; ///< Current ResetType
bool locked; ///< Event signal wait
bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
std::string name; ///< Name of event (optional)
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result WaitSynchronization(bool* wait) {
*wait = locked;
if (locked) {
Handle thread = GetCurrentThreadHandle();
if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
waiting_threads.push_back(thread);
}
Kernel::WaitCurrentThread(WAITTYPE_EVENT);
}
if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
locked = true;
}
return 0;
}
};
/**
* Hackish function to set an events permanent lock state, used to pass through synch blocks
* @param handle Handle to event to change
* @param permanent_locked Boolean permanent locked value to set event
* @return Result of operation, 0 on success, otherwise error code
*/
Result SetPermanentLock(Handle handle, const bool permanent_locked) {
Event* evt = g_object_pool.GetFast<Event>(handle);
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
evt->permanent_locked = permanent_locked;
return 0;
}
/**
* Changes whether an event is locked or not
* @param handle Handle to event to change
* @param locked Boolean locked value to set event
* @return Result of operation, 0 on success, otherwise error code
*/
Result SetEventLocked(const Handle handle, const bool locked) {
Event* evt = g_object_pool.GetFast<Event>(handle);
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
if (!evt->permanent_locked) {
evt->locked = locked;
}
return 0;
}
/**
* Signals an event
* @param handle Handle to event to signal
* @return Result of operation, 0 on success, otherwise error code
*/
Result SignalEvent(const Handle handle) {
Event* evt = g_object_pool.GetFast<Event>(handle);
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
// Resume threads waiting for event to signal
bool event_caught = false;
for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
ResumeThreadFromWait( evt->waiting_threads[i]);
// If any thread is signalled awake by this event, assume the event was "caught" and reset
// the event. This will result in the next thread waiting on the event to block. Otherwise,
// the event will not be reset, and the next thread to call WaitSynchronization on it will
// not block. Not sure if this is correct behavior, but it seems to work.
event_caught = true;
}
evt->waiting_threads.clear();
if (!evt->permanent_locked) {
evt->locked = event_caught;
}
return 0;
}
/**
* Clears an event
* @param handle Handle to event to clear
* @return Result of operation, 0 on success, otherwise error code
*/
Result ClearEvent(Handle handle) {
Event* evt = g_object_pool.GetFast<Event>(handle);
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
if (!evt->permanent_locked) {
evt->locked = true;
}
return 0;
}
/**
* Creates an event
* @param handle Reference to handle for the newly created mutex
* @param reset_type ResetType describing how to create event
* @param name Optional name of event
* @return Newly created Event object
*/
Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
Event* evt = new Event;
handle = Kernel::g_object_pool.Create(evt);
evt->locked = true;
evt->permanent_locked = false;
evt->reset_type = evt->intitial_reset_type = reset_type;
evt->name = name;
return evt;
}
/**
* Creates an event
* @param reset_type ResetType describing how to create event
* @param name Optional name of event
* @return Handle to newly created Event object
*/
Handle CreateEvent(const ResetType reset_type, const std::string& name) {
Handle handle;
Event* evt = CreateEvent(handle, reset_type, name);
return handle;
}
} // namespace

View file

@ -0,0 +1,52 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/svc.h"
namespace Kernel {
/**
* Changes whether an event is locked or not
* @param handle Handle to event to change
* @param locked Boolean locked value to set event
* @return Result of operation, 0 on success, otherwise error code
*/
Result SetEventLocked(const Handle handle, const bool locked);
/**
* Hackish function to set an events permanent lock state, used to pass through synch blocks
* @param handle Handle to event to change
* @param permanent_locked Boolean permanent locked value to set event
* @return Result of operation, 0 on success, otherwise error code
*/
Result SetPermanentLock(Handle handle, const bool permanent_locked);
/**
* Signals an event
* @param handle Handle to event to signal
* @return Result of operation, 0 on success, otherwise error code
*/
Result SignalEvent(const Handle handle);
/**
* Clears an event
* @param handle Handle to event to clear
* @return Result of operation, 0 on success, otherwise error code
*/
Result ClearEvent(Handle handle);
/**
* Creates an event
* @param reset_type ResetType describing how to create event
* @param name Optional name of event
* @return Handle to newly created Event object
*/
Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown");
} // namespace

View file

@ -14,6 +14,7 @@
namespace Kernel { namespace Kernel {
Handle g_main_thread = 0;
ObjectPool g_object_pool; ObjectPool g_object_pool;
ObjectPool::ObjectPool() { ObjectPool::ObjectPool() {
@ -127,7 +128,7 @@ Object* ObjectPool::CreateByIDType(int type) {
default: default:
ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
return NULL; return nullptr;
} }
} }
@ -150,7 +151,7 @@ bool LoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point); Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far // 0x30 is the typical main thread priority I've seen used so far
Handle thread = Kernel::SetupMainThread(0x30); g_main_thread = Kernel::SetupMainThread(0x30);
return true; return true;
} }

View file

@ -11,6 +11,11 @@ typedef s32 Result;
namespace Kernel { namespace Kernel {
enum KernelHandle {
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
enum class HandleType : u32 { enum class HandleType : u32 {
Unknown = 0, Unknown = 0,
Port = 1, Port = 1,
@ -39,9 +44,26 @@ class Object : NonCopyable {
public: public:
virtual ~Object() {} virtual ~Object() {}
Handle GetHandle() const { return handle; } Handle GetHandle() const { return handle; }
virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
virtual Kernel::HandleType GetHandleType() const = 0; virtual Kernel::HandleType GetHandleType() const = 0;
/**
* Synchronize kernel object
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
virtual Result SyncRequest(bool* wait) {
ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
return -1;
}
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
virtual Result WaitSynchronization(bool* wait) = 0;
}; };
class ObjectPool : NonCopyable { class ObjectPool : NonCopyable {
@ -143,6 +165,7 @@ private:
}; };
extern ObjectPool g_object_pool; extern ObjectPool g_object_pool;
extern Handle g_main_thread;
/** /**
* Loads executable stored at specified address * Loads executable stored at specified address

View file

@ -8,13 +8,15 @@
#include "common/common.h" #include "common/common.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
namespace Kernel { namespace Kernel {
class Mutex : public Object { class Mutex : public Object {
public: public:
const char* GetTypeName() { return "Mutex"; } const char* GetTypeName() const { return "Mutex"; }
const char* GetName() const { return name.c_str(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
@ -23,6 +25,34 @@ public:
bool locked; ///< Current locked state bool locked; ///< Current locked state
Handle lock_thread; ///< Handle to thread that currently has mutex Handle lock_thread; ///< Handle to thread that currently has mutex
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
std::string name; ///< Name of mutex (optional)
/**
* Synchronize kernel object
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result SyncRequest(bool* wait) {
// TODO(bunnei): ImplementMe
locked = true;
return 0;
}
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result WaitSynchronization(bool* wait) {
// TODO(bunnei): ImplementMe
*wait = locked;
if (locked) {
Kernel::WaitCurrentThread(WAITTYPE_MUTEX);
}
return 0;
}
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -70,10 +100,10 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
bool ReleaseMutex(Mutex* mutex) { bool ReleaseMutex(Mutex* mutex) {
MutexEraseLock(mutex); MutexEraseLock(mutex);
bool woke_threads = false; bool woke_threads = false;
auto iter = mutex->waiting_threads.begin();
// Find the next waiting thread for the mutex... // Find the next waiting thread for the mutex...
while (!woke_threads && !mutex->waiting_threads.empty()) { while (!woke_threads && !mutex->waiting_threads.empty()) {
std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
woke_threads |= ReleaseMutexForThread(mutex, *iter); woke_threads |= ReleaseMutexForThread(mutex, *iter);
mutex->waiting_threads.erase(iter); mutex->waiting_threads.erase(iter);
} }
@ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) {
*/ */
Result ReleaseMutex(Handle handle) { Result ReleaseMutex(Handle handle) {
Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
_assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
if (!ReleaseMutex(mutex)) { if (!ReleaseMutex(mutex)) {
return -1; return -1;
} }
@ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) {
* Creates a mutex * Creates a mutex
* @param handle Reference to handle for the newly created mutex * @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially * @param initial_locked Specifies if the mutex should be locked initially
* @param name Optional name of mutex
* @return Pointer to new Mutex object
*/ */
Mutex* CreateMutex(Handle& handle, bool initial_locked) { Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
Mutex* mutex = new Mutex; Mutex* mutex = new Mutex;
handle = Kernel::g_object_pool.Create(mutex); handle = Kernel::g_object_pool.Create(mutex);
mutex->locked = mutex->initial_locked = initial_locked; mutex->locked = mutex->initial_locked = initial_locked;
mutex->name = name;
// Acquire mutex with current thread if initialized as locked... // Acquire mutex with current thread if initialized as locked...
if (mutex->locked) { if (mutex->locked) {
@ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) {
/** /**
* Creates a mutex * Creates a mutex
* @param initial_locked Specifies if the mutex should be locked initially * @param initial_locked Specifies if the mutex should be locked initially
* @param name Optional name of mutex
* @return Handle to newly created object
*/ */
Handle CreateMutex(bool initial_locked) { Handle CreateMutex(bool initial_locked, const std::string& name) {
Handle handle; Handle handle;
Mutex* mutex = CreateMutex(handle, initial_locked); Mutex* mutex = CreateMutex(handle, initial_locked, name);
return handle; return handle;
} }

View file

@ -13,14 +13,16 @@ namespace Kernel {
/** /**
* Releases a mutex * Releases a mutex
* @param handle Handle to mutex to release * @param handle Handle to mutex to release
* @return Result of operation, 0 on success, otherwise error code
*/ */
Result ReleaseMutex(Handle handle); Result ReleaseMutex(Handle handle);
/** /**
* Creates a mutex * Creates a mutex
* @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially * @param initial_locked Specifies if the mutex should be locked initially
* @param name Optional name of mutex
* @return Handle to newly created object
*/ */
Handle CreateMutex(bool initial_locked); Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
} // namespace } // namespace

View file

@ -24,8 +24,8 @@ namespace Kernel {
class Thread : public Kernel::Object { class Thread : public Kernel::Object {
public: public:
const char* GetName() { return name; } const char* GetName() const { return name; }
const char* GetTypeName() { return "Thread"; } const char* GetTypeName() const { return "Thread"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
@ -36,6 +36,23 @@ public:
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result WaitSynchronization(bool* wait) {
if (status != THREADSTATUS_DORMANT) {
Handle thread = GetCurrentThreadHandle();
if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
waiting_threads.push_back(thread);
}
WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
*wait = true;
}
return 0;
}
ThreadContext context; ThreadContext context;
u32 status; u32 status;
@ -49,6 +66,9 @@ public:
s32 processor_id; s32 processor_id;
WaitType wait_type; WaitType wait_type;
Handle wait_handle;
std::vector<Handle> waiting_threads;
char name[Kernel::MAX_NAME_LENGTH + 1]; char name[Kernel::MAX_NAME_LENGTH + 1];
}; };
@ -62,7 +82,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue;
Handle g_current_thread_handle; Handle g_current_thread_handle;
Thread* g_current_thread; Thread* g_current_thread;
/// Gets the current thread /// Gets the current thread
inline Thread* GetCurrentThread() { inline Thread* GetCurrentThread() {
return g_current_thread; return g_current_thread;
@ -94,15 +113,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext)); memset(&t->context, 0, sizeof(ThreadContext));
t->context.cpu_registers[0] = arg; t->context.cpu_registers[0] = arg;
t->context.pc = t->entry_point; t->context.pc = t->context.reg_15 = t->entry_point;
t->context.sp = t->stack_top; t->context.sp = t->stack_top;
t->context.cpsr = 0x1F; // Usermode t->context.cpsr = 0x1F; // Usermode
if (t->current_priority < lowest_priority) { if (t->current_priority < lowest_priority) {
t->current_priority = t->initial_priority; t->current_priority = t->initial_priority;
} }
t->wait_type = WAITTYPE_NONE; t->wait_type = WAITTYPE_NONE;
t->wait_handle = 0;
} }
/// Change a thread to "ready" state /// Change a thread to "ready" state
@ -122,6 +141,37 @@ void ChangeReadyState(Thread* t, bool ready) {
} }
} }
/// Verify that a thread has not been released from waiting
inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) {
Thread* thread = g_object_pool.GetFast<Thread>(handle);
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
if (type != thread->wait_type || wait_handle != thread->wait_handle)
return false;
return true;
}
/// Stops the current thread
void StopThread(Handle handle, const char* reason) {
Thread* thread = g_object_pool.GetFast<Thread>(handle);
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
ChangeReadyState(thread, false);
thread->status = THREADSTATUS_DORMANT;
for (size_t i = 0; i < thread->waiting_threads.size(); ++i) {
const Handle waiting_thread = thread->waiting_threads[i];
if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
ResumeThreadFromWait(waiting_thread);
}
}
thread->waiting_threads.clear();
// Stopped threads are never waiting.
thread->wait_type = WAITTYPE_NONE;
thread->wait_handle = 0;
}
/// Changes a threads state /// Changes a threads state
void ChangeThreadState(Thread* t, ThreadStatus new_status) { void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (!t || t->status == new_status) { if (!t || t->status == new_status) {
@ -132,7 +182,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (new_status == THREADSTATUS_WAIT) { if (new_status == THREADSTATUS_WAIT) {
if (t->wait_type == WAITTYPE_NONE) { if (t->wait_type == WAITTYPE_NONE) {
printf("ERROR: Waittype none not allowed here\n"); ERROR_LOG(KERNEL, "Waittype none not allowed");
} }
} }
} }
@ -166,7 +216,7 @@ void SwitchContext(Thread* t) {
t->wait_type = WAITTYPE_NONE; t->wait_type = WAITTYPE_NONE;
LoadContext(t->context); LoadContext(t->context);
} else { } else {
SetCurrentThread(NULL); SetCurrentThread(nullptr);
} }
} }
@ -181,26 +231,43 @@ Thread* NextThread() {
next = g_thread_ready_queue.pop_first(); next = g_thread_ready_queue.pop_first();
} }
if (next == 0) { if (next == 0) {
return NULL; return nullptr;
} }
return Kernel::g_object_pool.GetFast<Thread>(next); return Kernel::g_object_pool.GetFast<Thread>(next);
} }
/// Puts the current thread in the wait state for the given type /// Puts the current thread in the wait state for the given type
void WaitCurrentThread(WaitType wait_type) { void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
Thread* t = GetCurrentThread(); Thread* thread = GetCurrentThread();
t->wait_type = wait_type; thread->wait_type = wait_type;
ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); thread->wait_handle = wait_handle;
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
} }
/// Resumes a thread from waiting by marking it as "ready" /// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle) { void ResumeThreadFromWait(Handle handle) {
u32 error; u32 error;
Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error); Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
if (t) { if (thread) {
t->status &= ~THREADSTATUS_WAIT; thread->status &= ~THREADSTATUS_WAIT;
if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
ChangeReadyState(t, true); ChangeReadyState(thread, true);
}
}
}
/// Prints the thread queue for debugging purposes
void DebugThreadQueue() {
Thread* thread = GetCurrentThread();
if (!thread) {
return;
}
INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
for (u32 i = 0; i < g_thread_queue.size(); i++) {
Handle handle = g_thread_queue[i];
s32 priority = g_thread_ready_queue.contains(handle);
if (priority != -1) {
INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle);
} }
} }
} }
@ -212,32 +279,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
_assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
"CreateThread priority=%d, outside of allowable range!", priority) "CreateThread priority=%d, outside of allowable range!", priority)
Thread* t = new Thread; Thread* thread = new Thread;
handle = Kernel::g_object_pool.Create(t); handle = Kernel::g_object_pool.Create(thread);
g_thread_queue.push_back(handle); g_thread_queue.push_back(handle);
g_thread_ready_queue.prepare(priority); g_thread_ready_queue.prepare(priority);
t->status = THREADSTATUS_DORMANT; thread->status = THREADSTATUS_DORMANT;
t->entry_point = entry_point; thread->entry_point = entry_point;
t->stack_top = stack_top; thread->stack_top = stack_top;
t->stack_size = stack_size; thread->stack_size = stack_size;
t->initial_priority = t->current_priority = priority; thread->initial_priority = thread->current_priority = priority;
t->processor_id = processor_id; thread->processor_id = processor_id;
t->wait_type = WAITTYPE_NONE; thread->wait_type = WAITTYPE_NONE;
thread->wait_handle = 0;
strncpy(t->name, name, Kernel::MAX_NAME_LENGTH); strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH);
t->name[Kernel::MAX_NAME_LENGTH] = '\0'; thread->name[Kernel::MAX_NAME_LENGTH] = '\0';
return t; return thread;
} }
/// Creates a new thread - wrapper for external user /// Creates a new thread - wrapper for external user
Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
u32 stack_top, int stack_size) { u32 stack_top, int stack_size) {
if (name == NULL) {
ERROR_LOG(KERNEL, "CreateThread(): NULL name"); if (name == nullptr) {
ERROR_LOG(KERNEL, "CreateThread(): nullptr name");
return -1; return -1;
} }
if ((u32)stack_size < 0x200) { if ((u32)stack_size < 0x200) {
@ -258,31 +327,67 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
return -1; return -1;
} }
Handle handle; Handle handle;
Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
stack_size); stack_size);
ResetThread(t, arg, 0); ResetThread(thread, arg, 0);
CallThread(thread);
HLE::EatCycles(32000);
// This won't schedule to the new thread, but it may to one woken from eating cycles.
// Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
HLE::ReSchedule("thread created");
CallThread(t);
return handle; return handle;
} }
/// Get the priority of the thread specified by handle
u32 GetThreadPriority(const Handle handle) {
Thread* thread = g_object_pool.GetFast<Thread>(handle);
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
return thread->current_priority;
}
/// Set the priority of the thread specified by handle
Result SetThreadPriority(Handle handle, s32 priority) {
Thread* thread = nullptr;
if (!handle) {
thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
} else {
thread = g_object_pool.GetFast<Thread>(handle);
}
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
// If priority is invalid, clamp to valid range
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority);
// TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
// validity of this
priority = new_priority;
}
// Change thread priority
s32 old = thread->current_priority;
g_thread_ready_queue.remove(old, handle);
thread->current_priority = priority;
g_thread_ready_queue.prepare(thread->current_priority);
// Change thread status to "ready" and push to ready queue
if (thread->IsRunning()) {
thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
}
if (thread->IsReady()) {
g_thread_ready_queue.push_back(thread->current_priority, handle);
}
return 0;
}
/// Sets up the primary application thread /// Sets up the primary application thread
Handle SetupMainThread(s32 priority, int stack_size) { Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle; Handle handle;
// Initialize new "main" thread // Initialize new "main" thread
Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
ResetThread(t, 0, 0); ResetThread(thread, 0, 0);
// If running another thread already, set it to "ready" state // If running another thread already, set it to "ready" state
Thread* cur = GetCurrentThread(); Thread* cur = GetCurrentThread();
@ -291,24 +396,31 @@ Handle SetupMainThread(s32 priority, int stack_size) {
} }
// Run new "main" thread // Run new "main" thread
SetCurrentThread(t); SetCurrentThread(thread);
t->status = THREADSTATUS_RUNNING; thread->status = THREADSTATUS_RUNNING;
LoadContext(t->context); LoadContext(thread->context);
return handle; return handle;
} }
/// Reschedules to the next available thread (call after current thread is suspended) /// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule() { void Reschedule() {
Thread* prev = GetCurrentThread(); Thread* prev = GetCurrentThread();
Thread* next = NextThread(); Thread* next = NextThread();
HLE::g_reschedule = false;
if (next > 0) { if (next > 0) {
INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
SwitchContext(next); SwitchContext(next);
// Hack - automatically change previous thread (which would have been in "wait" state) to // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
// "ready" state, so that we can immediately resume to it when new thread yields. FixMe to // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
// actually wait for whatever event it is supposed to be waiting on. // This results in the current thread yielding on a VBLANK once, and then it will be
ChangeReadyState(prev, true); // immediately placed back in the queue for execution.
if (prev->wait_type == WAITTYPE_VBLANK) {
ResumeThreadFromWait(prev->GetHandle());
}
} }
} }

View file

@ -34,7 +34,7 @@ enum WaitType {
WAITTYPE_NONE, WAITTYPE_NONE,
WAITTYPE_SLEEP, WAITTYPE_SLEEP,
WAITTYPE_SEMA, WAITTYPE_SEMA,
WAITTYPE_EVENTFLAG, WAITTYPE_EVENT,
WAITTYPE_THREADEND, WAITTYPE_THREADEND,
WAITTYPE_VBLANK, WAITTYPE_VBLANK,
WAITTYPE_MUTEX, WAITTYPE_MUTEX,
@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended) /// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(); void Reschedule();
/// Puts the current thread in the wait state for the given type /// Stops the current thread
void WaitCurrentThread(WaitType wait_type); void StopThread(Handle thread, const char* reason);
/// Resumes a thread from waiting by marking it as "ready" /// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle); void ResumeThreadFromWait(Handle handle);
@ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle);
/// Gets the current thread handle /// Gets the current thread handle
Handle GetCurrentThreadHandle(); Handle GetCurrentThreadHandle();
/// Puts the current thread in the wait state for the given type
void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
/// Put current thread in a wait state - on WaitSynchronization /// Put current thread in a wait state - on WaitSynchronization
void WaitThread_Synchronization(); void WaitThread_Synchronization();
/// Get the priority of the thread specified by handle
u32 GetThreadPriority(const Handle handle);
/// Set the priority of the thread specified by handle
Result SetThreadPriority(Handle handle, s32 priority);
/// Initialize threading /// Initialize threading
void ThreadingInit(); void ThreadingInit();

View file

@ -6,6 +6,7 @@
#include "common/common.h" #include "common/common.h"
#include "core/hle/hle.h" #include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h" #include "core/hle/kernel/mutex.h"
#include "core/hle/service/apt.h" #include "core/hle/service/apt.h"
@ -15,96 +16,120 @@
namespace APT_U { namespace APT_U {
void Initialize(Service::Interface* self) { void Initialize(Service::Interface* self) {
NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize"); u32* cmd_buff = Service::GetCommandBuffer();
DEBUG_LOG(KERNEL, "called");
cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
Kernel::SetEventLocked(cmd_buff[3], true);
Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
cmd_buff[1] = 0; // No error
} }
void GetLockHandle(Service::Interface* self) { void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
cmd_buff[1] = 0; // No error cmd_buff[1] = 0; // No error
cmd_buff[5] = Kernel::CreateMutex(false); cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]); DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
}
void Enable(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
cmd_buff[1] = 0; // No error
ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk);
}
void InquireNotification(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[2];
cmd_buff[1] = 0; // No error
cmd_buff[3] = 0; // Signal type
ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id);
} }
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle"}, {0x00010040, GetLockHandle, "GetLockHandle"},
{0x00020080, Initialize, "Initialize"}, {0x00020080, Initialize, "Initialize"},
{0x00030040, NULL, "Enable"}, {0x00030040, Enable, "Enable"},
{0x00040040, NULL, "Finalize"}, {0x00040040, nullptr, "Finalize"},
{0x00050040, NULL, "GetAppletManInfo"}, {0x00050040, nullptr, "GetAppletManInfo"},
{0x00060040, NULL, "GetAppletInfo"}, {0x00060040, nullptr, "GetAppletInfo"},
{0x00070000, NULL, "GetLastSignaledAppletId"}, {0x00070000, nullptr, "GetLastSignaledAppletId"},
{0x00080000, NULL, "CountRegisteredApplet"}, {0x00080000, nullptr, "CountRegisteredApplet"},
{0x00090040, NULL, "IsRegistered"}, {0x00090040, nullptr, "IsRegistered"},
{0x000A0040, NULL, "GetAttribute"}, {0x000A0040, nullptr, "GetAttribute"},
{0x000B0040, NULL, "InquireNotification"}, {0x000B0040, InquireNotification, "InquireNotification"},
{0x000C0104, NULL, "SendParameter"}, {0x000C0104, nullptr, "SendParameter"},
{0x000D0080, NULL, "ReceiveParameter"}, {0x000D0080, nullptr, "ReceiveParameter"},
{0x000E0080, NULL, "GlanceParameter"}, {0x000E0080, nullptr, "GlanceParameter"},
{0x000F0100, NULL, "CancelParameter"}, {0x000F0100, nullptr, "CancelParameter"},
{0x001000C2, NULL, "DebugFunc"}, {0x001000C2, nullptr, "DebugFunc"},
{0x001100C0, NULL, "MapProgramIdForDebug"}, {0x001100C0, nullptr, "MapProgramIdForDebug"},
{0x00120040, NULL, "SetHomeMenuAppletIdForDebug"}, {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
{0x00130000, NULL, "GetPreparationState"}, {0x00130000, nullptr, "GetPreparationState"},
{0x00140040, NULL, "SetPreparationState"}, {0x00140040, nullptr, "SetPreparationState"},
{0x00150140, NULL, "PrepareToStartApplication"}, {0x00150140, nullptr, "PrepareToStartApplication"},
{0x00160040, NULL, "PreloadLibraryApplet"}, {0x00160040, nullptr, "PreloadLibraryApplet"},
{0x00170040, NULL, "FinishPreloadingLibraryApplet"}, {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
{0x00180040, NULL, "PrepareToStartLibraryApplet"}, {0x00180040, nullptr, "PrepareToStartLibraryApplet"},
{0x00190040, NULL, "PrepareToStartSystemApplet"}, {0x00190040, nullptr, "PrepareToStartSystemApplet"},
{0x001A0000, NULL, "PrepareToStartNewestHomeMenu"}, {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, NULL, "StartApplication"}, {0x001B00C4, nullptr, "StartApplication"},
{0x001C0000, NULL, "WakeupApplication"}, {0x001C0000, nullptr, "WakeupApplication"},
{0x001D0000, NULL, "CancelApplication"}, {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, NULL, "StartLibraryApplet"}, {0x001E0084, nullptr, "StartLibraryApplet"},
{0x001F0084, NULL, "StartSystemApplet"}, {0x001F0084, nullptr, "StartSystemApplet"},
{0x00200044, NULL, "StartNewestHomeMenu"}, {0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, NULL, "OrderToCloseApplication"}, {0x00210000, nullptr, "OrderToCloseApplication"},
{0x00220040, NULL, "PrepareToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"},
{0x00230040, NULL, "PrepareToJumpToApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"},
{0x00240044, NULL, "JumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"},
{0x002500C0, NULL, "PrepareToCloseLibraryApplet"}, {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
{0x00260000, NULL, "PrepareToCloseSystemApplet"}, {0x00260000, nullptr, "PrepareToCloseSystemApplet"},
{0x00270044, NULL, "CloseApplication"}, {0x00270044, nullptr, "CloseApplication"},
{0x00280044, NULL, "CloseLibraryApplet"}, {0x00280044, nullptr, "CloseLibraryApplet"},
{0x00290044, NULL, "CloseSystemApplet"}, {0x00290044, nullptr, "CloseSystemApplet"},
{0x002A0000, NULL, "OrderToCloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
{0x002B0000, NULL, "PrepareToJumpToHomeMenu"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
{0x002C0044, NULL, "JumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"},
{0x002D0000, NULL, "PrepareToLeaveHomeMenu"}, {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
{0x002E0044, NULL, "LeaveHomeMenu"}, {0x002E0044, nullptr, "LeaveHomeMenu"},
{0x002F0040, NULL, "PrepareToLeaveResidentApplet"}, {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
{0x00300044, NULL, "LeaveResidentApplet"}, {0x00300044, nullptr, "LeaveResidentApplet"},
{0x00310100, NULL, "PrepareToDoApplicationJump"}, {0x00310100, nullptr, "PrepareToDoApplicationJump"},
{0x00320084, NULL, "DoApplicationJump"}, {0x00320084, nullptr, "DoApplicationJump"},
{0x00330000, NULL, "GetProgramIdOnApplicationJump"}, {0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
{0x00340084, NULL, "SendDeliverArg"}, {0x00340084, nullptr, "SendDeliverArg"},
{0x00350080, NULL, "ReceiveDeliverArg"}, {0x00350080, nullptr, "ReceiveDeliverArg"},
{0x00360040, NULL, "LoadSysMenuArg"}, {0x00360040, nullptr, "LoadSysMenuArg"},
{0x00370042, NULL, "StoreSysMenuArg"}, {0x00370042, nullptr, "StoreSysMenuArg"},
{0x00380040, NULL, "PreloadResidentApplet"}, {0x00380040, nullptr, "PreloadResidentApplet"},
{0x00390040, NULL, "PrepareToStartResidentApplet"}, {0x00390040, nullptr, "PrepareToStartResidentApplet"},
{0x003A0044, NULL, "StartResidentApplet"}, {0x003A0044, nullptr, "StartResidentApplet"},
{0x003B0040, NULL, "CancelLibraryApplet"}, {0x003B0040, nullptr, "CancelLibraryApplet"},
{0x003C0042, NULL, "SendDspSleep"}, {0x003C0042, nullptr, "SendDspSleep"},
{0x003D0042, NULL, "SendDspWakeUp"}, {0x003D0042, nullptr, "SendDspWakeUp"},
{0x003E0080, NULL, "ReplySleepQuery"}, {0x003E0080, nullptr, "ReplySleepQuery"},
{0x003F0040, NULL, "ReplySleepNotificationComplete"}, {0x003F0040, nullptr, "ReplySleepNotificationComplete"},
{0x00400042, NULL, "SendCaptureBufferInfo"}, {0x00400042, nullptr, "SendCaptureBufferInfo"},
{0x00410040, NULL, "ReceiveCaptureBufferInfo"}, {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
{0x00420080, NULL, "SleepSystem"}, {0x00420080, nullptr, "SleepSystem"},
{0x00430040, NULL, "NotifyToWait"}, {0x00430040, nullptr, "NotifyToWait"},
{0x00440000, NULL, "GetSharedFont"}, {0x00440000, nullptr, "GetSharedFont"},
{0x00450040, NULL, "GetWirelessRebootInfo"}, {0x00450040, nullptr, "GetWirelessRebootInfo"},
{0x00460104, NULL, "Wrap"}, {0x00460104, nullptr, "Wrap"},
{0x00470104, NULL, "Unwrap"}, {0x00470104, nullptr, "Unwrap"},
{0x00480100, NULL, "GetProgramInfo"}, {0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, NULL, "Reboot"}, {0x00490180, nullptr, "Reboot"},
{0x004A0040, NULL, "GetCaptureInfo"}, {0x004A0040, nullptr, "GetCaptureInfo"},
{0x004B00C2, NULL, "AppletUtility"}, {0x004B00C2, nullptr, "AppletUtility"},
{0x004C0000, NULL, "SetFatalErrDispMode"}, {0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, NULL, "GetAppletProgramInfo"}, {0x004D0080, nullptr, "GetAppletProgramInfo"},
{0x004E0000, NULL, "HardwareResetAsync"}, {0x004E0000, nullptr, "HardwareResetAsync"},
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -8,6 +8,7 @@
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/hle/hle.h" #include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/gsp.h" #include "core/hle/service/gsp.h"
#include "core/hw/lcd.h" #include "core/hw/lcd.h"
@ -52,6 +53,7 @@ void GX_FinishCommand(u32 thread_id) {
namespace GSP_GPU { namespace GSP_GPU {
Handle g_event_handle = 0;
u32 g_thread_id = 0; u32 g_thread_id = 0;
enum { enum {
@ -92,7 +94,7 @@ void ReadHWRegs(Service::Interface* self) {
break; break;
default: default:
ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr);
} }
} }
@ -100,7 +102,20 @@ void ReadHWRegs(Service::Interface* self) {
void RegisterInterruptRelayQueue(Service::Interface* self) { void RegisterInterruptRelayQueue(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; u32 flags = cmd_buff[1];
u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling u32 event_handle = cmd_buff[3];
_assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!");
g_event_handle = event_handle;
Kernel::SetEventLocked(event_handle, false);
// Hack - This function will permanently set the state of the GSP event such that GPU command
// synchronization barriers always passthrough. Correct solution would be to set this after the
// GPU as processed all queued up commands, but due to the emulator being single-threaded they
// will always be ready.
Kernel::SetPermanentLock(event_handle, true);
cmd_buff[2] = g_thread_id; // ThreadID cmd_buff[2] = g_thread_id; // ThreadID
} }
@ -117,43 +132,43 @@ void TriggerCmdReqQueue(Service::Interface* self) {
break; break;
default: default:
ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]);
} }
GX_FinishCommand(g_thread_id); GX_FinishCommand(g_thread_id);
} }
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, NULL, "WriteHWRegs"}, {0x00010082, nullptr, "WriteHWRegs"},
{0x00020084, NULL, "WriteHWRegsWithMask"}, {0x00020084, nullptr, "WriteHWRegsWithMask"},
{0x00030082, NULL, "WriteHWRegRepeat"}, {0x00030082, nullptr, "WriteHWRegRepeat"},
{0x00040080, ReadHWRegs, "ReadHWRegs"}, {0x00040080, ReadHWRegs, "ReadHWRegs"},
{0x00050200, NULL, "SetBufferSwap"}, {0x00050200, nullptr, "SetBufferSwap"},
{0x00060082, NULL, "SetCommandList"}, {0x00060082, nullptr, "SetCommandList"},
{0x000700C2, NULL, "RequestDma"}, {0x000700C2, nullptr, "RequestDma"},
{0x00080082, NULL, "FlushDataCache"}, {0x00080082, nullptr, "FlushDataCache"},
{0x00090082, NULL, "InvalidateDataCache"}, {0x00090082, nullptr, "InvalidateDataCache"},
{0x000A0044, NULL, "RegisterInterruptEvents"}, {0x000A0044, nullptr, "RegisterInterruptEvents"},
{0x000B0040, NULL, "SetLcdForceBlack"}, {0x000B0040, nullptr, "SetLcdForceBlack"},
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
{0x000D0140, NULL, "SetDisplayTransfer"}, {0x000D0140, nullptr, "SetDisplayTransfer"},
{0x000E0180, NULL, "SetTextureCopy"}, {0x000E0180, nullptr, "SetTextureCopy"},
{0x000F0200, NULL, "SetMemoryFill"}, {0x000F0200, nullptr, "SetMemoryFill"},
{0x00100040, NULL, "SetAxiConfigQoSMode"}, {0x00100040, nullptr, "SetAxiConfigQoSMode"},
{0x00110040, NULL, "SetPerfLogMode"}, {0x00110040, nullptr, "SetPerfLogMode"},
{0x00120000, NULL, "GetPerfLog"}, {0x00120000, nullptr, "GetPerfLog"},
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
{0x00140000, NULL, "UnregisterInterruptRelayQueue"}, {0x00140000, nullptr, "UnregisterInterruptRelayQueue"},
{0x00150002, NULL, "TryAcquireRight"}, {0x00150002, nullptr, "TryAcquireRight"},
{0x00160042, NULL, "AcquireRight"}, {0x00160042, nullptr, "AcquireRight"},
{0x00170000, NULL, "ReleaseRight"}, {0x00170000, nullptr, "ReleaseRight"},
{0x00180000, NULL, "ImportDisplayCaptureInfo"}, {0x00180000, nullptr, "ImportDisplayCaptureInfo"},
{0x00190000, NULL, "SaveVramSysArea"}, {0x00190000, nullptr, "SaveVramSysArea"},
{0x001A0000, NULL, "RestoreVramSysArea"}, {0x001A0000, nullptr, "RestoreVramSysArea"},
{0x001B0000, NULL, "ResetGpuCore"}, {0x001B0000, nullptr, "ResetGpuCore"},
{0x001C0040, NULL, "SetLedForceOff"}, {0x001C0040, nullptr, "SetLedForceOff"},
{0x001D0040, NULL, "SetTestCommand"}, {0x001D0040, nullptr, "SetTestCommand"},
{0x001E0080, NULL, "SetInternalPriorities"}, {0x001E0080, nullptr, "SetInternalPriorities"},
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -13,11 +13,11 @@
namespace HID_User { namespace HID_User {
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {
{0x000A0000, NULL, "GetIPCHandles"}, {0x000A0000, nullptr, "GetIPCHandles"},
{0x00110000, NULL, "EnableAccelerometer"}, {0x00110000, nullptr, "EnableAccelerometer"},
{0x00130000, NULL, "EnableGyroscopeLow"}, {0x00130000, nullptr, "EnableGyroscopeLow"},
{0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
{0x00160000, NULL, "GetGyroscopeLowCalibrateParam"}, {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,32 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "common/log.h"
#include "core/hle/hle.h"
#include "core/hle/service/ndm.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace NDM_U
namespace NDM_U {
const Interface::FunctionInfo FunctionTable[] = {
{0x00060040, nullptr, "SuspendDaemons"},
{0x00080040, nullptr, "DisableWifiUsage"},
{0x00090000, nullptr, "EnableWifiUsage"},
{0x00140040, nullptr, "OverrideDefaultDaemons"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interface class
Interface::Interface() {
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
}
Interface::~Interface() {
}
} // namespace

View file

@ -0,0 +1,33 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace NDM
// No idea what this is
namespace NDM_U {
class Interface : public Service::Interface {
public:
Interface();
~Interface();
/**
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
const char *GetPortName() const {
return "ndm:u";
}
};
} // namespace

View file

@ -12,13 +12,14 @@
#include "core/hle/service/apt.h" #include "core/hle/service/apt.h"
#include "core/hle/service/gsp.h" #include "core/hle/service/gsp.h"
#include "core/hle/service/hid.h" #include "core/hle/service/hid.h"
#include "core/hle/service/ndm.h"
#include "core/hle/service/srv.h" #include "core/hle/service/srv.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
namespace Service { namespace Service {
Manager* g_manager = NULL; ///< Service manager Manager* g_manager = nullptr; ///< Service manager
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Manager class // Service Manager class
@ -55,7 +56,7 @@ Interface* Manager::FetchFromHandle(Handle handle) {
Interface* Manager::FetchFromPortName(std::string port_name) { Interface* Manager::FetchFromPortName(std::string port_name) {
auto itr = m_port_map.find(port_name); auto itr = m_port_map.find(port_name);
if (itr == m_port_map.end()) { if (itr == m_port_map.end()) {
return NULL; return nullptr;
} }
return FetchFromHandle(itr->second); return FetchFromHandle(itr->second);
} }
@ -72,14 +73,15 @@ void Init() {
g_manager->AddService(new APT_U::Interface); g_manager->AddService(new APT_U::Interface);
g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface); g_manager->AddService(new HID_User::Interface);
g_manager->AddService(new NDM_U::Interface);
NOTICE_LOG(HLE, "Services initialized OK"); NOTICE_LOG(HLE, "initialized OK");
} }
/// Shutdown ServiceManager /// Shutdown ServiceManager
void Shutdown() { void Shutdown() {
delete g_manager; delete g_manager;
NOTICE_LOG(HLE, "Services shutdown OK"); NOTICE_LOG(HLE, "shutdown OK");
} }

View file

@ -39,8 +39,8 @@ class Interface : public Kernel::Object {
friend class Manager; friend class Manager;
public: public:
const char *GetName() { return GetPortName(); } const char *GetName() const { return GetPortName(); }
const char *GetTypeName() { return GetPortName(); } const char *GetTypeName() const { return GetPortName(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
@ -76,22 +76,31 @@ public:
} }
/** /**
* Called when svcSendSyncRequest is called, loads command buffer and executes comand * Synchronize kernel object
* @return Return result of svcSendSyncRequest passed back to user app * @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/ */
Result Sync() { Result SyncRequest(bool* wait) {
u32* cmd_buff = GetCommandBuffer(); u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]); auto itr = m_functions.find(cmd_buff[0]);
if (itr == m_functions.end()) { if (itr == m_functions.end()) {
ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!", ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
GetPortName(), cmd_buff[0]); GetPortName(), cmd_buff[0]);
return -1;
// TODO(bunnei): Hack - ignore error
u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[1] = 0;
return 0;
} }
if (itr->second.func == NULL) { if (itr->second.func == nullptr) {
ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!", ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
GetPortName(), itr->second.name.c_str()); GetPortName(), itr->second.name.c_str());
return -1;
// TODO(bunnei): Hack - ignore error
u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[1] = 0;
return 0;
} }
itr->second.func(this); itr->second.func(this);
@ -99,6 +108,17 @@ public:
return 0; // TODO: Implement return from actual function return 0; // TODO: Implement return from actual function
} }
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result WaitSynchronization(bool* wait) {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "unimplemented function");
return 0;
}
protected: protected:
/** /**

View file

@ -5,21 +5,28 @@
#include "core/hle/hle.h" #include "core/hle/hle.h"
#include "core/hle/service/srv.h" #include "core/hle/service/srv.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/kernel/mutex.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SRV // Namespace SRV
namespace SRV { namespace SRV {
Handle g_mutex = 0;
void Initialize(Service::Interface* self) { void Initialize(Service::Interface* self) {
NOTICE_LOG(OSHLE, "SRV::Sync - Initialize"); DEBUG_LOG(OSHLE, "called");
if (!g_mutex) {
g_mutex = Kernel::CreateMutex(true, "SRV:Lock");
}
} }
void GetProcSemaphore(Service::Interface* self) { void GetProcSemaphore(Service::Interface* self) {
DEBUG_LOG(OSHLE, "called");
// Get process semaphore? // Get process semaphore?
u32* cmd_buff = Service::GetCommandBuffer(); u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception cmd_buff[1] = 0; // No error
cmd_buff[3] = g_mutex; // Return something... 0 == nullptr, raises an exception
} }
void GetServiceHandle(Service::Interface* self) { void GetServiceHandle(Service::Interface* self) {
@ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) {
std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(), if (nullptr != service) {
service->GetHandle());
if (NULL != service) {
cmd_buff[3] = service->GetHandle(); cmd_buff[3] = service->GetHandle();
DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} else { } else {
ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str()); ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
res = -1; res = -1;
} }
cmd_buff[1] = res; cmd_buff[1] = res;
//return res;
} }
const Interface::FunctionInfo FunctionTable[] = { const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, Initialize, "Initialize"}, {0x00010002, Initialize, "Initialize"},
{0x00020000, GetProcSemaphore, "GetProcSemaphore"}, {0x00020000, GetProcSemaphore, "GetProcSemaphore"},
{0x00030100, NULL, "RegisterService"}, {0x00030100, nullptr, "RegisterService"},
{0x000400C0, NULL, "UnregisterService"}, {0x000400C0, nullptr, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"}, {0x00050100, GetServiceHandle, "GetServiceHandle"},
}; };

View file

@ -26,12 +26,6 @@ public:
return "srv:"; return "srv:";
} }
/**
* Called when svcSendSyncRequest is called, loads command buffer and executes comand
* @return Return result of svcSendSyncRequest passed back to user app
*/
Result Sync();
}; };
} // namespace } // namespace

View file

@ -9,6 +9,7 @@
#include "core/mem_map.h" #include "core/mem_map.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h" #include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -16,7 +17,6 @@
#include "core/hle/function_wrappers.h" #include "core/hle/function_wrappers.h"
#include "core/hle/svc.h" #include "core/hle/svc.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/kernel/thread.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SVC // Namespace SVC
@ -34,40 +34,32 @@ enum MapMemoryPermission {
}; };
/// Map application or GSP heap memory /// Map application or GSP heap memory
Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
u32* outaddr = (u32*)_outaddr; DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
u32 virtual_address = 0x00000000;
DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
operation, addr0, addr1, size, permissions); operation, addr0, addr1, size, permissions);
switch (operation) { switch (operation) {
// Map normal heap memory // Map normal heap memory
case MEMORY_OPERATION_HEAP: case MEMORY_OPERATION_HEAP:
virtual_address = Memory::MapBlock_Heap(size, operation, permissions); *out_addr = Memory::MapBlock_Heap(size, operation, permissions);
break; break;
// Map GSP heap memory // Map GSP heap memory
case MEMORY_OPERATION_GSP_HEAP: case MEMORY_OPERATION_GSP_HEAP:
virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions);
break; break;
// Unknown ControlMemory operation // Unknown ControlMemory operation
default: default:
ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); ERROR_LOG(SVC, "unknown operation=0x%08X", operation);
} }
if (NULL != outaddr) {
*outaddr = virtual_address;
}
Core::g_app_core->SetReg(1, virtual_address);
return 0; return 0;
} }
/// Maps a memory block to specified address /// Maps a memory block to specified address
Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
memblock, addr, mypermissions, otherpermission); memblock, addr, mypermissions, otherpermission);
switch (mypermissions) { switch (mypermissions) {
case MEMORY_PERMISSION_NORMAL: case MEMORY_PERMISSION_NORMAL:
@ -76,88 +68,146 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
Memory::MapBlock_Shared(memblock, addr, mypermissions); Memory::MapBlock_Shared(memblock, addr, mypermissions);
break; break;
default: default:
ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions);
} }
return 0; return 0;
} }
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
Result ConnectToPort(void* out, const char* port_name) { Result ConnectToPort(Handle* out, const char* port_name) {
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
if (service) {
Core::g_app_core->SetReg(1, service->GetHandle()); DEBUG_LOG(SVC, "called port_name=%s", port_name);
} else { _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!");
PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name);
} *out = service->GetHandle();
DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
return 0; return 0;
} }
/// Synchronize to an OS service /// Synchronize to an OS service
Result SendSyncRequest(Handle handle) { Result SendSyncRequest(Handle handle) {
DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
Service::Interface* service = Service::g_manager->FetchFromHandle(handle);
service->Sync(); _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
return 0; DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName());
bool wait = false;
Result res = object->SyncRequest(&wait);
if (wait) {
Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
}
return res;
} }
/// Close a handle /// Close a handle
Result CloseHandle(Handle handle) { Result CloseHandle(Handle handle) {
// ImplementMe // ImplementMe
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
return 0; return 0;
} }
/// Wait for a handle to synchronize, timeout after the specified nanoseconds /// Wait for a handle to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", // TODO(bunnei): Do something with nano_seconds, currently ignoring this
handle, nano_seconds); bool wait = false;
Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(),
object->GetName(), nano_seconds);
_assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
Result res = object->WaitSynchronization(&wait);
// Check for next thread to schedule
if (wait) {
HLE::Reschedule(__func__);
return 0; return 0;
} }
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds return res;
Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { }
s32* out = (s32*)_out;
Handle* handles = (Handle*)_handles;
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
s64 nano_seconds) {
// TODO(bunnei): Do something with nano_seconds, currently ignoring this
bool unlock_all = true;
bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
handle_count, (wait_all ? "true" : "false"), nano_seconds); handle_count, (wait_all ? "true" : "false"), nano_seconds);
for (u32 i = 0; i < handle_count; i++) { // Iterate through each handle, synchronize kernel object
DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); for (s32 i = 0; i < handle_count; i++) {
bool wait = false;
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
_assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object "
"is nullptr!", handles[i]);
DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(),
object->GetName());
Result res = object->WaitSynchronization(&wait);
if (!wait && !wait_all) {
*out = i;
return 0;
} else {
unlock_all = false;
} }
Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? }
if (wait_all && unlock_all) {
*out = handle_count;
return 0;
}
// Check for next thread to schedule
HLE::Reschedule(__func__);
return 0; return 0;
} }
/// Create an address arbiter (to allocate access to shared resources) /// Create an address arbiter (to allocate access to shared resources)
Result CreateAddressArbiter(void* arbiter) { Result CreateAddressArbiter(void* arbiter) {
// ImplementMe ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
Core::g_app_core->SetReg(1, 0xFABBDADD); Core::g_app_core->SetReg(1, 0xFABBDADD);
return 0; return 0;
} }
/// Arbitrate address
Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) {
ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
ArbitrationType type = (ArbitrationType)_type;
Memory::Write32(addr, type);
return 0;
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit /// Used to output a message on a debug hardware unit - does nothing on a retail unit
void OutputDebugString(const char* string) { void OutputDebugString(const char* string) {
NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); OS_LOG(SVC, "%s", string);
} }
/// Get resource limit /// Get resource limit
Result GetResourceLimit(void* resource_limit, Handle process) { Result GetResourceLimit(Handle* resource_limit, Handle process) {
// With regards to proceess values: // With regards to proceess values:
// 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
// the current KThread. // the current KThread.
DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); *resource_limit = 0xDEADBEEF;
Core::g_app_core->SetReg(1, 0xDEADBEEF); ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
return 0; return 0;
} }
/// Get resource limit current values /// Get resource limit current values
Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
//s64* values = (s64*)_values; s32 name_count) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
resource_limit, names, name_count); resource_limit, names, name_count);
Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
return 0; return 0;
@ -180,179 +230,234 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
Core::g_app_core->SetReg(1, thread); Core::g_app_core->SetReg(1, thread);
DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
"threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point, "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
name.c_str(), arg, stack_top, priority, processor_id, thread); name.c_str(), arg, stack_top, priority, processor_id, thread);
return 0; return 0;
} }
/// Called when a thread exits
u32 ExitThread() {
Handle thread = Kernel::GetCurrentThreadHandle();
DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
Kernel::StopThread(thread, __func__);
HLE::Reschedule(__func__);
return 0;
}
/// Gets the priority for the specified thread
Result GetThreadPriority(s32* priority, Handle handle) {
*priority = Kernel::GetThreadPriority(handle);
return 0;
}
/// Sets the priority for the specified thread
Result SetThreadPriority(Handle handle, s32 priority) {
return Kernel::SetThreadPriority(handle, priority);
}
/// Create a mutex /// Create a mutex
Result CreateMutex(void* _mutex, u32 initial_locked) { Result CreateMutex(Handle* mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
*mutex = Kernel::CreateMutex((initial_locked != 0)); *mutex = Kernel::CreateMutex((initial_locked != 0));
Core::g_app_core->SetReg(1, *mutex); DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",
DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",
initial_locked ? "true" : "false", *mutex); initial_locked ? "true" : "false", *mutex);
return 0; return 0;
} }
/// Release a mutex /// Release a mutex
Result ReleaseMutex(Handle handle) { Result ReleaseMutex(Handle handle) {
DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); DEBUG_LOG(SVC, "called handle=0x%08X", handle);
_assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!");
Kernel::ReleaseMutex(handle); Kernel::ReleaseMutex(handle);
return 0; return 0;
} }
/// Get current thread ID /// Get current thread ID
Result GetThreadId(void* thread_id, u32 thread) { Result GetThreadId(u32* thread_id, Handle thread) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
return 0; return 0;
} }
/// Query memory /// Query memory
Result QueryMemory(void *_info, void *_out, u32 addr) { Result QueryMemory(void* info, void* out, u32 addr) {
MemoryInfo* info = (MemoryInfo*) _info; ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
PageInfo* out = (PageInfo*) _out;
DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
return 0; return 0;
} }
/// Create an event /// Create an event
Result CreateEvent(void* _event, u32 reset_type) { Result CreateEvent(Handle* evt, u32 reset_type) {
Handle* event = (Handle*)_event; *evt = Kernel::CreateEvent((ResetType)reset_type);
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",
Core::g_app_core->SetReg(1, 0xBADC0DE0); reset_type, *evt);
return 0; return 0;
} }
/// Duplicates a kernel handle
Result DuplicateHandle(Handle* out, Handle handle) {
DEBUG_LOG(SVC, "called handle=0x%08X", handle);
// Translate kernel handles -> real handles
if (handle == Kernel::CurrentThread) {
handle = Kernel::GetCurrentThreadHandle();
}
_assert_msg_(KERNEL, (handle != Kernel::CurrentProcess),
"(UNIMPLEMENTED) process handle duplication!");
// TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
*out = handle;
return 0;
}
/// Signals an event
Result SignalEvent(Handle evt) {
Result res = Kernel::SignalEvent(evt);
DEBUG_LOG(SVC, "called event=0x%08X", evt);
return res;
}
/// Clears an event
Result ClearEvent(Handle evt) {
Result res = Kernel::ClearEvent(evt);
DEBUG_LOG(SVC, "called event=0x%08X", evt);
return res;
}
/// Sleep the current thread
void SleepThread(s64 nanoseconds) {
DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds);
}
const HLE::FunctionDef SVC_Table[] = { const HLE::FunctionDef SVC_Table[] = {
{0x00, NULL, "Unknown"}, {0x00, nullptr, "Unknown"},
{0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"}, {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
{0x02, WrapI_VVU<QueryMemory>, "QueryMemory"}, {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
{0x03, NULL, "ExitProcess"}, {0x03, nullptr, "ExitProcess"},
{0x04, NULL, "GetProcessAffinityMask"}, {0x04, nullptr, "GetProcessAffinityMask"},
{0x05, NULL, "SetProcessAffinityMask"}, {0x05, nullptr, "SetProcessAffinityMask"},
{0x06, NULL, "GetProcessIdealProcessor"}, {0x06, nullptr, "GetProcessIdealProcessor"},
{0x07, NULL, "SetProcessIdealProcessor"}, {0x07, nullptr, "SetProcessIdealProcessor"},
{0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
{0x09, NULL, "ExitThread"}, {0x09, HLE::Wrap<ExitThread>, "ExitThread"},
{0x0A, NULL, "SleepThread"}, {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
{0x0B, NULL, "GetThreadPriority"}, {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
{0x0C, NULL, "SetThreadPriority"}, {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
{0x0D, NULL, "GetThreadAffinityMask"}, {0x0D, nullptr, "GetThreadAffinityMask"},
{0x0E, NULL, "SetThreadAffinityMask"}, {0x0E, nullptr, "SetThreadAffinityMask"},
{0x0F, NULL, "GetThreadIdealProcessor"}, {0x0F, nullptr, "GetThreadIdealProcessor"},
{0x10, NULL, "SetThreadIdealProcessor"}, {0x10, nullptr, "SetThreadIdealProcessor"},
{0x11, NULL, "GetCurrentProcessorNumber"}, {0x11, nullptr, "GetCurrentProcessorNumber"},
{0x12, NULL, "Run"}, {0x12, nullptr, "Run"},
{0x13, WrapI_VU<CreateMutex>, "CreateMutex"}, {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
{0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"}, {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
{0x15, NULL, "CreateSemaphore"}, {0x15, nullptr, "CreateSemaphore"},
{0x16, NULL, "ReleaseSemaphore"}, {0x16, nullptr, "ReleaseSemaphore"},
{0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
{0x18, NULL, "SignalEvent"}, {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
{0x19, NULL, "ClearEvent"}, {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
{0x1A, NULL, "CreateTimer"}, {0x1A, nullptr, "CreateTimer"},
{0x1B, NULL, "SetTimer"}, {0x1B, nullptr, "SetTimer"},
{0x1C, NULL, "CancelTimer"}, {0x1C, nullptr, "CancelTimer"},
{0x1D, NULL, "ClearTimer"}, {0x1D, nullptr, "ClearTimer"},
{0x1E, NULL, "CreateMemoryBlock"}, {0x1E, nullptr, "CreateMemoryBlock"},
{0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
{0x20, NULL, "UnmapMemoryBlock"}, {0x20, nullptr, "UnmapMemoryBlock"},
{0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"}, {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
{0x22, NULL, "ArbitrateAddress"}, {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
{0x23, WrapI_U<CloseHandle>, "CloseHandle"}, {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
{0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
{0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"}, {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
{0x26, NULL, "SignalAndWait"}, {0x26, nullptr, "SignalAndWait"},
{0x27, NULL, "DuplicateHandle"}, {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
{0x28, NULL, "GetSystemTick"}, {0x28, nullptr, "GetSystemTick"},
{0x29, NULL, "GetHandleInfo"}, {0x29, nullptr, "GetHandleInfo"},
{0x2A, NULL, "GetSystemInfo"}, {0x2A, nullptr, "GetSystemInfo"},
{0x2B, NULL, "GetProcessInfo"}, {0x2B, nullptr, "GetProcessInfo"},
{0x2C, NULL, "GetThreadInfo"}, {0x2C, nullptr, "GetThreadInfo"},
{0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
{0x2E, NULL, "SendSyncRequest1"}, {0x2E, nullptr, "SendSyncRequest1"},
{0x2F, NULL, "SendSyncRequest2"}, {0x2F, nullptr, "SendSyncRequest2"},
{0x30, NULL, "SendSyncRequest3"}, {0x30, nullptr, "SendSyncRequest3"},
{0x31, NULL, "SendSyncRequest4"}, {0x31, nullptr, "SendSyncRequest4"},
{0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
{0x33, NULL, "OpenProcess"}, {0x33, nullptr, "OpenProcess"},
{0x34, NULL, "OpenThread"}, {0x34, nullptr, "OpenThread"},
{0x35, NULL, "GetProcessId"}, {0x35, nullptr, "GetProcessId"},
{0x36, NULL, "GetProcessIdOfThread"}, {0x36, nullptr, "GetProcessIdOfThread"},
{0x37, WrapI_VU<GetThreadId>, "GetThreadId"}, {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
{0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
{0x39, NULL, "GetResourceLimitLimitValues"}, {0x39, nullptr, "GetResourceLimitLimitValues"},
{0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
{0x3B, NULL, "GetThreadContext"}, {0x3B, nullptr, "GetThreadContext"},
{0x3C, NULL, "Break"}, {0x3C, nullptr, "Break"},
{0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"}, {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
{0x3E, NULL, "ControlPerformanceCounter"}, {0x3E, nullptr, "ControlPerformanceCounter"},
{0x3F, NULL, "Unknown"}, {0x3F, nullptr, "Unknown"},
{0x40, NULL, "Unknown"}, {0x40, nullptr, "Unknown"},
{0x41, NULL, "Unknown"}, {0x41, nullptr, "Unknown"},
{0x42, NULL, "Unknown"}, {0x42, nullptr, "Unknown"},
{0x43, NULL, "Unknown"}, {0x43, nullptr, "Unknown"},
{0x44, NULL, "Unknown"}, {0x44, nullptr, "Unknown"},
{0x45, NULL, "Unknown"}, {0x45, nullptr, "Unknown"},
{0x46, NULL, "Unknown"}, {0x46, nullptr, "Unknown"},
{0x47, NULL, "CreatePort"}, {0x47, nullptr, "CreatePort"},
{0x48, NULL, "CreateSessionToPort"}, {0x48, nullptr, "CreateSessionToPort"},
{0x49, NULL, "CreateSession"}, {0x49, nullptr, "CreateSession"},
{0x4A, NULL, "AcceptSession"}, {0x4A, nullptr, "AcceptSession"},
{0x4B, NULL, "ReplyAndReceive1"}, {0x4B, nullptr, "ReplyAndReceive1"},
{0x4C, NULL, "ReplyAndReceive2"}, {0x4C, nullptr, "ReplyAndReceive2"},
{0x4D, NULL, "ReplyAndReceive3"}, {0x4D, nullptr, "ReplyAndReceive3"},
{0x4E, NULL, "ReplyAndReceive4"}, {0x4E, nullptr, "ReplyAndReceive4"},
{0x4F, NULL, "ReplyAndReceive"}, {0x4F, nullptr, "ReplyAndReceive"},
{0x50, NULL, "BindInterrupt"}, {0x50, nullptr, "BindInterrupt"},
{0x51, NULL, "UnbindInterrupt"}, {0x51, nullptr, "UnbindInterrupt"},
{0x52, NULL, "InvalidateProcessDataCache"}, {0x52, nullptr, "InvalidateProcessDataCache"},
{0x53, NULL, "StoreProcessDataCache"}, {0x53, nullptr, "StoreProcessDataCache"},
{0x54, NULL, "FlushProcessDataCache"}, {0x54, nullptr, "FlushProcessDataCache"},
{0x55, NULL, "StartInterProcessDma"}, {0x55, nullptr, "StartInterProcessDma"},
{0x56, NULL, "StopDma"}, {0x56, nullptr, "StopDma"},
{0x57, NULL, "GetDmaState"}, {0x57, nullptr, "GetDmaState"},
{0x58, NULL, "RestartDma"}, {0x58, nullptr, "RestartDma"},
{0x59, NULL, "Unknown"}, {0x59, nullptr, "Unknown"},
{0x5A, NULL, "Unknown"}, {0x5A, nullptr, "Unknown"},
{0x5B, NULL, "Unknown"}, {0x5B, nullptr, "Unknown"},
{0x5C, NULL, "Unknown"}, {0x5C, nullptr, "Unknown"},
{0x5D, NULL, "Unknown"}, {0x5D, nullptr, "Unknown"},
{0x5E, NULL, "Unknown"}, {0x5E, nullptr, "Unknown"},
{0x5F, NULL, "Unknown"}, {0x5F, nullptr, "Unknown"},
{0x60, NULL, "DebugActiveProcess"}, {0x60, nullptr, "DebugActiveProcess"},
{0x61, NULL, "BreakDebugProcess"}, {0x61, nullptr, "BreakDebugProcess"},
{0x62, NULL, "TerminateDebugProcess"}, {0x62, nullptr, "TerminateDebugProcess"},
{0x63, NULL, "GetProcessDebugEvent"}, {0x63, nullptr, "GetProcessDebugEvent"},
{0x64, NULL, "ContinueDebugEvent"}, {0x64, nullptr, "ContinueDebugEvent"},
{0x65, NULL, "GetProcessList"}, {0x65, nullptr, "GetProcessList"},
{0x66, NULL, "GetThreadList"}, {0x66, nullptr, "GetThreadList"},
{0x67, NULL, "GetDebugThreadContext"}, {0x67, nullptr, "GetDebugThreadContext"},
{0x68, NULL, "SetDebugThreadContext"}, {0x68, nullptr, "SetDebugThreadContext"},
{0x69, NULL, "QueryDebugProcessMemory"}, {0x69, nullptr, "QueryDebugProcessMemory"},
{0x6A, NULL, "ReadProcessMemory"}, {0x6A, nullptr, "ReadProcessMemory"},
{0x6B, NULL, "WriteProcessMemory"}, {0x6B, nullptr, "WriteProcessMemory"},
{0x6C, NULL, "SetHardwareBreakPoint"}, {0x6C, nullptr, "SetHardwareBreakPoint"},
{0x6D, NULL, "GetDebugThreadParam"}, {0x6D, nullptr, "GetDebugThreadParam"},
{0x6E, NULL, "Unknown"}, {0x6E, nullptr, "Unknown"},
{0x6F, NULL, "Unknown"}, {0x6F, nullptr, "Unknown"},
{0x70, NULL, "ControlProcessMemory"}, {0x70, nullptr, "ControlProcessMemory"},
{0x71, NULL, "MapProcessMemory"}, {0x71, nullptr, "MapProcessMemory"},
{0x72, NULL, "UnmapProcessMemory"}, {0x72, nullptr, "UnmapProcessMemory"},
{0x73, NULL, "Unknown"}, {0x73, nullptr, "Unknown"},
{0x74, NULL, "Unknown"}, {0x74, nullptr, "Unknown"},
{0x75, NULL, "Unknown"}, {0x75, nullptr, "Unknown"},
{0x76, NULL, "TerminateProcess"}, {0x76, nullptr, "TerminateProcess"},
{0x77, NULL, "Unknown"}, {0x77, nullptr, "Unknown"},
{0x78, NULL, "CreateResourceLimit"}, {0x78, nullptr, "CreateResourceLimit"},
{0x79, NULL, "Unknown"}, {0x79, nullptr, "Unknown"},
{0x7A, NULL, "Unknown"}, {0x7A, nullptr, "Unknown"},
{0x7B, NULL, "Unknown"}, {0x7B, nullptr, "Unknown"},
{0x7C, NULL, "KernelSetState"}, {0x7C, nullptr, "KernelSetState"},
{0x7D, NULL, "QueryProcessMemory"}, {0x7D, nullptr, "QueryProcessMemory"},
}; };
void Register() { void Register() {

View file

@ -29,6 +29,10 @@ struct ThreadContext {
u32 fpu_registers[32]; u32 fpu_registers[32];
u32 fpscr; u32 fpscr;
u32 fpexc; u32 fpexc;
// These are not part of native ThreadContext, but needed by emu
u32 reg_15;
u32 mode;
}; };
enum ResetType { enum ResetType {
@ -38,6 +42,15 @@ enum ResetType {
RESETTYPE_MAX_BIT = (1u << 31), RESETTYPE_MAX_BIT = (1u << 31),
}; };
enum ArbitrationType {
ARBITRATIONTYPE_SIGNAL,
ARBITRATIONTYPE_WAIT_IF_LESS_THAN,
ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN,
ARBITRATIONTYPE_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
ARBITRATIONTYPE_MAX_BIT = (1u << 31)
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SVC // Namespace SVC

View file

@ -17,8 +17,6 @@ namespace LCD {
Registers g_regs; Registers g_regs;
static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second
u64 g_last_ticks = 0; ///< Last CPU ticks u64 g_last_ticks = 0; ///< Last CPU ticks
/** /**

View file

@ -8,6 +8,9 @@
namespace LCD { namespace LCD {
static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
struct Registers { struct Registers {
u32 framebuffer_top_left_1; u32 framebuffer_top_left_1;
u32 framebuffer_top_left_2; u32 framebuffer_top_left_2;

View file

@ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) {
var = *((const T*)&g_vram[vaddr & VRAM_MASK]); var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
} else { } else {
//_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
} }
} }
@ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) {
// Error out... // Error out...
} else { } else {
_assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
data, vaddr);
} }
} }