ARMv7Callback.h, psv modules initialization fixed

sceLibc: __cxa_atexit, __aeabi_atexit
This commit is contained in:
Nekotekina 2015-01-21 17:34:05 +03:00
parent 506951a5a4
commit 509e09c2c5
14 changed files with 251 additions and 58 deletions

View file

@ -0,0 +1,18 @@
#pragma once
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h"
namespace vm
{
template<typename AT, typename RT, typename... T>
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::operator()(ARMv7Context& context, T... args) const
{
return psv_func_detail::func_caller<RT, T...>::call(context, vm::cast(this->addr()), args...);
}
}
template<typename RT, typename... T>
__forceinline RT cb_call(ARMv7Context& context, u32 addr, T... args)
{
return psv_func_detail::func_caller<RT, T...>::call(context, addr, args...);
}

View file

@ -29,7 +29,9 @@ struct ARMv7Context
void write_pc(u32 value); void write_pc(u32 value);
u32 read_pc(); u32 read_pc();
void put_stack_arg(u32 shift, u32 value);
u32 get_stack_arg(u32 pos); u32 get_stack_arg(u32 pos);
void fast_call(u32 addr);
union union
{ {

View file

@ -20,11 +20,21 @@ u32 ARMv7Context::read_pc()
return thread.PC; return thread.PC;
} }
void ARMv7Context::put_stack_arg(u32 shift, u32 value)
{
vm::psv::write32(SP + shift, value);
}
u32 ARMv7Context::get_stack_arg(u32 pos) u32 ARMv7Context::get_stack_arg(u32 pos)
{ {
return vm::psv::read32(SP + sizeof(u32) * (pos - 5)); return vm::psv::read32(SP + sizeof(u32) * (pos - 5));
} }
void ARMv7Context::fast_call(u32 addr)
{
return thread.FastCall(addr);
}
ARMv7Thread::ARMv7Thread() ARMv7Thread::ARMv7Thread()
: CPUThread(CPU_THREAD_ARMv7) : CPUThread(CPU_THREAD_ARMv7)
, context(*this) , context(*this)

View file

