Conflicts:
	src/core/hle/function_wrappers.h
	src/core/hle/service/gsp.cpp
master
bunnei 2014-06-14 12:13:16 +07:00
commit 004df76795
41 changed files with 1279 additions and 1235 deletions

@ -48,7 +48,7 @@ void DisassemblerWidget::Init()
unsigned int curInstAddr = base_addr;
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);
model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0'))));

@ -259,14 +259,17 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
switch (Level)
{
case OS_LEVEL: // light yellow
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case NOTICE_LEVEL: // light green
Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
break;
case ERROR_LEVEL: // light red
Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
case WARNING_LEVEL: // light yellow
Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case WARNING_LEVEL: // light purple
Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case INFO_LEVEL: // cyan
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;
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);
WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL);
printf(Text);
#else
char ColorAttr[16] = "";
char ResetAttr[16] = "";

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

@ -10,14 +10,16 @@
#include "common/thread.h"
#include "common/file_util.h"
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
const char *file, int line, const char* fmt, ...)
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
const char* function, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
if (LogManager::GetInstance())
if (LogManager::GetInstance()) {
LogManager::GetInstance()->Log(level, type,
file, line, fmt, args);
file, line, function, fmt, args);
}
va_end(args);
}
@ -88,6 +90,8 @@ LogManager::LogManager()
m_Log[i]->AddListener(m_debuggerLog);
#endif
}
m_consoleLog->Open();
}
LogManager::~LogManager()
@ -107,8 +111,8 @@ LogManager::~LogManager()
delete m_debuggerLog;
}
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
const char *file, int line, const char *format, va_list args)
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
int line, const char* function, const char *fmt, va_list args)
{
char temp[MAX_MSGLEN];
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())
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
Host_SysMessage(msg);
#endif
printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this
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_shortName, shortName, 32);
m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL;
m_level = LogTypes::MAX_LOGLEVEL;
}
// LogContainer

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

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

@ -89,6 +89,9 @@ public:
*/
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
u64 GetNumInstructions() {
return num_instructions;

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

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

@ -4456,6 +4456,7 @@ ARMul_Emulate26 (ARMul_State * state)
}
/* Drop through. */
case 0xe0:
case 0xe4:
case 0xe6:
case 0xe8:
@ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state)
/* Co-Processor Register Transfers (MRC) and Data Ops. */
case 0xe0:
case 0xe1:
case 0xe3:
case 0xe5:
@ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state)
case 0xfd:
case 0xfe:
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);
ARMul_Abort (state, ARMul_SWIV);
break;
}
}

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

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

@ -165,6 +165,12 @@
<ClCompile Include="arm\interpreter\armcopro.cpp">
<Filter>arm\interpreter</Filter>
</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>
<ClInclude Include="arm\disassembler\arm_disasm.h">
@ -295,6 +301,12 @@
<ClInclude Include="hle\kernel\mutex.h">
<Filter>hle\kernel</Filter>
</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>
<Text Include="CMakeLists.txt" />

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

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

@ -1,19 +1,6 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// 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/.
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
@ -21,725 +8,107 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
// For easy parameter parsing and return value processing.
namespace HLE {
//32bit wrappers
template<void func()> void WrapV_V() {
func();
#define PARAM(n) Core::g_app_core->GetReg(n)
#define RETURN(n) Core::g_app_core->SetReg(0, n)
////////////////////////////////////////////////////////////////////////////////////////////////////
// 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());
}
template<int func(void *, const char *)> void WrapI_VC() {
u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)));
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));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Function wrappers that return type void
template<u32 func(const char *, const char *)> void WrapU_CC() {
int retval = func(Memory::GetCharPointer(PARAM(0)),
Memory::GetCharPointer(PARAM(1)));
RETURN(retval);
template<void func(s64)> void Wrap() {
func(((s64)PARAM(1) << 32) | PARAM(0));
}
template<void func(const char*)> void WrapV_C() {
template<void func(const char*)> void Wrap() {
func(Memory::GetCharPointer(PARAM(0)));
}
template<void func(const char *, int)> void WrapV_CI() {
func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
}
#undef PARAM
#undef RETURN
template<u32 func(const char *, int)> void WrapU_CI() {
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);
}
} // namespace HLE

