mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-14 23:00:05 +00:00
Merge branch 'hle-interface'
This commit is contained in:
commit
958bca606e
@ -55,8 +55,8 @@ enum LOG_TYPE {
|
||||
WII_IPC_HID,
|
||||
WII_IPC_HLE,
|
||||
WII_IPC_NET,
|
||||
WII_IPC_WC24,
|
||||
WII_IPC_SSL,
|
||||
NDMA,
|
||||
HLE,
|
||||
RENDER,
|
||||
LCD,
|
||||
HW,
|
||||
|
@ -67,9 +67,9 @@ LogManager::LogManager()
|
||||
m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER");
|
||||
m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD");
|
||||
m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET");
|
||||
m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24");
|
||||
m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL");
|
||||
m_Log[LogTypes::HW] = new LogContainer("HARDWARE", "HARDWARE");
|
||||
m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA");
|
||||
m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation");
|
||||
m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware");
|
||||
m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay");
|
||||
m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
|
||||
m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
|
||||
|
@ -17,6 +17,22 @@
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
/// Make a string lowercase
|
||||
void LowerStr(char* str) {
|
||||
for (int i = 0; str[i]; i++) {
|
||||
str[i] = tolower(str[ i ]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a string uppercase
|
||||
void UpperStr(char* str) {
|
||||
for (int i=0; i < strlen(str); i++) {
|
||||
if(str[i] >= 'a' && str[i] <= 'z') {
|
||||
str[i] &= 0xDF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// faster than sscanf
|
||||
bool AsciiToHex(const char* _szValue, u32& result)
|
||||
{
|
||||
|
@ -14,6 +14,12 @@
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
/// Make a string lowercase
|
||||
void LowerStr(char* str);
|
||||
|
||||
/// Make a string uppercase
|
||||
void UpperStr(char* str);
|
||||
|
||||
std::string StringFromFormat(const char* format, ...);
|
||||
// Cheap!
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
|
||||
|
@ -42,6 +42,13 @@ public:
|
||||
*/
|
||||
virtual u32 GetReg(int index) const = 0;
|
||||
|
||||
/**
|
||||
* Set an ARM register
|
||||
* @param index Register index (0-15)
|
||||
* @param value Value to set register to
|
||||
*/
|
||||
virtual void SetReg(int index, u32 value) = 0;
|
||||
|
||||
/**
|
||||
* Get the current CPSR register
|
||||
* @return Returns the value of the CPSR register
|
||||
@ -59,11 +66,13 @@ public:
|
||||
return m_num_instructions;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
/// Execture next instruction
|
||||
virtual void ExecuteInstruction() = 0;
|
||||
|
||||
private:
|
||||
|
||||
u64 m_num_instructions; ///< Number of instructions executed
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ARM_Interface);
|
||||
|
@ -31,30 +31,61 @@ ARM_Interpreter::ARM_Interpreter() {
|
||||
m_state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
|
||||
}
|
||||
|
||||
void ARM_Interpreter::SetPC(u32 pc) {
|
||||
m_state->pc = m_state->Reg[15] = pc;
|
||||
}
|
||||
|
||||
u32 ARM_Interpreter::GetPC() const {
|
||||
return m_state->pc;
|
||||
}
|
||||
|
||||
u32 ARM_Interpreter::GetReg(int index) const {
|
||||
return m_state->Reg[index];
|
||||
}
|
||||
|
||||
u32 ARM_Interpreter::GetCPSR() const {
|
||||
return m_state->Cpsr;
|
||||
}
|
||||
|
||||
u64 ARM_Interpreter::GetTicks() const {
|
||||
return ARMul_Time(m_state);
|
||||
}
|
||||
|
||||
ARM_Interpreter::~ARM_Interpreter() {
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Program Counter to an address
|
||||
* @param addr Address to set PC to
|
||||
*/
|
||||
void ARM_Interpreter::SetPC(u32 pc) {
|
||||
m_state->pc = m_state->Reg[15] = pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current Program Counter
|
||||
* @return Returns current PC
|
||||
*/
|
||||
u32 ARM_Interpreter::GetPC() const {
|
||||
return m_state->pc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ARM register
|
||||
* @param index Register index (0-15)
|
||||
* @return Returns the value in the register
|
||||
*/
|
||||
u32 ARM_Interpreter::GetReg(int index) const {
|
||||
return m_state->Reg[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an ARM register
|
||||
* @param index Register index (0-15)
|
||||
* @param value Value to set register to
|
||||
*/
|
||||
void ARM_Interpreter::SetReg(int index, u32 value) {
|
||||
m_state->Reg[index] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current CPSR register
|
||||
* @return Returns the value of the CPSR register
|
||||
*/
|
||||
u32 ARM_Interpreter::GetCPSR() const {
|
||||
return m_state->Cpsr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of clock ticks since the last reset
|
||||
* @return Returns number of clock ticks
|
||||
*/
|
||||
u64 ARM_Interpreter::GetTicks() const {
|
||||
return ARMul_Time(m_state);
|
||||
}
|
||||
|
||||
/// Execture next instruction
|
||||
void ARM_Interpreter::ExecuteInstruction() {
|
||||
m_state->step++;
|
||||
m_state->cycle++;
|
||||
|
@ -12,22 +12,55 @@
|
||||
|
||||
class ARM_Interpreter : virtual public ARM_Interface {
|
||||
public:
|
||||
|
||||
ARM_Interpreter();
|
||||
~ARM_Interpreter();
|
||||
|
||||
void ExecuteInstruction();
|
||||
|
||||
/**
|
||||
* Set the Program Counter to an address
|
||||
* @param addr Address to set PC to
|
||||
*/
|
||||
void SetPC(u32 pc);
|
||||
|
||||
/*
|
||||
* Get the current Program Counter
|
||||
* @return Returns current PC
|
||||
*/
|
||||
u32 GetPC() const;
|
||||
|
||||
/**
|
||||
* Get an ARM register
|
||||
* @param index Register index (0-15)
|
||||
* @return Returns the value in the register
|
||||
*/
|
||||
u32 GetReg(int index) const;
|
||||
|
||||
/**
|
||||
* Set an ARM register
|
||||
* @param index Register index (0-15)
|
||||
* @param value Value to set register to
|
||||
*/
|
||||
void SetReg(int index, u32 value);
|
||||
|
||||
/**
|
||||
* Get the current CPSR register
|
||||
* @return Returns the value of the CPSR register
|
||||
*/
|
||||
u32 GetCPSR() const;
|
||||
|
||||
/**
|
||||
* Returns the number of clock ticks since the last reset
|
||||
* @return Returns number of clock ticks
|
||||
*/
|
||||
u64 GetTicks() const;
|
||||
|
||||
protected:
|
||||
|
||||
/// Execture next instruction
|
||||
void ExecuteInstruction();
|
||||
|
||||
private:
|
||||
|
||||
ARMul_State* m_state;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ARM_Interpreter);
|
||||
|
@ -16,6 +16,8 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
|
||||
#include "arm_regformat.h"
|
||||
#include "armdefs.h"
|
||||
#include "armemu.h"
|
||||
@ -4558,6 +4560,7 @@ ARMul_Emulate26 (ARMul_State * state)
|
||||
// ARMul_OSHandleSWI (state, BITS (0, 23));
|
||||
// break;
|
||||
//}
|
||||
HLE::CallSyscall(instr);
|
||||
ARMul_Abort (state, ARMul_SWIV);
|
||||
break;
|
||||
}
|
||||
|
@ -229,6 +229,17 @@ extern ARMword isize;
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SETABORT_SKIPBRANCH(i, m, d) \
|
||||
do \
|
||||
{ \
|
||||
int SETABORT_mode = (m); \
|
||||
\
|
||||
ARMul_SetSPSR (state, SETABORT_mode, ARMul_GetCPSR (state)); \
|
||||
ARMul_SetCPSR (state, ((ARMul_GetCPSR (state) & ~(EMODE | TBIT)) \
|
||||
| (i) | SETABORT_mode)); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
//#ifndef MODE32
|
||||
#define VECTORS 0x20
|
||||
#define LEGALADDR 0x03ffffff
|
||||
|
@ -530,9 +530,13 @@ ARMul_Abort (ARMul_State * state, ARMword vector)
|
||||
isize);
|
||||
break;
|
||||
case ARMul_SWIV: /* Software Interrupt */
|
||||
SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE,
|
||||
// Modified SETABORT that doesn't branch to a SVC vector as we are implementing this in HLE
|
||||
// Instead of doing normal routine, backup R15 by one instruction (this is what PC will get
|
||||
// set to, making it the next instruction after the SVC call), and skip setting the LR.
|
||||
SETABORT_SKIPBRANCH (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE,
|
||||
isize);
|
||||
break;
|
||||
state->Reg[15] -= 4;
|
||||
return;
|
||||
case ARMul_PrefetchAbortV: /* Prefetch Abort */
|
||||
state->AbortAddr = 1;
|
||||
SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE,
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "armemu.h"
|
||||
//#include "ansidecl.h"
|
||||
#include "skyeye_defs.h"
|
||||
#include "core/hle/hle.h"
|
||||
|
||||
unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
|
||||
unsigned cpnum);
|
||||
//extern int skyeye_instr_debug;
|
||||
@ -734,39 +736,39 @@ ARMword
|
||||
ARMul_MRC (ARMul_State * state, ARMword instr)
|
||||
{
|
||||
unsigned cpab;
|
||||
ARMword result = 0;
|
||||
ARMword result = HLE::CallGetThreadCommandBuffer();
|
||||
|
||||
//printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr);
|
||||
if (!CP_ACCESS_ALLOWED (state, CPNum)) {
|
||||
//chy 2004-07-19 should fix in the future????!!!!
|
||||
//printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr);
|
||||
ARMul_UndefInstr (state, instr);
|
||||
return -1;
|
||||
}
|
||||
////printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr);
|
||||
//if (!CP_ACCESS_ALLOWED (state, CPNum)) {
|
||||
// //chy 2004-07-19 should fix in the future????!!!!
|
||||
// //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr);
|
||||
// ARMul_UndefInstr (state, instr);
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
|
||||
while (cpab == ARMul_BUSY) {
|
||||
ARMul_Icycles (state, 1, 0);
|
||||
if (IntPending (state)) {
|
||||
cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT,
|
||||
instr, 0);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr,
|
||||
&result);
|
||||
}
|
||||
if (cpab == ARMul_CANT) {
|
||||
printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr);
|
||||
ARMul_Abort (state, ARMul_UndefinedInstrV);
|
||||
/* Parent will destroy the flags otherwise. */
|
||||
result = ECC;
|
||||
}
|
||||
else {
|
||||
BUSUSEDINCPCN;
|
||||
ARMul_Ccycles (state, 1, 0);
|
||||
ARMul_Icycles (state, 1, 0);
|
||||
}
|
||||
//cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
|
||||
//while (cpab == ARMul_BUSY) {
|
||||
// ARMul_Icycles (state, 1, 0);
|
||||
// if (IntPending (state)) {
|
||||
// cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT,
|
||||
// instr, 0);
|
||||
// return (0);
|
||||
// }
|
||||
// else
|
||||
// cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr,
|
||||
// &result);
|
||||
//}
|
||||
//if (cpab == ARMul_CANT) {
|
||||
// printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr);
|
||||
// ARMul_Abort (state, ARMul_UndefinedInstrV);
|
||||
// /* Parent will destroy the flags otherwise. */
|
||||
// result = ECC;
|
||||
//}
|
||||
//else {
|
||||
// BUSUSEDINCPCN;
|
||||
// ARMul_Ccycles (state, 1, 0);
|
||||
// ARMul_Icycles (state, 1, 0);
|
||||
//}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ void Stop() {
|
||||
|
||||
/// Initialize the core
|
||||
int Init() {
|
||||
NOTICE_LOG(MASTER_LOG, "Core initialized OK");
|
||||
NOTICE_LOG(MASTER_LOG, "initialized OK");
|
||||
|
||||
g_disasm = new ARM_Disasm();
|
||||
g_app_core = new ARM_Interpreter();
|
||||
@ -54,7 +54,7 @@ void Shutdown() {
|
||||
delete g_app_core;
|
||||
delete g_sys_core;
|
||||
|
||||
NOTICE_LOG(MASTER_LOG, "Core shutdown OK");
|
||||
NOTICE_LOG(MASTER_LOG, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -152,8 +152,16 @@
|
||||
<ClCompile Include="elf\elf_reader.cpp" />
|
||||
<ClCompile Include="file_sys\directory_file_system.cpp" />
|
||||
<ClCompile Include="file_sys\meta_file_system.cpp" />
|
||||
<ClCompile Include="hle\hle.cpp" />
|
||||
<ClCompile Include="hle\service\apt.cpp" />
|
||||
<ClCompile Include="hle\service\gsp.cpp" />
|
||||
<ClCompile Include="hle\service\hid.cpp" />
|
||||
<ClCompile Include="hle\service\service.cpp" />
|
||||
<ClCompile Include="hle\service\srv.cpp" />
|
||||
<ClCompile Include="hle\syscall.cpp" />
|
||||
<ClCompile Include="hw\hw.cpp" />
|
||||
<ClCompile Include="hw\hw_lcd.cpp" />
|
||||
<ClCompile Include="hw\lcd.cpp" />
|
||||
<ClCompile Include="hw\ndma.cpp" />
|
||||
<ClCompile Include="loader.cpp" />
|
||||
<ClCompile Include="mem_map.cpp" />
|
||||
<ClCompile Include="mem_map_funcs.cpp" />
|
||||
@ -182,8 +190,17 @@
|
||||
<ClInclude Include="file_sys\directory_file_system.h" />
|
||||
<ClInclude Include="file_sys\file_sys.h" />
|
||||
<ClInclude Include="file_sys\meta_file_system.h" />
|
||||
<ClInclude Include="hle\function_wrappers.h" />
|
||||
<ClInclude Include="hle\hle.h" />
|
||||
<ClInclude Include="hle\service\apt.h" />
|
||||
<ClInclude Include="hle\service\gsp.h" />
|
||||
<ClInclude Include="hle\service\hid.h" />
|
||||
<ClInclude Include="hle\service\service.h" />
|
||||
<ClInclude Include="hle\service\srv.h" />
|
||||
<ClInclude Include="hle\syscall.h" />
|
||||
<ClInclude Include="hw\hw.h" />
|
||||
<ClInclude Include="hw\hw_lcd.h" />
|
||||
<ClInclude Include="hw\lcd.h" />
|
||||
<ClInclude Include="hw\ndma.h" />
|
||||
<ClInclude Include="loader.h" />
|
||||
<ClInclude Include="mem_map.h" />
|
||||
<ClInclude Include="system.h" />
|
||||
|
@ -22,6 +22,12 @@
|
||||
<Filter Include="elf">
|
||||
<UniqueIdentifier>{7ae34319-6d72-4d12-bc62-9b438ba9241f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="hle">
|
||||
<UniqueIdentifier>{8b62769e-3e2a-4a57-a7bc-b3b2933c2bc7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="hle\service">
|
||||
<UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="arm\disassembler\arm_disasm.cpp">
|
||||
@ -63,9 +69,6 @@
|
||||
<ClCompile Include="hw\hw.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw\hw_lcd.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="elf\elf_reader.cpp">
|
||||
<Filter>elf</Filter>
|
||||
</ClCompile>
|
||||
@ -75,6 +78,33 @@
|
||||
<ClCompile Include="mem_map_funcs.cpp" />
|
||||
<ClCompile Include="system.cpp" />
|
||||
<ClCompile Include="core_timing.cpp" />
|
||||
<ClCompile Include="hle\hle.cpp">
|
||||
<Filter>hle</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\syscall.cpp">
|
||||
<Filter>hle</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\service\service.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\service\apt.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\service\srv.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\service\gsp.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\service\hid.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw\ndma.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw\lcd.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="arm\disassembler\arm_disasm.h">
|
||||
@ -131,9 +161,6 @@
|
||||
<ClInclude Include="hw\hw.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw\hw_lcd.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="elf\elf_reader.h">
|
||||
<Filter>elf</Filter>
|
||||
</ClInclude>
|
||||
@ -148,6 +175,36 @@
|
||||
<ClInclude Include="loader.h" />
|
||||
<ClInclude Include="mem_map.h" />
|
||||
<ClInclude Include="system.h" />
|
||||
<ClInclude Include="hle\hle.h">
|
||||
<Filter>hle</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\function_wrappers.h">
|
||||
<Filter>hle</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\service\service.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\syscall.h">
|
||||
<Filter>hle</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\service\apt.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\service\srv.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\service\gsp.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\service\hid.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw\ndma.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw\lcd.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
736
src/core/hle/function_wrappers.h
Normal file
736
src/core/hle/function_wrappers.h
Normal file
@ -0,0 +1,736 @@
|
||||
// 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/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hle/hle.h"
|
||||
|
||||
// For easy parameter parsing and return value processing.
|
||||
|
||||
//32bit wrappers
|
||||
template<void func()> void WrapV_V() {
|
||||
func();
|
||||
}
|
||||
|
||||
template<u32 func()> void WrapU_V() {
|
||||
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<float func()> void WrapF_V() {
|
||||
RETURNF(func());
|
||||
}
|
||||
|
||||
// TODO: Not sure about the floating point parameter passing
|
||||
template<float func(int, float, u32)> void WrapF_IFU() {
|
||||
RETURNF(func(PARAM(0), PARAMF(0), PARAM(1)));
|
||||
}
|
||||
|
||||
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, float, float)> void WrapI_UFF() {
|
||||
// Not sure about the float arguments.
|
||||
int retval = func(PARAM(0), PARAMF(0), PARAMF(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 WrapI_V() {
|
||||
int retval = func();
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int)> void WrapU_I() {
|
||||
u32 retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, int, u32)> void WrapU_IIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int)> void WrapI_I() {
|
||||
int retval = func(PARAM(0));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32)> void WrapV_U() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(int)> void WrapV_I() {
|
||||
func(PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(u32, u32)> void WrapV_UU() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(int, int)> void WrapV_II() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(u32, const char *)> void WrapV_UC() {
|
||||
func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
}
|
||||
|
||||
template<int func(u32, const char *)> void WrapI_UC() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, const char *, int)> void WrapI_UCI() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32)> void WrapU_UU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int)> void WrapU_UUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int, int)> void WrapU_UUII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, int, u32, int, int)> void WrapV_UIUII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, int, u32, int, int)> void WrapI_UIUII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32, int)> void WrapU_UIUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, int, u32, int)> void WrapI_UIUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32)> void WrapU_UIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int)> void WrapU_UII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int, u32)> void WrapU_UIIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, int, int)> void WrapI_UUII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, int, int, int)> void WrapI_UUIII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, int, int, int)> void WrapV_UIII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
}
|
||||
|
||||
template<void func(u32, int, int)> void WrapV_UII() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<u32 func(int, u32)> void WrapU_IU() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32)> void WrapI_IU() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, int)> void WrapI_UUI() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, u32, int, u32)> void WrapI_UUIU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int)> void WrapI_II() {
|
||||
int retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, int)> void WrapI_III() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, int)> void WrapI_IUI() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, int, int)> void WrapI_IIII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, int, int, int)> void WrapI_UIII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, int, u32, int)> void WrapI_IIIUI() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32, int, int)> void WrapI_IUUII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, int, u32)> void WrapI_IIU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32)> void WrapV_IU() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(u32, int)> void WrapV_UI() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<u32 func(const char *)> void WrapU_C() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)),
|
||||
Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)),
|
||||
PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *)> void WrapI_C() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32)> void WrapI_CU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, int)> void WrapI_CUI() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, const char *, int, u32)> void WrapI_ICIU() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, int, u32)> void WrapI_CIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32)> void WrapI_CUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, const char*, int, int)> void WrapI_CCII() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32)> void WrapU_CU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
RETURN((u32) retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, const char *)> void WrapU_UC() {
|
||||
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32, u32)> void WrapU_CUU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN((u32) retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, int, int)> void WrapU_III() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, int)> void WrapU_II() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, int, int, int)> void WrapU_IIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u32, u32)> void WrapU_IUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32)> void WrapU_UUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32, u32)> void WrapV_IUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(int, int, u32)> void WrapV_IIU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(u32, int, u32)> void WrapV_UIU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<int func(u32, int, u32)> void WrapI_UIU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32)> void WrapV_UUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2));
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32, u32)> void WrapV_UUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
|
||||
func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
|
||||
PARAM(4));
|
||||
}
|
||||
|
||||
template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
|
||||
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
|
||||
PARAM(4));
|
||||
}
|
||||
|
||||
template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
|
||||
PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() {
|
||||
u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int, int)> void WrapU_UIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(int, u32, int, int)> void WrapI_IUII() {
|
||||
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
}
|
||||
|
||||
template<u32 func(const char *, const char *)> void WrapU_CC() {
|
||||
int retval = func(Memory::GetCharPointer(PARAM(0)),
|
||||
Memory::GetCharPointer(PARAM(1)));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<void func(const char *, int)> void WrapV_CI() {
|
||||
func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
|
||||
}
|
||||
|
||||
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, u32, u32, u32, u32)> void WrapI_VUUUUU(){
|
||||
u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<int func(u32, s64)> void WrapI_US64() {
|
||||
int retval = func(PARAM(0), PARAM64(2));
|
||||
RETURN(retval);
|
||||
}
|
120
src/core/hle/hle.cpp
Normal file
120
src/core/hle/hle.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/syscall.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace HLE {
|
||||
|
||||
static std::vector<ModuleDef> g_module_db;
|
||||
|
||||
u8* g_command_buffer = NULL; ///< Command buffer used for sharing between appcore and syscore
|
||||
|
||||
// Read from memory used by CTROS HLE functions
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr) {
|
||||
if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) {
|
||||
var = *((const T*)&g_command_buffer[addr & CMD_BUFFER_MASK]);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "unknown read from address %08X", addr);
|
||||
}
|
||||
}
|
||||
|
||||
// Write to memory used by CTROS HLE functions
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data) {
|
||||
if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) {
|
||||
*(T*)&g_command_buffer[addr & CMD_BUFFER_MASK] = data;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "unknown write to address %08X", addr);
|
||||
}
|
||||
}
|
||||
|
||||
u8 *GetPointer(const u32 addr) {
|
||||
if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) {
|
||||
return g_command_buffer + (addr & CMD_BUFFER_MASK);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "unknown pointer from address %08X", addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly instantiate template functions because we aren't defining this in the header:
|
||||
|
||||
template void Read<u64>(u64 &var, const u32 addr);
|
||||
template void Read<u32>(u32 &var, const u32 addr);
|
||||
template void Read<u16>(u16 &var, const u32 addr);
|
||||
template void Read<u8>(u8 &var, const u32 addr);
|
||||
|
||||
template void Write<u64>(u32 addr, const u64 data);
|
||||
template void Write<u32>(u32 addr, const u32 data);
|
||||
template void Write<u16>(u32 addr, const u16 data);
|
||||
template void Write<u8>(u32 addr, const u8 data);
|
||||
|
||||
const FunctionDef* GetSyscallInfo(u32 opcode) {
|
||||
u32 func_num = opcode & 0xFFFFFF; // 8 bits
|
||||
if (func_num > 0xFF) {
|
||||
ERROR_LOG(HLE,"Unknown syscall: 0x%02X", func_num);
|
||||
return NULL;
|
||||
}
|
||||
return &g_module_db[0].func_table[func_num];
|
||||
}
|
||||
|
||||
void CallSyscall(u32 opcode) {
|
||||
const FunctionDef *info = GetSyscallInfo(opcode);
|
||||
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
if (info->func) {
|
||||
info->func();
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Unimplemented SysCall function %s(..)", info->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the coprocessor (in this case, syscore) command buffer pointer
|
||||
Addr CallGetThreadCommandBuffer() {
|
||||
// Called on insruction: mrc p15, 0, r0, c13, c0, 3
|
||||
// Returns an address in OSHLE memory for the CPU to read/write to
|
||||
RETURN(CMD_BUFFER_ADDR);
|
||||
return CMD_BUFFER_ADDR;
|
||||
}
|
||||
|
||||
void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
|
||||
ModuleDef module = {name, num_functions, func_table};
|
||||
g_module_db.push_back(module);
|
||||
}
|
||||
|
||||
void RegisterAllModules() {
|
||||
Syscall::Register();
|
||||
}
|
||||
|
||||
void Init() {
|
||||
Service::Init();
|
||||
|
||||
g_command_buffer = new u8[CMD_BUFFER_SIZE];
|
||||
|
||||
RegisterAllModules();
|
||||
|
||||
NOTICE_LOG(HLE, "initialized OK");
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
Service::Shutdown();
|
||||
|
||||
delete g_command_buffer;
|
||||
|
||||
g_module_db.clear();
|
||||
|
||||
NOTICE_LOG(HLE, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
66
src/core/hle/hle.h
Normal file
66
src/core/hle/hle.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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 {
|
||||
|
||||
enum {
|
||||
CMD_BUFFER_ADDR = 0xA0010000, ///< Totally arbitrary unused address space
|
||||
CMD_BUFFER_SIZE = 0x10000,
|
||||
CMD_BUFFER_MASK = (CMD_BUFFER_SIZE - 1),
|
||||
CMD_BUFFER_ADDR_END = (CMD_BUFFER_ADDR + CMD_BUFFER_SIZE),
|
||||
};
|
||||
|
||||
typedef u32 Addr;
|
||||
typedef void (*Func)();
|
||||
|
||||
struct FunctionDef {
|
||||
u32 id;
|
||||
Func func;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct ModuleDef {
|
||||
std::string name;
|
||||
int num_funcs;
|
||||
const FunctionDef* func_table;
|
||||
};
|
||||
|
||||
// Read from memory used by CTROS HLE functions
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr);
|
||||
|
||||
// Write to memory used by CTROS HLE functions
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data);
|
||||
|
||||
u8* GetPointer(const u32 Address);
|
||||
|
||||
inline const char* GetCharPointer(const u32 address) {
|
||||
return (const char *)GetPointer(address);
|
||||
}
|
||||
|
||||
void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
|
||||
|
||||
void CallSyscall(u32 opcode);
|
||||
|
||||
Addr CallGetThreadCommandBuffer();
|
||||
|
||||
void Init();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
} // namespace
|
116
src/core/hle/service/apt.cpp
Normal file
116
src/core/hle/service/apt.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
// 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/apt.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace APT_U
|
||||
|
||||
namespace APT_U {
|
||||
|
||||
void Initialize() {
|
||||
NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize");
|
||||
}
|
||||
|
||||
void GetLockHandle() {
|
||||
u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset);
|
||||
cmd_buff[5] = 0x00000000; // TODO: This should be an actual mutex handle
|
||||
}
|
||||
|
||||
const HLE::FunctionDef 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"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
41
src/core/hle/service/apt.h
Normal file
41
src/core/hle/service/apt.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace APT_U
|
||||
|
||||
namespace APT_U {
|
||||
|
||||
// Application and title launching service. These services handle signaling for home/power button as
|
||||
// well. Only one session for either APT service can be open at a time, normally processes close the
|
||||
// service handle immediately once finished using the service. The commands for APT:U and APT:S are
|
||||
// exactly the same, however certain commands are only accessible with APT:S(NS module will call
|
||||
// svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services.
|
||||
|
||||
/// Interface to "APT:U" service
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const {
|
||||
return "APT:U";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interface);
|
||||
};
|
||||
|
||||
} // namespace
|
59
src/core/hle/service/gsp.cpp
Normal file
59
src/core/hle/service/gsp.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// 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/gsp.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace GSP_GPU
|
||||
|
||||
namespace GSP_GPU {
|
||||
|
||||
const HLE::FunctionDef FunctionTable[] = {
|
||||
{0x00010082, NULL, "WriteHWRegs"},
|
||||
{0x00020084, NULL, "WriteHWRegsWithMask"},
|
||||
{0x00030082, NULL, "WriteHWRegRepeat"},
|
||||
{0x00040080, NULL, "ReadHWRegs"},
|
||||
{0x00050200, NULL, "SetBufferSwap"},
|
||||
{0x00060082, NULL, "SetCommandList"},
|
||||
{0x000700C2, NULL, "RequestDma"},
|
||||
{0x00080082, NULL, "FlushDataCache"},
|
||||
{0x00090082, NULL, "InvalidateDataCache"},
|
||||
{0x000A0044, NULL, "RegisterInterruptEvents"},
|
||||
{0x000B0040, NULL, "SetLcdForceBlack"},
|
||||
{0x000C0000, NULL, "TriggerCmdReqQueue"},
|
||||
{0x000D0140, NULL, "SetDisplayTransfer"},
|
||||
{0x000E0180, NULL, "SetTextureCopy"},
|
||||
{0x000F0200, NULL, "SetMemoryFill"},
|
||||
{0x00100040, NULL, "SetAxiConfigQoSMode"},
|
||||
{0x00110040, NULL, "SetPerfLogMode"},
|
||||
{0x00120000, NULL, "GetPerfLog"},
|
||||
{0x00130042, NULL, "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"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
35
src/core/hle/service/gsp.h
Normal file
35
src/core/hle/service/gsp.h
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace GSP_GPU
|
||||
|
||||
namespace GSP_GPU {
|
||||
|
||||
/// Interface to "srv:" service
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const {
|
||||
return "gsp::Gpu";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interface);
|
||||
};
|
||||
|
||||
} // namespace
|
33
src/core/hle/service/hid.cpp
Normal file
33
src/core/hle/service/hid.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// 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/hid.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace HID_User
|
||||
|
||||
namespace HID_User {
|
||||
|
||||
const HLE::FunctionDef FunctionTable[] = {
|
||||
{0x000A0000, NULL, "GetIPCHandles"},
|
||||
{0x00110000, NULL, "EnableAccelerometer"},
|
||||
{0x00130000, NULL, "EnableGyroscopeLow"},
|
||||
{0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"},
|
||||
{0x00160000, NULL, "GetGyroscopeLowCalibrateParam"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
37
src/core/hle/service/hid.h
Normal file
37
src/core/hle/service/hid.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace HID_User
|
||||
|
||||
// This service is used for interfacing to physical user controls... perhaps "Human Interface
|
||||
// Devices"? Uses include game pad controls, accelerometers, gyroscopes, etc.
|
||||
|
||||
namespace HID_User {
|
||||
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const {
|
||||
return "hid:USER";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interface);
|
||||
};
|
||||
|
||||
} // namespace
|
94
src/core/hle/service/service.cpp
Normal file
94
src/core/hle/service/service.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/apt.h"
|
||||
#include "core/hle/service/gsp.h"
|
||||
#include "core/hle/service/hid.h"
|
||||
#include "core/hle/service/srv.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
Manager* g_manager = NULL; ///< Service manager
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Service Manager class
|
||||
|
||||
Manager::Manager() {
|
||||
}
|
||||
|
||||
Manager::~Manager() {
|
||||
for(Interface* service : m_services) {
|
||||
DeleteService(service->GetPortName());
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a service to the manager (does not create it though)
|
||||
void Manager::AddService(Interface* service) {
|
||||
int index = m_services.size();
|
||||
u32 new_uid = GetUIDFromIndex(index);
|
||||
|
||||
m_services.push_back(service);
|
||||
|
||||
m_port_map[service->GetPortName()] = new_uid;
|
||||
service->m_uid = new_uid;
|
||||
}
|
||||
|
||||
/// Removes a service from the manager, also frees memory
|
||||
void Manager::DeleteService(std::string port_name) {
|
||||
auto service = FetchFromPortName(port_name);
|
||||
|
||||
m_services.erase(m_services.begin() + GetIndexFromUID(service->m_uid));
|
||||
m_port_map.erase(port_name);
|
||||
|
||||
delete service;
|
||||
}
|
||||
|
||||
/// Get a Service Interface from its UID
|
||||
Interface* Manager::FetchFromUID(u32 uid) {
|
||||
int index = GetIndexFromUID(uid);
|
||||
if (index < (int)m_services.size()) {
|
||||
return m_services[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Get a Service Interface from its port
|
||||
Interface* Manager::FetchFromPortName(std::string port_name) {
|
||||
auto itr = m_port_map.find(port_name);
|
||||
if (itr == m_port_map.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return FetchFromUID(itr->second);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Module interface
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init() {
|
||||
g_manager = new Manager;
|
||||
|
||||
g_manager->AddService(new SRV::Interface);
|
||||
g_manager->AddService(new APT_U::Interface);
|
||||
g_manager->AddService(new GSP_GPU::Interface);
|
||||
g_manager->AddService(new HID_User::Interface);
|
||||
|
||||
NOTICE_LOG(HLE, "Services initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown ServiceManager
|
||||
void Shutdown() {
|
||||
delete g_manager;
|
||||
NOTICE_LOG(HLE, "Services shutdown OK");
|
||||
}
|
||||
|
||||
|
||||
}
|
143
src/core/hle/service/service.h
Normal file
143
src/core/hle/service/service.h
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/syscall.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace Service
|
||||
|
||||
namespace Service {
|
||||
|
||||
typedef s32 NativeUID; ///< Native handle for a service
|
||||
|
||||
static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters)
|
||||
static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
|
||||
|
||||
class Manager;
|
||||
|
||||
/// Interface to a CTROS service
|
||||
class Interface {
|
||||
friend class Manager;
|
||||
public:
|
||||
|
||||
Interface() {
|
||||
}
|
||||
|
||||
virtual ~Interface() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the UID for the serice
|
||||
* @return UID of service in native format
|
||||
*/
|
||||
NativeUID GetUID() const {
|
||||
return (NativeUID)m_uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string name used by CTROS for a service
|
||||
* @return Port name of service
|
||||
*/
|
||||
virtual std::string GetPortName() const {
|
||||
return "[UNKNOWN SERVICE PORT]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when svcSendSyncRequest is called, loads command buffer and executes comand
|
||||
* @return Return result of svcSendSyncRequest passed back to user app
|
||||
*/
|
||||
Syscall::Result Sync() {
|
||||
u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + kCommandHeaderOffset);
|
||||
auto itr = m_functions.find(cmd_buff[0]);
|
||||
|
||||
if (itr == m_functions.end()) {
|
||||
ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!",
|
||||
GetPortName().c_str(), cmd_buff[0]);
|
||||
return -1;
|
||||
}
|
||||
if (itr->second.func == NULL) {
|
||||
ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",
|
||||
GetPortName().c_str(), itr->second.name.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
itr->second.func();
|
||||
|
||||
return 0; // TODO: Implement return from actual function
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Registers the functions in the service
|
||||
*/
|
||||
void Register(const HLE::FunctionDef* functions, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
m_functions[functions[i].id] = functions[i];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_uid;
|
||||
std::map<u32, HLE::FunctionDef> m_functions;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interface);
|
||||
};
|
||||
|
||||
/// Simple class to manage accessing services from ports and UID handles
|
||||
class Manager {
|
||||
|
||||
public:
|
||||
Manager();
|
||||
|
||||
~Manager();
|
||||
|
||||
/// Add a service to the manager (does not create it though)
|
||||
void AddService(Interface* service);
|
||||
|
||||
/// Removes a service from the manager (does not delete it though)
|
||||
void DeleteService(std::string port_name);
|
||||
|
||||
/// Get a Service Interface from its UID
|
||||
Interface* FetchFromUID(u32 uid);
|
||||
|
||||
/// Get a Service Interface from its port
|
||||
Interface* FetchFromPortName(std::string port_name);
|
||||
|
||||
private:
|
||||
|
||||
/// Convert an index into m_services vector into a UID
|
||||
static u32 GetUIDFromIndex(const int index) {
|
||||
return index | 0x10000000;
|
||||
}
|
||||
|
||||
/// Convert a UID into an index into m_services
|
||||
static int GetIndexFromUID(const u32 uid) {
|
||||
return uid & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
std::vector<Interface*> m_services;
|
||||
std::map<std::string, u32> m_port_map;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Manager);
|
||||
};
|
||||
|
||||
/// Initialize ServiceManager
|
||||
void Init();
|
||||
|
||||
/// Shutdown ServiceManager
|
||||
void Shutdown();
|
||||
|
||||
|
||||
extern Manager* g_manager; ///< Service manager
|
||||
|
||||
|
||||
} // namespace
|
58
src/core/hle/service/srv.cpp
Normal file
58
src/core/hle/service/srv.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/service/srv.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace SRV
|
||||
|
||||
namespace SRV {
|
||||
|
||||
void Initialize() {
|
||||
NOTICE_LOG(OSHLE, "SRV::Sync - Initialize");
|
||||
}
|
||||
|
||||
void GetServiceHandle() {
|
||||
Syscall::Result res = 0;
|
||||
u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset);
|
||||
|
||||
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->GetUID());
|
||||
|
||||
if (NULL != service) {
|
||||
cmd_buff[3] = service->GetUID();
|
||||
} else {
|
||||
ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str());
|
||||
res = -1;
|
||||
}
|
||||
cmd_buff[1] = res;
|
||||
|
||||
//return res;
|
||||
}
|
||||
|
||||
const HLE::FunctionDef FunctionTable[] = {
|
||||
{0x00010002, Initialize, "Initialize"},
|
||||
{0x00020000, NULL, "GetProcSemaphore"},
|
||||
{0x00030100, NULL, "RegisterService"},
|
||||
{0x000400C0, NULL, "UnregisterService"},
|
||||
{0x00050100, GetServiceHandle, "GetServiceHandle"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
40
src/core/hle/service/srv.h
Normal file
40
src/core/hle/service/srv.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace SRV
|
||||
|
||||
namespace SRV {
|
||||
|
||||
/// Interface to "srv:" service
|
||||
class Interface : public Service::Interface {
|
||||
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const {
|
||||
return "srv:";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when svcSendSyncRequest is called, loads command buffer and executes comand
|
||||
* @return Return result of svcSendSyncRequest passed back to user app
|
||||
*/
|
||||
Syscall::Result Sync();
|
||||
|
||||
private:
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interface);
|
||||
};
|
||||
|
||||
} // namespace
|
197
src/core/hle/syscall.cpp
Normal file
197
src/core/hle/syscall.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "core/mem_map.h"
|
||||
|
||||
#include "core/hle/function_wrappers.h"
|
||||
#include "core/hle/syscall.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace Syscall
|
||||
|
||||
namespace Syscall {
|
||||
|
||||
/// Map application or GSP heap memory
|
||||
Result ControlMemory(void* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 permissions) {
|
||||
u32 virtual_address = 0x00000000;
|
||||
|
||||
switch (operation) {
|
||||
|
||||
// Map GSP heap memory?
|
||||
case 0x00010003:
|
||||
virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions);
|
||||
break;
|
||||
|
||||
// Unknown ControlMemory operation
|
||||
default:
|
||||
ERROR_LOG(OSHLE, "Unknown ControlMemory operation %08X", operation);
|
||||
}
|
||||
|
||||
Core::g_app_core->SetReg(1, Memory::MapBlock_HeapGSP(size, operation, permissions));
|
||||
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) {
|
||||
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
|
||||
Core::g_app_core->SetReg(1, service->GetUID());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Synchronize to an OS service
|
||||
Result SendSyncRequest(Handle session) {
|
||||
Service::Interface* service = Service::g_manager->FetchFromUID(session);
|
||||
service->Sync();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Close a handle
|
||||
Result CloseHandle(Handle handle) {
|
||||
// ImplementMe
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
||||
Result WaitSynchronization1(Handle handle, s64 nanoseconds) {
|
||||
// ImplementMe
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HLE::FunctionDef Syscall_Table[] = {
|
||||
{0x00, NULL, "Unknown"},
|
||||
{0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"},
|
||||
{0x02, NULL, "QueryMemory"},
|
||||
{0x03, NULL, "ExitProcess"},
|
||||
{0x04, NULL, "GetProcessAffinityMask"},
|
||||
{0x05, NULL, "SetProcessAffinityMask"},
|
||||
{0x06, NULL, "GetProcessIdealProcessor"},
|
||||
{0x07, NULL, "SetProcessIdealProcessor"},
|
||||
{0x08, NULL, "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, NULL, "CreateMutex"},
|
||||
{0x14, NULL, "ReleaseMutex"},
|
||||
{0x15, NULL, "CreateSemaphore"},
|
||||
{0x16, NULL, "ReleaseSemaphore"},
|
||||
{0x17, NULL, "CreateEvent"},
|
||||
{0x18, NULL, "SignalEvent"},
|
||||
{0x19, NULL, "ClearEvent"},
|
||||
{0x1A, NULL, "CreateTimer"},
|
||||
{0x1B, NULL, "SetTimer"},
|
||||
{0x1C, NULL, "CancelTimer"},
|
||||
{0x1D, NULL, "ClearTimer"},
|
||||
{0x1E, NULL, "CreateMemoryBlock"},
|
||||
{0x1F, NULL, "MapMemoryBlock"},
|
||||
{0x20, NULL, "UnmapMemoryBlock"},
|
||||
{0x21, NULL, "CreateAddressArbiter"},
|
||||
{0x22, NULL, "ArbitrateAddress"},
|
||||
{0x23, WrapI_U<CloseHandle>, "CloseHandle"},
|
||||
{0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"},
|
||||
{0x25, NULL, "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, NULL, "GetThreadId"},
|
||||
{0x38, NULL, "GetResourceLimit"},
|
||||
{0x39, NULL, "GetResourceLimitLimitValues"},
|
||||
{0x3A, NULL, "GetResourceLimitCurrentValues"},
|
||||
{0x3B, NULL, "GetThreadContext"},
|
||||
{0x3C, NULL, "Break"},
|
||||
{0x3D, NULL, "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"},
|
||||
};
|
||||
|
||||
void Register() {
|
||||
HLE::RegisterModule("SyscallTable", ARRAY_SIZE(Syscall_Table), Syscall_Table);
|
||||
}
|
||||
|
||||
} // namespace
|
19
src/core/hle/syscall.h
Normal file
19
src/core/hle/syscall.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace Syscall
|
||||
|
||||
namespace Syscall {
|
||||
|
||||
typedef u32 Handle;
|
||||
typedef s32 Result;
|
||||
|
||||
void Register();
|
||||
|
||||
} // namespace
|
@ -6,18 +6,73 @@
|
||||
#include "common/log.h"
|
||||
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/hw_lcd.h"
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/hw/ndma.h"
|
||||
|
||||
namespace HW {
|
||||
|
||||
enum {
|
||||
ADDRESS_CONFIG = 0x10000000,
|
||||
ADDRESS_IRQ = 0x10001000,
|
||||
ADDRESS_NDMA = 0x10002000,
|
||||
ADDRESS_TIMER = 0x10003000,
|
||||
ADDRESS_CTRCARD = 0x10004000,
|
||||
ADDRESS_CTRCARD_2 = 0x10005000,
|
||||
ADDRESS_SDMC_NAND = 0x10006000,
|
||||
ADDRESS_SDMC_NAND_2 = 0x10007000, // Apparently not used on retail
|
||||
ADDRESS_PXI = 0x10008000,
|
||||
ADDRESS_AES = 0x10009000,
|
||||
ADDRESS_SHA = 0x1000A000,
|
||||
ADDRESS_RSA = 0x1000B000,
|
||||
ADDRESS_XDMA = 0x1000C000,
|
||||
ADDRESS_SPICARD = 0x1000D800,
|
||||
ADDRESS_CONFIG_2 = 0x10010000,
|
||||
ADDRESS_HASH = 0x10101000,
|
||||
ADDRESS_CSND = 0x10103000,
|
||||
ADDRESS_DSP = 0x10140000,
|
||||
ADDRESS_PDN = 0x10141000,
|
||||
ADDRESS_CODEC = 0x10141000,
|
||||
ADDRESS_SPI = 0x10142000,
|
||||
ADDRESS_SPI_2 = 0x10143000,
|
||||
ADDRESS_I2C = 0x10144000,
|
||||
ADDRESS_CODEC_2 = 0x10145000,
|
||||
ADDRESS_HID = 0x10146000,
|
||||
ADDRESS_PAD = 0x10146000,
|
||||
ADDRESS_PTM = 0x10146000,
|
||||
ADDRESS_I2C_2 = 0x10148000,
|
||||
ADDRESS_SPI_3 = 0x10160000,
|
||||
ADDRESS_I2C_3 = 0x10161000,
|
||||
ADDRESS_MIC = 0x10162000,
|
||||
ADDRESS_PXI_2 = 0x10163000,
|
||||
ADDRESS_NTRCARD = 0x10164000,
|
||||
ADDRESS_DSP_2 = 0x10203000,
|
||||
ADDRESS_HASH_2 = 0x10301000,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr) {
|
||||
NOTICE_LOG(HW, "Hardware read from address %08X", addr);
|
||||
switch (addr & 0xFFFFF000) {
|
||||
|
||||
case ADDRESS_NDMA:
|
||||
NDMA::Read(var, addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data) {
|
||||
NOTICE_LOG(HW, "Hardware write to address %08X", addr);
|
||||
switch (addr & 0xFFFFF000) {
|
||||
|
||||
case ADDRESS_NDMA:
|
||||
NDMA::Write(addr, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly instantiate template functions because we aren't defining this in the header:
|
||||
@ -27,25 +82,27 @@ template void Read<u32>(u32 &var, const u32 addr);
|
||||
template void Read<u16>(u16 &var, const u32 addr);
|
||||
template void Read<u8>(u8 &var, const u32 addr);
|
||||
|
||||
template void Write<const u64>(u32 addr, const u64 data);
|
||||
template void Write<const u32>(u32 addr, const u32 data);
|
||||
template void Write<const u16>(u32 addr, const u16 data);
|
||||
template void Write<const u8>(u32 addr, const u8 data);
|
||||
template void Write<u64>(u32 addr, const u64 data);
|
||||
template void Write<u32>(u32 addr, const u32 data);
|
||||
template void Write<u16>(u32 addr, const u16 data);
|
||||
template void Write<u8>(u32 addr, const u8 data);
|
||||
|
||||
/// Update hardware
|
||||
void Update() {
|
||||
LCD::Update();
|
||||
NDMA::Update();
|
||||
}
|
||||
|
||||
/// Initialize hardware
|
||||
void Init() {
|
||||
LCD::Init();
|
||||
NOTICE_LOG(HW, "Hardware initialized OK");
|
||||
NDMA::Init();
|
||||
NOTICE_LOG(HW, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown() {
|
||||
NOTICE_LOG(HW, "Hardware shutdown OK");
|
||||
NOTICE_LOG(HW, "shutdown OK");
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
#include "common/log.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hw/hw_lcd.h"
|
||||
#include "core/hw/lcd.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
@ -37,12 +37,12 @@ void Update() {
|
||||
/// Initialize hardware
|
||||
void Init() {
|
||||
g_last_ticks = Core::g_app_core->GetTicks();
|
||||
NOTICE_LOG(LCD, "LCD initialized OK");
|
||||
NOTICE_LOG(LCD, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown() {
|
||||
NOTICE_LOG(LCD, "LCD shutdown OK");
|
||||
NOTICE_LOG(LCD, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
48
src/core/hw/ndma.cpp
Normal file
48
src/core/hw/ndma.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include "core/hw/ndma.h"
|
||||
|
||||
namespace NDMA {
|
||||
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr) {
|
||||
ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data) {
|
||||
ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
|
||||
}
|
||||
|
||||
// Explicitly instantiate template functions because we aren't defining this in the header:
|
||||
|
||||
template void Read<u64>(u64 &var, const u32 addr);
|
||||
template void Read<u32>(u32 &var, const u32 addr);
|
||||
template void Read<u16>(u16 &var, const u32 addr);
|
||||
template void Read<u8>(u8 &var, const u32 addr);
|
||||
|
||||
template void Write<u64>(u32 addr, const u64 data);
|
||||
template void Write<u32>(u32 addr, const u32 data);
|
||||
template void Write<u16>(u32 addr, const u16 data);
|
||||
template void Write<u8>(u32 addr, const u8 data);
|
||||
|
||||
/// Update hardware
|
||||
void Update() {
|
||||
}
|
||||
|
||||
/// Initialize hardware
|
||||
void Init() {
|
||||
NOTICE_LOG(LCD, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown() {
|
||||
NOTICE_LOG(LCD, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
26
src/core/hw/ndma.h
Normal file
26
src/core/hw/ndma.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace NDMA {
|
||||
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr);
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data);
|
||||
|
||||
/// Update hardware
|
||||
void Update();
|
||||
|
||||
/// Initialize hardware
|
||||
void Init();
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown();
|
||||
|
||||
} // namespace
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -12,27 +12,27 @@
|
||||
|
||||
namespace Memory {
|
||||
|
||||
|
||||
u8* g_base = NULL; ///< The base pointer to the auto-mirrored arena.
|
||||
|
||||
MemArena g_arena; ///< The MemArena class
|
||||
|
||||
u8* g_bootrom = NULL; ///< Bootrom physical memory
|
||||
u8* g_fcram = NULL; ///< Main memory (FCRAM) pointer
|
||||
u8* g_heap_gsp = NULL; ///< GSP heap (main memory)
|
||||
u8* g_heap = NULL; ///< Application heap (main memory)
|
||||
u8* g_vram = NULL; ///< Video memory (VRAM) pointer
|
||||
u8* g_scratchpad = NULL; ///< Scratchpad memory - Used for main thread stack
|
||||
|
||||
u8* g_physical_bootrom = NULL; ///< Bootrom physical memory
|
||||
u8* g_uncached_bootrom = NULL;
|
||||
|
||||
u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM)
|
||||
u8* g_physical_heap_gsp = NULL;
|
||||
u8* g_physical_vram = NULL; ///< Video physical memory (VRAM)
|
||||
u8* g_physical_scratchpad = NULL; ///< Scratchpad memory used for main thread stack
|
||||
|
||||
// We don't declare the IO region in here since its handled by other means.
|
||||
static MemoryView g_views[] = {
|
||||
{ &g_vram, &g_physical_vram, MEM_VRAM_VADDR, MEM_VRAM_SIZE, 0 },
|
||||
{ &g_fcram, &g_physical_fcram, MEM_FCRAM_VADDR, MEM_FCRAM_SIZE, MV_IS_PRIMARY_RAM },
|
||||
{&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
|
||||
{&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0},
|
||||
{&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
|
||||
};
|
||||
|
||||
/*static MemoryView views[] =
|
||||
@ -56,14 +56,12 @@ void Init() {
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(g_views); i++) {
|
||||
if (g_views[i].flags & MV_IS_PRIMARY_RAM)
|
||||
g_views[i].size = MEM_FCRAM_SIZE;
|
||||
g_views[i].size = FCRAM_SIZE;
|
||||
}
|
||||
|
||||
g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena);
|
||||
|
||||
g_scratchpad = new u8[MEM_SCRATCHPAD_SIZE];
|
||||
|
||||
NOTICE_LOG(MEMMAP, "Memory system initialized. RAM at %p (mirror at 0 @ %p)", g_fcram,
|
||||
NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
|
||||
g_physical_fcram);
|
||||
}
|
||||
|
||||
@ -72,12 +70,9 @@ void Shutdown() {
|
||||
MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena);
|
||||
|
||||
g_arena.ReleaseSpace();
|
||||
delete[] g_scratchpad;
|
||||
|
||||
g_base = NULL;
|
||||
g_scratchpad = NULL;
|
||||
g_base = NULL;
|
||||
|
||||
NOTICE_LOG(MEMMAP, "Memory system shut down.");
|
||||
NOTICE_LOG(MEMMAP, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -4,39 +4,67 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Memory {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum {
|
||||
MEM_BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
||||
MEM_MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
||||
MEM_VRAM_SIZE = 0x00600000, ///< VRAM size
|
||||
MEM_DSP_SIZE = 0x00080000, ///< DSP memory size
|
||||
MEM_AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
||||
MEM_FCRAM_SIZE = 0x08000000, ///< FCRAM size... Really 0x07E00000, but power of 2
|
||||
// works much better
|
||||
MEM_SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
|
||||
|
||||
MEM_VRAM_MASK = 0x007FFFFF,
|
||||
MEM_FCRAM_MASK = (MEM_FCRAM_SIZE - 1), ///< FCRAM mask
|
||||
MEM_SCRATCHPAD_MASK = (MEM_SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask
|
||||
|
||||
MEM_FCRAM_PADDR = 0x20000000, ///< FCRAM physical address
|
||||
MEM_FCRAM_PADDR_END = (MEM_FCRAM_PADDR + MEM_FCRAM_SIZE), ///< FCRAM end of physical space
|
||||
MEM_FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
||||
MEM_FCRAM_VADDR_END = (MEM_FCRAM_VADDR + MEM_FCRAM_SIZE), ///< FCRAM end of virtual space
|
||||
BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
|
||||
MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
|
||||
VRAM_SIZE = 0x00600000, ///< VRAM size
|
||||
DSP_SIZE = 0x00080000, ///< DSP memory size
|
||||
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
|
||||
FCRAM_SIZE = 0x08000000, ///< FCRAM size
|
||||
SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
|
||||
HEAP_GSP_SIZE = 0x02000000, ///< GSP heap size... TODO: Define correctly?
|
||||
HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
|
||||
|
||||
MEM_VRAM_VADDR = 0x1F000000,
|
||||
MEM_SCRATCHPAD_VADDR = (0x10000000 - MEM_SCRATCHPAD_SIZE), ///< Scratchpad virtual address
|
||||
HEAP_PADDR = HEAP_GSP_SIZE,
|
||||
HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
|
||||
HEAP_VADDR = 0x08000000,
|
||||
HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
|
||||
HEAP_GSP_VADDR = 0x14000000,
|
||||
HEAP_GSP_VADDR_END = (HEAP_GSP_VADDR + HEAP_GSP_SIZE),
|
||||
HEAP_GSP_PADDR = 0x00000000,
|
||||
HEAP_GSP_PADDR_END = (HEAP_GSP_PADDR + HEAP_GSP_SIZE),
|
||||
|
||||
VRAM_MASK = 0x007FFFFF,
|
||||
FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask
|
||||
SCRATCHPAD_MASK = (SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask
|
||||
HEAP_GSP_MASK = (HEAP_GSP_SIZE - 1),
|
||||
HEAP_MASK = (HEAP_SIZE - 1),
|
||||
|
||||
FCRAM_PADDR = 0x20000000, ///< FCRAM physical address
|
||||
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
|
||||
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
|
||||
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
|
||||
|
||||
VRAM_VADDR = 0x1F000000,
|
||||
SCRATCHPAD_VADDR_END = 0x10000000,
|
||||
SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Memory {
|
||||
/// Represents a block of heap memory mapped by ControlMemory
|
||||
struct HeapBlock {
|
||||
HeapBlock() : base_address(0), address(0), size(0), operation(0), permissions(0) {
|
||||
}
|
||||
u32 base_address;
|
||||
u32 address;
|
||||
u32 size;
|
||||
u32 operation;
|
||||
u32 permissions;
|
||||
|
||||
const u32 GetVirtualAddress() const{
|
||||
return base_address + address;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Base is a pointer to the base of the memory map. Yes, some MMU tricks
|
||||
// are used to set up a full GC or Wii memory map in process memory. on
|
||||
@ -50,9 +78,9 @@ extern u8 *g_base;
|
||||
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
|
||||
// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
|
||||
// 32-bit: Same as the corresponding physical/virtual pointers.
|
||||
extern u8* g_fcram; ///< Main memory
|
||||
extern u8* g_vram; ///< Video memory (VRAM)
|
||||
extern u8* g_scratchpad; ///< Stack memory
|
||||
extern u8* g_heap_gsp; ///< GSP heap (main memory)
|
||||
extern u8* g_heap; ///< Application heap (main memory)
|
||||
extern u8* g_vram; ///< Video memory (VRAM)
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
@ -70,4 +98,16 @@ void Write32(const u32 addr, const u32 data);
|
||||
|
||||
u8* GetPointer(const u32 Address);
|
||||
|
||||
/**
|
||||
* Maps a block of memory on the GSP heap
|
||||
* @param size Size of block in bytes
|
||||
* @param operation Control memory operation
|
||||
* @param permissions Control memory permissions
|
||||
*/
|
||||
u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions);
|
||||
|
||||
inline const char* GetCharPointer(const u32 address) {
|
||||
return (const char *)GetPointer(address);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -2,151 +2,146 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "hle/hle.h"
|
||||
|
||||
namespace Memory {
|
||||
|
||||
std::map<u32, HeapBlock> g_heap_gsp_map;
|
||||
|
||||
/// Convert a physical address to virtual address
|
||||
u32 _AddressPhysicalToVirtual(const u32 addr) {
|
||||
// Our memory interface read/write functions assume virtual addresses. Put any physical address
|
||||
// to virtual address translations here. This is obviously quite hacky... But we're not doing
|
||||
// any MMU emulation yet or anything
|
||||
if ((addr >= FCRAM_PADDR) && (addr < (FCRAM_PADDR_END))) {
|
||||
return (addr & FCRAM_MASK) | FCRAM_VADDR;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void _Read(T &var, const u32 addr) {
|
||||
// TODO: Figure out the fastest order of tests for both read and write (they are probably different).
|
||||
// TODO: Make sure this represents the mirrors in a correct way.
|
||||
// Could just do a base-relative read, too.... TODO
|
||||
|
||||
const u32 vaddr = _AddressPhysicalToVirtual(addr);
|
||||
|
||||
// Memory allocated for HLE use that can be addressed from the emulated application
|
||||
// The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE
|
||||
// core running the user application (appcore)
|
||||
if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) {
|
||||
HLE::Read<T>(var, vaddr);
|
||||
|
||||
// Hardware I/O register reads
|
||||
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
||||
if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) {
|
||||
HW::Read<T>(var, addr);
|
||||
} else if ((vaddr & 0xFF000000) == 0x10000000 || (vaddr & 0xFF000000) == 0x1E000000) {
|
||||
HW::Read<T>(var, vaddr);
|
||||
|
||||
// FCRAM virtual address reads
|
||||
} else if ((addr & 0x3E000000) == 0x08000000) {
|
||||
var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]);
|
||||
// FCRAM - GSP heap
|
||||
} else if ((vaddr > HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||
var = *((const T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK]);
|
||||
|
||||
// Scratchpad memory
|
||||
} else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) {
|
||||
var = *((const T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK]);
|
||||
|
||||
/*else if ((addr & 0x3F800000) == 0x04000000) {
|
||||
var = *((const T*)&m_pVRAM[addr & VRAM_MASK]);
|
||||
}*/
|
||||
// FCRAM - application heap
|
||||
} else if ((vaddr > HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||
var = *((const T*)&g_heap[vaddr & HEAP_MASK]);
|
||||
|
||||
// HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses.
|
||||
// Until we progress far enough along, we'll accept all physical address reads here. I think
|
||||
// that this is typically a corner-case from usermode software unless they are trying to do
|
||||
// bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc.
|
||||
} else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) {
|
||||
var = *((const T*)&g_fcram[addr & MEM_FCRAM_MASK]);
|
||||
/*else if ((vaddr & 0x3F800000) == 0x04000000) {
|
||||
var = *((const T*)&m_pVRAM[vaddr & VRAM_MASK]);*/
|
||||
|
||||
} else {
|
||||
_assert_msg_(MEMMAP, false, "unknown memory read");
|
||||
//_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void _Write(u32 addr, const T data) {
|
||||
u32 vaddr = _AddressPhysicalToVirtual(addr);
|
||||
|
||||
// Memory allocated for HLE use that can be addressed from the emulated application
|
||||
// The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE
|
||||
// core running the user application (appcore)
|
||||
if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) {
|
||||
HLE::Write<T>(vaddr, data);
|
||||
|
||||
// Hardware I/O register writes
|
||||
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
|
||||
if ((addr & 0xFF000000) == 0x10000000 || (addr & 0xFF000000) == 0x1E000000) {
|
||||
HW::Write<const T>(addr, data);
|
||||
|
||||
// ExeFS:/.code is loaded here:
|
||||
} else if ((addr & 0xFFF00000) == 0x00100000) {
|
||||
// TODO(ShizZy): This is dumb... handle correctly. From 3DBrew:
|
||||
// http://3dbrew.org/wiki/Memory_layout#ARM11_User-land_memory_regions
|
||||
// The ExeFS:/.code is loaded here, executables must be loaded to the 0x00100000 region when
|
||||
// the exheader "special memory" flag is clear. The 0x03F00000-byte size restriction only
|
||||
// applies when this flag is clear. Executables are usually loaded to 0x14000000 when the
|
||||
// exheader "special memory" flag is set, however this address can be arbitrary.
|
||||
*(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data;
|
||||
} else if ((vaddr & 0xFF000000) == 0x10000000 || (vaddr & 0xFF000000) == 0x1E000000) {
|
||||
HW::Write<T>(vaddr, data);
|
||||
|
||||
// Scratchpad memory
|
||||
} else if (addr > MEM_SCRATCHPAD_VADDR && addr <= (MEM_SCRATCHPAD_VADDR + MEM_SCRATCHPAD_SIZE)) {
|
||||
*(T*)&g_scratchpad[addr & MEM_SCRATCHPAD_MASK] = data;
|
||||
// FCRAM - GSP heap
|
||||
} else if ((vaddr > HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||
*(T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK] = data;
|
||||
|
||||
// Heap mapped by ControlMemory:
|
||||
} else if ((addr & 0x3E000000) == 0x08000000) {
|
||||
// TODO(ShizZy): Writes to this virtual address should be put in physical memory at FCRAM + GSP
|
||||
// heap size... the following is writing to FCRAM + 0, which is actually supposed to be the
|
||||
// application's GSP heap
|
||||
*(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data;
|
||||
// FCRAM - application heap
|
||||
} else if ((vaddr > HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||
*(T*)&g_heap[vaddr & HEAP_MASK] = data;
|
||||
|
||||
} else if ((addr & 0xFF000000) == 0x14000000) {
|
||||
} else if ((vaddr & 0xFF000000) == 0x14000000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to GSP heap");
|
||||
} else if ((addr & 0xFFF00000) == 0x1EC00000) {
|
||||
} else if ((vaddr & 0xFFF00000) == 0x1EC00000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to IO registers");
|
||||
} else if ((addr & 0xFF000000) == 0x1F000000) {
|
||||
} else if ((vaddr & 0xFF000000) == 0x1F000000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to VRAM");
|
||||
} else if ((addr & 0xFFF00000) == 0x1FF00000) {
|
||||
} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
|
||||
} else if ((addr & 0xFFFF0000) == 0x1FF80000) {
|
||||
} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory");
|
||||
} else if ((addr & 0xFFFFF000) == 0x1FF81000) {
|
||||
} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) {
|
||||
_assert_msg_(MEMMAP, false, "umimplemented write to shared page");
|
||||
|
||||
// HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses.
|
||||
// Until we progress far enough along, we'll accept all physical address writes here. I think
|
||||
// that this is typically a corner-case from usermode software unless they are trying to do
|
||||
// bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc.
|
||||
} else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) {
|
||||
*(T*)&g_fcram[addr & MEM_FCRAM_MASK] = data;
|
||||
|
||||
// Error out...
|
||||
} else {
|
||||
_assert_msg_(MEMMAP, false, "unknown memory write");
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidAddress(const u32 addr) {
|
||||
if ((addr & 0x3E000000) == 0x08000000) {
|
||||
return true;
|
||||
} else if ((addr & 0x3F800000) == 0x04000000) {
|
||||
return true;
|
||||
} else if ((addr & 0xBFFF0000) == 0x00010000) {
|
||||
return true;
|
||||
} else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + MEM_FCRAM_MASK) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
_assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8,
|
||||
data, vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
u8 *GetPointer(const u32 addr) {
|
||||
// TODO(bunnei): Just a stub for now... ImplementMe!
|
||||
if ((addr & 0x3E000000) == 0x08000000) {
|
||||
return g_fcram + (addr & MEM_FCRAM_MASK);
|
||||
const u32 vaddr = _AddressPhysicalToVirtual(addr);
|
||||
|
||||
// HACK(bunnei): There is no layer yet to translate virtual addresses to physical addresses.
|
||||
// Until we progress far enough along, we'll accept all physical address reads here. I think
|
||||
// that this is typically a corner-case from usermode software unless they are trying to do
|
||||
// bare-metal things (e.g. early 3DS homebrew writes directly to the FB @ 0x20184E60, etc.
|
||||
} else if (((addr & 0xF0000000) == MEM_FCRAM_PADDR) && (addr < (MEM_FCRAM_PADDR_END))) {
|
||||
return g_fcram + (addr & MEM_FCRAM_MASK);
|
||||
// FCRAM - GSP heap
|
||||
if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
|
||||
return g_heap_gsp + (vaddr & HEAP_GSP_MASK);
|
||||
|
||||
// FCRAM - application heap
|
||||
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
|
||||
return g_heap + (vaddr & HEAP_MASK);
|
||||
|
||||
//else if ((addr & 0x3F800000) == 0x04000000) {
|
||||
// return g_vram + (addr & MEM_VRAM_MASK);
|
||||
//}
|
||||
//else if ((addr & 0x3F000000) >= 0x08000000 && (addr & 0x3F000000) < 0x08000000 + g_MemorySize) {
|
||||
// return m_pRAM + (addr & g_MemoryMask);
|
||||
//}
|
||||
} else {
|
||||
//ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
|
||||
ERROR_LOG(MEMMAP, "Unknown GetPointer %08x", addr);
|
||||
static bool reported = false;
|
||||
//if (!reported) {
|
||||
// Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", addr, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
|
||||
// reported = true;
|
||||
//}
|
||||
//if (!g_Config.bIgnoreBadMemAccess) {
|
||||
// Core_EnableStepping(true);
|
||||
// host->SetDebugMode(true);
|
||||
//}
|
||||
ERROR_LOG(MEMMAP, "Unknown GetPointer @ 0x%08x", vaddr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a block of memory on the GSP heap
|
||||
* @param size Size of block in bytes
|
||||
* @param flags Memory allocation flags
|
||||
*/
|
||||
u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) {
|
||||
HeapBlock block;
|
||||
|
||||
block.base_address = HEAP_GSP_VADDR;
|
||||
block.size = size;
|
||||
block.operation = operation;
|
||||
block.permissions = permissions;
|
||||
|
||||
if (g_heap_gsp_map.size() > 0) {
|
||||
const HeapBlock last_block = g_heap_gsp_map.rbegin()->second;
|
||||
block.address = last_block.address + last_block.size;
|
||||
}
|
||||
g_heap_gsp_map[block.GetVirtualAddress()] = block;
|
||||
|
||||
return block.GetVirtualAddress();
|
||||
}
|
||||
|
||||
u8 Read8(const u32 addr) {
|
||||
u8 _var = 0;
|
||||
_Read<u8>(_var, addr);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "core/mem_map.h"
|
||||
#include "core/system.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hle/hle.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
@ -19,15 +20,16 @@ void UpdateState(State state) {
|
||||
}
|
||||
|
||||
void Init(EmuWindow* emu_window) {
|
||||
Core::Init();
|
||||
Memory::Init();
|
||||
Core::Init();
|
||||
Memory::Init();
|
||||
HW::Init();
|
||||
CoreTiming::Init();
|
||||
HLE::Init();
|
||||
CoreTiming::Init();
|
||||
VideoCore::Init(emu_window);
|
||||
}
|
||||
|
||||
void RunLoopFor(int cycles) {
|
||||
RunLoopUntil(CoreTiming::GetTicks() + cycles);
|
||||
RunLoopUntil(CoreTiming::GetTicks() + cycles);
|
||||
}
|
||||
|
||||
void RunLoopUntil(u64 global_cycles) {
|
||||
@ -35,9 +37,12 @@ void RunLoopUntil(u64 global_cycles) {
|
||||
|
||||
void Shutdown() {
|
||||
Core::Shutdown();
|
||||
Memory::Shutdown();
|
||||
HW::Shutdown();
|
||||
HLE::Shutdown();
|
||||
CoreTiming::Shutdown();
|
||||
VideoCore::Shutdown();
|
||||
g_ctr_file_system.Shutdown();
|
||||
g_ctr_file_system.Shutdown();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hw/lcd.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
|
||||
@ -75,8 +77,8 @@ void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) {
|
||||
*/
|
||||
void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) {
|
||||
|
||||
FlipFramebuffer(0x20282160, m_xfb_top_flipped);
|
||||
FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped);
|
||||
FlipFramebuffer(LCD::TOP_RIGHT_FRAME1, m_xfb_top_flipped);
|
||||
FlipFramebuffer(LCD::SUB_FRAME1, m_xfb_bottom_flipped);
|
||||
|
||||
// Blit the top framebuffer
|
||||
// ------------------------
|
||||
@ -84,7 +86,7 @@ void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) {
|
||||
// Update textures with contents of XFB in RAM - top
|
||||
glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, m_xfb_top_flipped);
|
||||
GL_BGR, GL_UNSIGNED_BYTE, m_xfb_top_flipped);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Render target is destination framebuffer
|
||||
|
@ -38,12 +38,13 @@ void Init(EmuWindow* emu_window) {
|
||||
|
||||
g_current_frame = 0;
|
||||
|
||||
NOTICE_LOG(VIDEO, "initialized ok");
|
||||
NOTICE_LOG(VIDEO, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown the video core
|
||||
void Shutdown() {
|
||||
delete g_renderer;
|
||||
NOTICE_LOG(VIDEO, "shutdown OK");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user