@ -327,6 +327,10 @@ s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr<s32> pExitStatus, vm::ps
psv_log_base sceLibKernel("sceLibKernel", []() psv_log_base sceLibKernel("sceLibKernel", []()
{ {
sceLibKernel.on_load = nullptr;
sceLibKernel.on_unload = nullptr;
sceLibKernel.on_stop = nullptr;
//REG_FUNC(0x23EAA62, sceKernelPuts); //REG_FUNC(0x23EAA62, sceKernelPuts);
//REG_FUNC(0xB0335388, sceClibToupper); //REG_FUNC(0xB0335388, sceClibToupper);
//REG_FUNC(0x4C5471BC, sceClibTolower); //REG_FUNC(0x4C5471BC, sceClibTolower);

View file

@ -3,29 +3,51 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/ARMv7/ARMv7Callback.h"
extern psv_log_base sceLibc; extern psv_log_base sceLibc;
vm::psv::ptr<void> g_dso;
typedef void(*atexit_func_t)(vm::psv::ptr<void>);
std::vector<std::function<void(ARMv7Context&)>> g_atexit;
namespace sce_libc_func namespace sce_libc_func
{ {
void __cxa_atexit() void __cxa_atexit(vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> arg, vm::psv::ptr<void> dso)
{ {
sceLibc.Todo(__FUNCTION__); sceLibc.Error("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso);
Emu.Pause();
g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context)
{
func(context, arg);
});
} }
void __aeabi_atexit() void __aeabi_atexit(vm::psv::ptr<void> arg, vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> dso)
{ {
sceLibc.Todo(__FUNCTION__); sceLibc.Error("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso);
Emu.Pause();
g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context)
{
func(context, arg);
});
} }
void exit() void exit(ARMv7Context& context)
{ {
sceLibc.Error("exit()"); sceLibc.Error("exit()");
Emu.Pause();
for (auto func : g_atexit)
{
func(context);
}
g_atexit.clear();
sceLibc.Success("Process finished"); sceLibc.Success("Process finished");
CallAfter([]() CallAfter([]()
{ {
Emu.Stop(); Emu.Stop();
@ -95,9 +117,11 @@ namespace sce_libc_func
LOG_NOTICE(TTY, result); LOG_NOTICE(TTY, result);
} }
void __cxa_set_dso_handle_main() void __cxa_set_dso_handle_main(vm::psv::ptr<void> dso)
{ {
sceLibc.Error("__cxa_set_dso_handle_main()"); sceLibc.Error("__cxa_set_dso_handle_main(dso=0x%x)", dso);
g_dso = dso;
} }
void memcpy(vm::psv::ptr<void> dst, vm::psv::ptr<const void> src, u32 size) void memcpy(vm::psv::ptr<void> dst, vm::psv::ptr<const void> src, u32 size)
@ -127,6 +151,13 @@ namespace sce_libc_func
psv_log_base sceLibc("SceLibc", []() psv_log_base sceLibc("SceLibc", []()
{ {
g_dso.set(0);
g_atexit.clear();
sceLibc.on_load = nullptr;
sceLibc.on_unload = nullptr;
sceLibc.on_stop = nullptr;
REG_FUNC(0xE4531F85, _Assert); REG_FUNC(0xE4531F85, _Assert);
//REG_FUNC(0xE71C5CDE, _Stoul); //REG_FUNC(0xE71C5CDE, _Stoul);
//REG_FUNC(0x7A5CA6A3, _Stoulx); //REG_FUNC(0x7A5CA6A3, _Stoulx);

View file

@ -14,6 +14,10 @@ namespace sce_libm_func
psv_log_base sceLibm("SceLibm", []() psv_log_base sceLibm("SceLibm", []()
{ {
sceLibm.on_load = nullptr;
sceLibm.on_unload = nullptr;
sceLibm.on_stop = nullptr;
//REG_FUNC(0xC73FE76D, _Exp); //REG_FUNC(0xC73FE76D, _Exp);
//REG_FUNC(0xFF4EAE04, _FExp); //REG_FUNC(0xFF4EAE04, _FExp);
//REG_FUNC(0xB363D7D4, _LExp); //REG_FUNC(0xB363D7D4, _LExp);

View file

@ -30,6 +30,10 @@ namespace sce_libstdcxx_func
psv_log_base sceLibstdcxx("SceLibstdcxx", []() psv_log_base sceLibstdcxx("SceLibstdcxx", []()
{ {
sceLibstdcxx.on_load = nullptr;
sceLibstdcxx.on_unload = nullptr;
sceLibstdcxx.on_stop = nullptr;
//REG_FUNC(0x52B0C625, std::bad_typeid::what() const); //REG_FUNC(0x52B0C625, std::bad_typeid::what() const);
//REG_FUNC(0x64D7D074, std::bad_typeid::_Doraise() const); //REG_FUNC(0x64D7D074, std::bad_typeid::_Doraise() const);
//REG_FUNC(0x15FB88E2, std::logic_error::what() const); //REG_FUNC(0x15FB88E2, std::logic_error::what() const);

View file

@ -3,6 +3,7 @@
#include "PSVFuncList.h" #include "PSVFuncList.h"
std::vector<psv_func> g_psv_func_list; std::vector<psv_func> g_psv_func_list;
std::vector<psv_log_base*> g_psv_modules;
void add_psv_func(psv_func& data) void add_psv_func(psv_func& data)
{ {
@ -48,33 +49,53 @@ extern psv_log_base sceLibm;
extern psv_log_base sceLibstdcxx; extern psv_log_base sceLibstdcxx;
extern psv_log_base sceLibKernel; extern psv_log_base sceLibKernel;
void list_known_psv_modules() void initialize_psv_modules()
{ {
if (!g_psv_func_list.size()) assert(!g_psv_func_list.size() && !g_psv_modules.size());
// fill module list
g_psv_modules.push_back(&sceLibc);
g_psv_modules.push_back(&sceLibm);
g_psv_modules.push_back(&sceLibstdcxx);
g_psv_modules.push_back(&sceLibKernel);
// setup special functions (without NIDs)
psv_func unimplemented;
unimplemented.nid = 0;
unimplemented.name = "Special function (unimplemented stub)";
unimplemented.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
{ {
// setup special functions (without NIDs) context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4);
psv_func unimplemented; throw "Unimplemented function executed";
unimplemented.nid = 0; }));
unimplemented.name = "Special function (unimplemented stub)"; g_psv_func_list.push_back(unimplemented);
unimplemented.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
{
context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4);
throw "Unimplemented function executed";
}));
g_psv_func_list.push_back(unimplemented);
psv_func hle_return; psv_func hle_return;
hle_return.nid = 1; hle_return.nid = 1;
hle_return.name = "Special function (return from HLE)"; hle_return.name = "Special function (return from HLE)";
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context) hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
{ {
context.thread.FastStop(); context.thread.FastStop();
})); }));
g_psv_func_list.push_back(hle_return); g_psv_func_list.push_back(hle_return);
sceLibc.Init(); // load functions
sceLibm.Init(); for (auto module : g_psv_modules)
sceLibstdcxx.Init(); {
sceLibKernel.Init(); module->Init();
} }
} }
void finalize_psv_modules()
{
for (auto module : g_psv_modules)
{
if (module->on_stop)
{
module->on_stop();
}
}
g_psv_func_list.clear();
g_psv_modules.clear();
}

View file

@ -7,6 +7,11 @@ class psv_log_base : public LogBase
std::string m_name; std::string m_name;
void(*m_init_func)(); void(*m_init_func)();
public:
std::function<void()> on_load;
std::function<void()> on_unload;
std::function<void()> on_stop;
public: public:
psv_log_base(const std::string& name, void(*init_func)()) psv_log_base(const std::string& name, void(*init_func)())
: m_name(name) : m_name(name)
@ -422,6 +427,8 @@ namespace psv_func_detail
ARG_STACK, ARG_STACK,
}; };
static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h
template<typename T, bind_arg_type type, int g_count, int f_count, int v_count> template<typename T, bind_arg_type type, int g_count, int f_count, int v_count>
struct bind_arg; struct bind_arg;
@ -430,10 +437,15 @@ namespace psv_func_detail
{ {
static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL"); static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL");
static __forceinline T func(ARMv7Context& context) __forceinline static T get_arg(ARMv7Context& context)
{ {
return cast_from_armv7_gpr<T>(context.GPR[g_count - 1]); return cast_from_armv7_gpr<T>(context.GPR[g_count - 1]);
} }
__forceinline static void put_arg(ARMv7Context& context, const T& arg)
{
context.GPR[g_count - 1] = cast_to_armv7_gpr<T>(arg);
}
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, int g_count, int f_count, int v_count>
@ -442,7 +454,11 @@ namespace psv_func_detail
static_assert(f_count <= 0, "TODO: Unsupported argument type (float)"); static_assert(f_count <= 0, "TODO: Unsupported argument type (float)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT");
static __forceinline T func(ARMv7Context& context) __forceinline static T get_arg(ARMv7Context& context)
{
}
__forceinline static void put_arg(ARMv7Context& context, const T& arg)
{ {
} }
}; };
@ -453,7 +469,11 @@ namespace psv_func_detail
static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)");
static_assert(std::is_same<T, u128>::value, "Invalid function argument type for ARG_VECTOR"); static_assert(std::is_same<T, u128>::value, "Invalid function argument type for ARG_VECTOR");
static __forceinline T func(ARMv7Context& context) __forceinline static T get_arg(ARMv7Context& context)
{
}
__forceinline static void put_arg(ARMv7Context& context, const T& arg)
{ {
} }
}; };
@ -465,11 +485,19 @@ namespace psv_func_detail
static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)"); static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK"); static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK");
static __forceinline T func(ARMv7Context& context) __forceinline static T get_arg(ARMv7Context& context)
{ {
// TODO: check // TODO: check
const u32 res = context.get_stack_arg(g_count); return cast_from_armv7_gpr<T>(context.get_stack_arg(g_count));
return cast_from_armv7_gpr<T>(res); }
__forceinline static void put_arg(ARMv7Context& context, const T& arg)
{
// TODO: check
const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)");
context.write_stack_arg(stack_pos, cast_to_armv7_gpr<T>(arg));
} }
}; };
@ -481,7 +509,12 @@ namespace psv_func_detail
static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(type == ARG_GENERAL, "Wrong use of bind_result template");
static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL"); static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL");
static __forceinline void func(ARMv7Context& context, const T& result) __forceinline static T get_result(ARMv7Context& context)
{
return cast_from_armv7_gpr<T>(context.GPR[0]);
}
__forceinline static void put_result(ARMv7Context& context, const T& result)
{ {
context.GPR[0] = cast_to_armv7_gpr<T>(result); context.GPR[0] = cast_to_armv7_gpr<T>(result);
} }
@ -492,7 +525,7 @@ namespace psv_func_detail
//{ //{
// static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); // static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT");
// static __forceinline void func(ARMv7Context& context, const T& result) // static __forceinline void put_result(ARMv7Context& context, const T& result)
// { // {
// } // }
//}; //};
@ -502,11 +535,21 @@ namespace psv_func_detail
//{ //{
// static_assert(std::is_same<T, u128>::value, "Invalid function result type for ARG_VECTOR"); // static_assert(std::is_same<T, u128>::value, "Invalid function result type for ARG_VECTOR");
// static __forceinline void func(ARMv7Context& context, const T& result) // static __forceinline void put_result(ARMv7Context& context, const T& result)
// { // {
// } // }
//}; //};
template<typename RT>
struct result_type
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
template <typename RT, typename F, typename Tuple, bool Done, int Total, int... N> template <typename RT, typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl struct call_impl
{ {
@ -554,18 +597,35 @@ namespace psv_func_detail
const int f = f_count + (is_float ? 1 : 0); const int f = f_count + (is_float ? 1 : 0);
const int v = v_count + (is_vector ? 1 : 0); const int v = v_count + (is_vector ? 1 : 0);
return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::func(context)), iterate<g, f, v, A...>(context)); return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::get_arg(context)), iterate<g, f, v, A...>(context));
} }
template<typename RT> template<int g_count, int f_count, int v_count>
struct result_type __forceinline static bool put_func_args(ARMv7Context& context)
{ {
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)"); // terminator
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)"); return false;
static const bool is_float = std::is_floating_point<RT>::value; }
static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); template<int g_count, int f_count, int v_count, typename T1, typename... T>
}; __forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args)
{
static_assert(!std::is_pointer<T1>::value, "Invalid callback argument type (pointer)");
static_assert(!std::is_reference<T1>::value, "Invalid callback argument type (reference)");
// TODO: check calculations
const bool is_float = std::is_floating_point<T>::value;
const bool is_vector = std::is_same<T, u128>::value;
const bind_arg_type t = is_float
? ((f_count >= 4) ? ARG_STACK : ARG_FLOAT)
: (is_vector ? ((v_count >= 4) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 4) ? ARG_STACK : ARG_GENERAL));
const int g = g_count + (is_float || is_vector ? 0 : 1);
const int f = f_count + (is_float ? 1 : 0);
const int v = v_count + (is_vector ? 1 : 0);
bind_arg<T1, t, g, f, v>::put_arg(context, arg);
// return true if stack was used
return put_func_args<g, f, v>(context, args...) || (t == ARG_STACK);
}
template<typename RT, typename... T> template<typename RT, typename... T>
class func_binder; class func_binder;
@ -623,7 +683,7 @@ namespace psv_func_detail
virtual void operator()(ARMv7Context& context) virtual void operator()(ARMv7Context& context)
{ {
bind_result<RT, result_type<RT>::value>::func(context, call<RT>(m_call, iterate<0, 0, 0, T...>(context))); bind_result<RT, result_type<RT>::value>::put_result(context, call<RT>(m_call, iterate<0, 0, 0, T...>(context)));
} }
}; };
@ -642,7 +702,36 @@ namespace psv_func_detail
virtual void operator()(ARMv7Context& context) virtual void operator()(ARMv7Context& context)
{ {
bind_result<RT, result_type<RT>::value>::func(context, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Context&>(context), iterate<0, 0, 0, T...>(context)))); bind_result<RT, result_type<RT>::value>::put_result(context, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Context&>(context), iterate<0, 0, 0, T...>(context))));
}
};
template<typename RT, typename... T>
struct func_caller
{
__forceinline static RT call(ARMv7Context& context, u32 addr, T... args)
{
func_caller<void, T...>::call(context, addr, args...);
return bind_result<RT, result_type<RT>::value>::get_result(context);
}
};
template<typename... T>
struct func_caller<void, T...>
{
__forceinline static void call(ARMv7Context& context, u32 addr, T... args)
{
if (put_func_args<0, 0, 0, T...>(context, args...))
{
context.SP -= FIXED_STACK_FRAME_SIZE;
context.fast_call(addr);
context.SP += FIXED_STACK_FRAME_SIZE;
}
else
{
context.fast_call(addr);
}
} }
}; };
} }
@ -673,4 +762,5 @@ psv_func* get_psv_func_by_nid(u32 nid);
u32 get_psv_func_index(psv_func* func); u32 get_psv_func_index(psv_func* func);
void execute_psv_func_by_index(ARMv7Context& context, u32 index); void execute_psv_func_by_index(ARMv7Context& context, u32 index);
void list_known_psv_modules(); void initialize_psv_modules();
void finalize_psv_modules();

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
class CPUThread; class CPUThread;
struct ARMv7Context;
namespace vm namespace vm
{ {
@ -332,9 +333,11 @@ namespace vm
public: public:
typedef RT(*type)(T...); typedef RT(*type)(T...);
RT operator()(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context RT operator()(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified PPU thread context
RT operator()(T... args) const; // defined in CB_FUNC.h, call using current CPU thread context RT operator()(ARMv7Context& context, T... args) const; // defined in ARMv7Callback.h, passing context is mandatory
RT operator()(T... args) const; // defined in CB_FUNC.h, call using current PPU thread context
AT addr() const AT addr() const
{ {

View file

@ -5,6 +5,7 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/GameInfo.h" #include "Emu/GameInfo.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/SysCalls/Static.h" #include "Emu/SysCalls/Static.h"
#include "Emu/SysCalls/ModuleManager.h" #include "Emu/SysCalls/ModuleManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
@ -361,6 +362,7 @@ void Emulator::Stop()
LOG_NOTICE(HLE, "All threads stopped..."); LOG_NOTICE(HLE, "All threads stopped...");
finalize_psv_modules();
m_rsx_callback = 0; m_rsx_callback = 0;
// TODO: check finalization order // TODO: check finalization order

View file

@ -89,7 +89,7 @@ namespace loader
case MACHINE_MIPS: break; case MACHINE_MIPS: break;
case MACHINE_ARM: case MACHINE_ARM:
{ {
list_known_psv_modules(); initialize_psv_modules();
auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4)); auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb) armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb)

View file

@ -266,6 +266,7 @@
<ClInclude Include="Crypto\unself.h" /> <ClInclude Include="Crypto\unself.h" />
<ClInclude Include="Crypto\utils.h" /> <ClInclude Include="Crypto\utils.h" />
<ClInclude Include="define_new_memleakdetect.h" /> <ClInclude Include="define_new_memleakdetect.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Context.h" /> <ClInclude Include="Emu\ARMv7\ARMv7Context.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Decoder.h" /> <ClInclude Include="Emu\ARMv7\ARMv7Decoder.h" />
<ClInclude Include="Emu\ARMv7\ARMv7DisAsm.h" /> <ClInclude Include="Emu\ARMv7\ARMv7DisAsm.h" />

View file

@ -1285,5 +1285,8 @@
<ClInclude Include="Emu\ARMv7\ARMv7Context.h"> <ClInclude Include="Emu\ARMv7\ARMv7Context.h">
<Filter>Emu\CPU\ARMv7</Filter> <Filter>Emu\CPU\ARMv7</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h">
<Filter>Emu\CPU\ARMv7</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>