@ -7,6 +7,7 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
#include "core/hle/svc.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -15,11 +16,13 @@ namespace HLE {
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) {
u32 func_num = opcode & 0xFFFFFF; // 8 bits
if (func_num > 0xFF) {
ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num);
return NULL;
ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
return nullptr;
}
return &g_module_db[0].func_table[func_num];
}
@ -33,19 +36,16 @@ void CallSVC(u32 opcode) {
if (info->func) {
info->func();
} 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) {
// TODO: ImplementMe
}
void ReSchedule(const char *reason) {
void Reschedule(const char *reason) {
#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
// TODO: ImplementMe
Core::g_app_core->PrepareReschedule();
g_reschedule = true;
}
void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {

@ -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 {
extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
typedef u32 Addr;
typedef void (*Func)();
@ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func
void CallSVC(u32 opcode);
void EatCycles(u32 cycles);
void ReSchedule(const char *reason);
void Reschedule(const char *reason);
void Init();

@ -0,0 +1,159 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <map>
#include <algorithm>
#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

@ -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

@ -2,8 +2,6 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <string.h>
#include "common/common.h"
@ -14,6 +12,7 @@
namespace Kernel {
Handle g_main_thread = 0;
ObjectPool g_object_pool;
ObjectPool::ObjectPool() {
@ -127,16 +126,20 @@ Object* ObjectPool::CreateByIDType(int type) {
default:
ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
return NULL;
return nullptr;
}
}
/// Initialize the kernel
void Init() {
Kernel::ThreadingInit();
}
/// Shutdown the kernel
void Shutdown() {
Kernel::ThreadingShutdown();
g_object_pool.Clear(); // Free all kernel objects
}
/**
@ -150,7 +153,7 @@ bool LoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point);
// 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;
}

@ -11,6 +11,11 @@ typedef s32 Result;
namespace Kernel {
enum KernelHandle {
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
enum class HandleType : u32 {
Unknown = 0,
Port = 1,
@ -39,9 +44,26 @@ class Object : NonCopyable {
public:
virtual ~Object() {}
Handle GetHandle() const { return handle; }
virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
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 {
@ -143,6 +165,13 @@ private:
};
extern ObjectPool g_object_pool;
extern Handle g_main_thread;
/// Initialize the kernel
void Init();
/// Shutdown the kernel
void Shutdown();
/**
* Loads executable stored at specified address

@ -8,13 +8,15 @@
#include "common/common.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
class Mutex : public Object {
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; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
@ -23,6 +25,34 @@ public:
bool locked; ///< Current locked state
Handle lock_thread; ///< Handle to thread that currently has 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) {
MutexEraseLock(mutex);
bool woke_threads = false;
auto iter = mutex->waiting_threads.begin();
// Find the next waiting thread for the mutex...
while (!woke_threads && !mutex->waiting_threads.empty()) {
std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
woke_threads |= ReleaseMutexForThread(mutex, *iter);
mutex->waiting_threads.erase(iter);
}
@ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) {
*/
Result ReleaseMutex(Handle 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)) {
return -1;
}
@ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) {
* 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 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;
handle = Kernel::g_object_pool.Create(mutex);
mutex->locked = mutex->initial_locked = initial_locked;
mutex->name = name;
// Acquire mutex with current thread if initialized as locked...
if (mutex->locked) {
@ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) {
/**
* Creates a mutex
* @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;
Mutex* mutex = CreateMutex(handle, initial_locked);
Mutex* mutex = CreateMutex(handle, initial_locked, name);
return handle;
}

@ -13,14 +13,16 @@ namespace Kernel {
/**
* Releases a mutex
* @param handle Handle to mutex to release
* @return Result of operation, 0 on success, otherwise error code
*/
Result ReleaseMutex(Handle handle);
/**
* 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 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

@ -5,6 +5,7 @@
#include <stdio.h>
#include <list>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
@ -24,8 +25,8 @@ namespace Kernel {
class Thread : public Kernel::Object {
public:
const char* GetName() { return name; }
const char* GetTypeName() { return "Thread"; }
const char* GetName() const { return name; }
const char* GetTypeName() const { return "Thread"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
@ -36,6 +37,23 @@ public:
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 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;
u32 status;
@ -49,6 +67,9 @@ public:
s32 processor_id;
WaitType wait_type;
Handle wait_handle;
std::vector<Handle> waiting_threads;
char name[Kernel::MAX_NAME_LENGTH + 1];
};
@ -62,7 +83,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue;
Handle g_current_thread_handle;
Thread* g_current_thread;
/// Gets the current thread
inline Thread* GetCurrentThread() {
return g_current_thread;
@ -94,15 +114,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext));
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.cpsr = 0x1F; // Usermode
if (t->current_priority < lowest_priority) {
t->current_priority = t->initial_priority;
}
t->wait_type = WAITTYPE_NONE;
t->wait_handle = 0;
}
/// Change a thread to "ready" state
@ -122,6 +142,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
void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (!t || t->status == new_status) {
@ -132,7 +183,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (new_status == THREADSTATUS_WAIT) {
if (t->wait_type == WAITTYPE_NONE) {
printf("ERROR: Waittype none not allowed here\n");
ERROR_LOG(KERNEL, "Waittype none not allowed");
}
}
}
@ -166,7 +217,7 @@ void SwitchContext(Thread* t) {
t->wait_type = WAITTYPE_NONE;
LoadContext(t->context);
} else {
SetCurrentThread(NULL);
SetCurrentThread(nullptr);
}
}
@ -181,26 +232,43 @@ Thread* NextThread() {
next = g_thread_ready_queue.pop_first();
}
if (next == 0) {
return NULL;
return nullptr;
}
return Kernel::g_object_pool.GetFast<Thread>(next);
}
/// Puts the current thread in the wait state for the given type
void WaitCurrentThread(WaitType wait_type) {
Thread* t = GetCurrentThread();
t->wait_type = wait_type;
ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
Thread* thread = GetCurrentThread();
thread->wait_type = wait_type;
thread->wait_handle = wait_handle;
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
}
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle) {
u32 error;
Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error);
if (t) {
t->status &= ~THREADSTATUS_WAIT;
if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
ChangeReadyState(t, true);
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
if (thread) {
thread->status &= ~THREADSTATUS_WAIT;
if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
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 +280,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
_assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
"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_ready_queue.prepare(priority);
t->status = THREADSTATUS_DORMANT;
t->entry_point = entry_point;
t->stack_top = stack_top;
t->stack_size = stack_size;
t->initial_priority = t->current_priority = priority;
t->processor_id = processor_id;
t->wait_type = WAITTYPE_NONE;
thread->status = THREADSTATUS_DORMANT;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
thread->stack_size = stack_size;
thread->initial_priority = thread->current_priority = priority;
thread->processor_id = processor_id;
thread->wait_type = WAITTYPE_NONE;
thread->wait_handle = 0;
strncpy(t->name, name, Kernel::MAX_NAME_LENGTH);
t->name[Kernel::MAX_NAME_LENGTH] = '\0';
strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH);
thread->name[Kernel::MAX_NAME_LENGTH] = '\0';
return t;
return thread;
}
/// Creates a new thread - wrapper for external user
Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
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;
}
if ((u32)stack_size < 0x200) {
@ -258,31 +328,67 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
return -1;
}
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);
ResetThread(t, arg, 0);
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);
ResetThread(thread, arg, 0);
CallThread(thread);
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
Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle;
// 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);
ResetThread(t, 0, 0);
ResetThread(thread, 0, 0);
// If running another thread already, set it to "ready" state
Thread* cur = GetCurrentThread();
@ -291,24 +397,31 @@ Handle SetupMainThread(s32 priority, int stack_size) {
}
// Run new "main" thread
SetCurrentThread(t);
t->status = THREADSTATUS_RUNNING;
LoadContext(t->context);
SetCurrentThread(thread);
thread->status = THREADSTATUS_RUNNING;
LoadContext(thread->context);
return handle;
}
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule() {
Thread* prev = GetCurrentThread();
Thread* next = NextThread();
HLE::g_reschedule = false;
if (next > 0) {
INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
SwitchContext(next);
// Hack - automatically change previous thread (which would have been in "wait" state) to
// "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
// actually wait for whatever event it is supposed to be waiting on.
ChangeReadyState(prev, true);
// Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
// by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
// This results in the current thread yielding on a VBLANK once, and then it will be
// immediately placed back in the queue for execution.
if (prev->wait_type == WAITTYPE_VBLANK) {
ResumeThreadFromWait(prev->GetHandle());
}
}
}

@ -34,7 +34,7 @@ enum WaitType {
WAITTYPE_NONE,
WAITTYPE_SLEEP,
WAITTYPE_SEMA,
WAITTYPE_EVENTFLAG,
WAITTYPE_EVENT,
WAITTYPE_THREADEND,
WAITTYPE_VBLANK,
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)
void Reschedule();
/// Puts the current thread in the wait state for the given type
void WaitCurrentThread(WaitType wait_type);
/// Stops the current thread
void StopThread(Handle thread, const char* reason);
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);
@ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle);
/// Gets the current thread handle
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
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
void ThreadingInit();

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

@ -8,6 +8,7 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/gsp.h"
#include "core/hw/gpu.h"
@ -60,6 +61,7 @@ void GX_FinishCommand(u32 thread_id) {
namespace GSP_GPU {
Handle g_event_handle = 0;
u32 g_thread_id = 0;
enum {
@ -96,7 +98,7 @@ void ReadHWRegs(Service::Interface* self) {
break;
default:
ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr);
ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr);
}
}
@ -104,7 +106,19 @@ void ReadHWRegs(Service::Interface* self) {
void RegisterInterruptRelayQueue(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
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
}
@ -150,43 +164,43 @@ void TriggerCmdReqQueue(Service::Interface* self) {
}
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);
}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, NULL, "WriteHWRegs"},
{0x00020084, NULL, "WriteHWRegsWithMask"},
{0x00030082, NULL, "WriteHWRegRepeat"},
{0x00010082, nullptr, "WriteHWRegs"},
{0x00020084, nullptr, "WriteHWRegsWithMask"},
{0x00030082, nullptr, "WriteHWRegRepeat"},
{0x00040080, ReadHWRegs, "ReadHWRegs"},
{0x00050200, NULL, "SetBufferSwap"},
{0x00060082, NULL, "SetCommandList"},
{0x000700C2, NULL, "RequestDma"},
{0x00080082, NULL, "FlushDataCache"},
{0x00090082, NULL, "InvalidateDataCache"},
{0x000A0044, NULL, "RegisterInterruptEvents"},
{0x000B0040, NULL, "SetLcdForceBlack"},
{0x00050200, nullptr, "SetBufferSwap"},
{0x00060082, nullptr, "SetCommandList"},
{0x000700C2, nullptr, "RequestDma"},
{0x00080082, nullptr, "FlushDataCache"},
{0x00090082, nullptr, "InvalidateDataCache"},
{0x000A0044, nullptr, "RegisterInterruptEvents"},
{0x000B0040, nullptr, "SetLcdForceBlack"},
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
{0x000D0140, NULL, "SetDisplayTransfer"},
{0x000E0180, NULL, "SetTextureCopy"},
{0x000F0200, NULL, "SetMemoryFill"},
{0x00100040, NULL, "SetAxiConfigQoSMode"},
{0x00110040, NULL, "SetPerfLogMode"},
{0x00120000, NULL, "GetPerfLog"},
{0x000D0140, nullptr, "SetDisplayTransfer"},
{0x000E0180, nullptr, "SetTextureCopy"},
{0x000F0200, nullptr, "SetMemoryFill"},
{0x00100040, nullptr, "SetAxiConfigQoSMode"},
{0x00110040, nullptr, "SetPerfLogMode"},
{0x00120000, nullptr, "GetPerfLog"},
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
{0x00140000, NULL, "UnregisterInterruptRelayQueue"},
{0x00150002, NULL, "TryAcquireRight"},
{0x00160042, NULL, "AcquireRight"},
{0x00170000, NULL, "ReleaseRight"},
{0x00180000, NULL, "ImportDisplayCaptureInfo"},
{0x00190000, NULL, "SaveVramSysArea"},
{0x001A0000, NULL, "RestoreVramSysArea"},
{0x001B0000, NULL, "ResetGpuCore"},
{0x001C0040, NULL, "SetLedForceOff"},
{0x001D0040, NULL, "SetTestCommand"},
{0x001E0080, NULL, "SetInternalPriorities"},
{0x00140000, nullptr, "UnregisterInterruptRelayQueue"},
{0x00150002, nullptr, "TryAcquireRight"},
{0x00160042, nullptr, "AcquireRight"},
{0x00170000, nullptr, "ReleaseRight"},
{0x00180000, nullptr, "ImportDisplayCaptureInfo"},
{0x00190000, nullptr, "SaveVramSysArea"},
{0x001A0000, nullptr, "RestoreVramSysArea"},
{0x001B0000, nullptr, "ResetGpuCore"},
{0x001C0040, nullptr, "SetLedForceOff"},
{0x001D0040, nullptr, "SetTestCommand"},
{0x001E0080, nullptr, "SetInternalPriorities"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////

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

@ -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

@ -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

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

@ -39,8 +39,8 @@ class Interface : public Kernel::Object {
friend class Manager;
public:
const char *GetName() { return GetPortName(); }
const char *GetTypeName() { return GetPortName(); }
const char *GetName() const { return GetPortName(); }
const char *GetTypeName() const { return GetPortName(); }
static Kernel::HandleType GetStaticHandleType() { 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
* @return Return result of svcSendSyncRequest passed back to user app
* 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 Sync() {
Result SyncRequest(bool* wait) {
u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
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]);
return -1;
// TODO(bunnei): Hack - ignore error
u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[1] = 0;
return 0;
}
if (itr->second.func == NULL) {
ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",
if (itr->second.func == nullptr) {
ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
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);
@ -99,6 +108,17 @@ public:
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:
/**

@ -5,21 +5,28 @@
#include "core/hle/hle.h"
#include "core/hle/service/srv.h"
#include "core/hle/service/service.h"
#include "core/hle/kernel/mutex.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SRV
namespace SRV {
Handle g_mutex = 0;
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) {
DEBUG_LOG(OSHLE, "called");
// Get process semaphore?
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) {
@ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) {
std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(),
service->GetHandle());
if (NULL != service) {
if (nullptr != service) {
cmd_buff[3] = service->GetHandle();
DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} 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;
}
cmd_buff[1] = res;
//return res;
}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, Initialize, "Initialize"},
{0x00020000, GetProcSemaphore, "GetProcSemaphore"},
{0x00030100, NULL, "RegisterService"},
{0x000400C0, NULL, "UnregisterService"},
{0x00030100, nullptr, "RegisterService"},
{0x000400C0, nullptr, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"},
};

@ -26,12 +26,6 @@ public:
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

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

@ -29,6 +29,10 @@ struct ThreadContext {
u32 fpu_registers[32];
u32 fpscr;
u32 fpexc;
// These are not part of native ThreadContext, but needed by emu
u32 reg_15;
u32 mode;
};
enum ResetType {
@ -38,6 +42,15 @@ enum ResetType {
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

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

@ -8,6 +8,9 @@
namespace GPU {
static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
struct Registers {
enum Id : u32 {
FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left

@ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) {
var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
} 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...
} else {
_assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8,
data, vaddr);
ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
}
}

@ -8,6 +8,7 @@
#include "core/system.h"
#include "core/hw/hw.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "video_core/video_core.h"
@ -26,6 +27,7 @@ void Init(EmuWindow* emu_window) {
HLE::Init();
CoreTiming::Init();
VideoCore::Init(emu_window);
Kernel::Init();
}
void RunLoopFor(int cycles) {
@ -42,6 +44,7 @@ void Shutdown() {
HLE::Shutdown();
CoreTiming::Shutdown();
VideoCore::Shutdown();
Kernel::Shutdown();
g_ctr_file_system.Shutdown();
}