mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-04-28 21:37:58 +03:00
Combine guest memory and function table into one virtual allocation.
This commit is contained in:
parent
038edfdebd
commit
967a0ce17f
27 changed files with 46 additions and 199 deletions
|
@ -112,7 +112,6 @@ endif()
|
|||
|
||||
set(SWA_CPU_CXX_SOURCES
|
||||
"cpu/guest_thread.cpp"
|
||||
"cpu/code_cache.cpp"
|
||||
)
|
||||
|
||||
set(SWA_GPU_CXX_SOURCES
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <cpu/guest_code.h>
|
||||
#include <cpu/guest_stack_var.h>
|
||||
#include <kernel/function.h>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <bit>
|
||||
|
||||
#include "audio.h"
|
||||
#include "cpu/code_cache.h"
|
||||
#include <kernel/memory.h>
|
||||
|
||||
#define AUDIO_DRIVER_KEY (uint32_t)('DAUD')
|
||||
|
||||
|
@ -21,7 +21,7 @@ uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>*
|
|||
#endif
|
||||
|
||||
*driver = AUDIO_DRIVER_KEY;
|
||||
XAudioRegisterClient(KeFindHostFunction(*callback), callback[1]);
|
||||
XAudioRegisterClient(g_memory.FindFunction(*callback), callback[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#include "sdl2_driver.h"
|
||||
#include <cpu/code_cache.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <cpu/guest_code.h>
|
||||
#include <kernel/heap.h>
|
||||
|
||||
static PPCFunc* g_clientCallback{};
|
||||
|
@ -50,7 +48,7 @@ static void AudioThread()
|
|||
if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY)
|
||||
{
|
||||
ctx.ppcContext.r3.u32 = g_clientCallbackParam;
|
||||
g_clientCallback(ctx.ppcContext, reinterpret_cast<uint8_t*>(g_memory.base));
|
||||
g_clientCallback(ctx.ppcContext, g_memory.base);
|
||||
}
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include <stdafx.h>
|
||||
#include "xaudio_driver.h"
|
||||
#include <xaudio2.h>
|
||||
#include <cpu/code_cache.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <cpu/guest_code.h>
|
||||
#include <cpu/ppc_context.h>
|
||||
#include <kernel/heap.h>
|
||||
|
||||
|
@ -55,7 +53,7 @@ PPC_FUNC(DriverLoop)
|
|||
WaitForSingleObject(g_audioSemaphore, INFINITE);
|
||||
|
||||
ctx.r3.u64 = g_clientCallbackParam;
|
||||
GuestCode::Run((void*)g_clientCallback, &ctx);
|
||||
g_clientCallback(ctx, g_memory.base);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
#include <stdafx.h>
|
||||
#include "code_cache.h"
|
||||
#include "ppc_context.h"
|
||||
|
||||
CodeCache::CodeCache()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bucket = (char*)VirtualAlloc(nullptr, 0x200000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
assert(bucket != nullptr);
|
||||
#else
|
||||
bucket = (char*)mmap(NULL, 0x200000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
assert(bucket != (char*)MAP_FAILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
CodeCache::~CodeCache()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualFree(bucket, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(bucket, 0x200000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CodeCache::Init()
|
||||
{
|
||||
for (size_t i = 0; PPCFuncMappings[i].guest != 0; i++)
|
||||
{
|
||||
if (PPCFuncMappings[i].host != nullptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualAlloc(bucket + PPCFuncMappings[i].guest * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
|
||||
#endif
|
||||
*(void**)(bucket + PPCFuncMappings[i].guest * 2) = (void*)PPCFuncMappings[i].host;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::Insert(uint32_t guest, PPCFunc* host)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualAlloc(bucket + static_cast<uint64_t>(guest) * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
|
||||
#endif
|
||||
*reinterpret_cast<PPCFunc**>(bucket + static_cast<uint64_t>(guest) * 2) = host;
|
||||
}
|
||||
|
||||
void* CodeCache::Find(uint32_t guest) const
|
||||
{
|
||||
return *reinterpret_cast<void**>(bucket + static_cast<uint64_t>(guest) * 2);
|
||||
}
|
||||
|
||||
SWA_API PPCFunc* KeFindHostFunction(uint32_t guest)
|
||||
{
|
||||
return reinterpret_cast<PPCFunc*>(g_codeCache.Find(guest));
|
||||
}
|
||||
|
||||
SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function)
|
||||
{
|
||||
g_codeCache.Insert(guest, function);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
struct CodeCache
|
||||
{
|
||||
char* bucket{};
|
||||
|
||||
CodeCache();
|
||||
~CodeCache();
|
||||
|
||||
void Init();
|
||||
void Insert(uint32_t guest, PPCFunc* host);
|
||||
|
||||
void* Find(uint32_t guest) const;
|
||||
};
|
||||
|
||||
SWA_API PPCFunc* KeFindHostFunction(uint32_t guest);
|
||||
SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function);
|
||||
|
||||
extern CodeCache g_codeCache;
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
#include "ppc_context.h"
|
||||
#include <kernel/memory.h>
|
||||
|
||||
struct GuestCode
|
||||
{
|
||||
inline static void Run(void* hostAddress, PPCContext* ctx, void* baseAddress)
|
||||
{
|
||||
ctx->fpscr.loadFromHost();
|
||||
reinterpret_cast<PPCFunc*>(hostAddress)(*ctx, reinterpret_cast<uint8_t*>(baseAddress));
|
||||
}
|
||||
|
||||
inline static void Run(void* hostAddress, PPCContext* ctx)
|
||||
{
|
||||
ctx->fpscr.loadFromHost();
|
||||
reinterpret_cast<PPCFunc*>(hostAddress)(*ctx, reinterpret_cast<uint8_t*>(g_memory.base));
|
||||
}
|
||||
|
||||
inline static void Run(void* hostAddress)
|
||||
{
|
||||
Run(hostAddress, GetPPCContext());
|
||||
}
|
||||
};
|
|
@ -3,8 +3,6 @@
|
|||
#include <kernel/memory.h>
|
||||
#include <kernel/heap.h>
|
||||
#include <kernel/function.h>
|
||||
#include "code_cache.h"
|
||||
#include "guest_code.h"
|
||||
#include "ppc_context.h"
|
||||
|
||||
constexpr size_t PCR_SIZE = 0xAB0;
|
||||
|
@ -29,7 +27,6 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
|
|||
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
|
||||
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GuestThread::GetCurrentThreadId()); // thread id
|
||||
|
||||
ppcContext.fn = (uint8_t*)g_codeCache.bucket;
|
||||
ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
|
||||
ppcContext.r13.u64 = g_memory.MapVirtual(thread);
|
||||
ppcContext.fpscr.loadFromHost();
|
||||
|
@ -78,7 +75,7 @@ uint32_t GuestThread::Start(const GuestThreadParams& params)
|
|||
GuestThreadContext ctx(cpuNumber);
|
||||
ctx.ppcContext.r3.u64 = params.value;
|
||||
|
||||
reinterpret_cast<PPCFunc*>(g_codeCache.Find(params.function))(ctx.ppcContext, reinterpret_cast<uint8_t*>(g_memory.base));
|
||||
g_memory.FindFunction(params.function)(ctx.ppcContext, g_memory.base);
|
||||
|
||||
return ctx.ppcContext.r3.u32;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <app.h>
|
||||
#include <bc_diff.h>
|
||||
#include <cpu/code_cache.h>
|
||||
#include <cpu/guest_code.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <decompressor.h>
|
||||
#include <kernel/function.h>
|
||||
|
@ -1682,7 +1680,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||
memset(device, 0, sizeof(*device));
|
||||
|
||||
uint32_t functionOffset = 0x443344; // D3D
|
||||
g_codeCache.Insert(functionOffset, HostToGuestFunction<SetRenderStateUnimplemented>);
|
||||
g_memory.InsertFunction(functionOffset, HostToGuestFunction<SetRenderStateUnimplemented>);
|
||||
|
||||
for (size_t i = 0; i < std::size(device->setRenderStateFunctions); i++)
|
||||
device->setRenderStateFunctions[i] = functionOffset;
|
||||
|
@ -1690,7 +1688,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||
for (auto& [state, function] : g_setRenderStateFunctions)
|
||||
{
|
||||
functionOffset += 4;
|
||||
g_codeCache.Insert(functionOffset, function);
|
||||
g_memory.InsertFunction(functionOffset, function);
|
||||
device->setRenderStateFunctions[state / 4] = functionOffset;
|
||||
}
|
||||
|
||||
|
|
|
@ -314,19 +314,18 @@ T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
|
|||
auto& currentCtx = *GetPPCContext();
|
||||
|
||||
PPCContext newCtx; // NOTE: No need for zero initialization, has lots of unnecessary code generation.
|
||||
newCtx.fn = currentCtx.fn;
|
||||
newCtx.r1 = currentCtx.r1;
|
||||
newCtx.r13 = currentCtx.r13;
|
||||
newCtx.fpscr = currentCtx.fpscr;
|
||||
|
||||
_translate_args_to_guest(newCtx, (uint8_t*)g_memory.base, args);
|
||||
_translate_args_to_guest(newCtx, g_memory.base, args);
|
||||
|
||||
SetPPCContext(newCtx);
|
||||
|
||||
if constexpr (std::is_function_v<TFunction>)
|
||||
func(newCtx, (uint8_t*)g_memory.base);
|
||||
func(newCtx, g_memory.base);
|
||||
else
|
||||
(*(PPCFunc**)(newCtx.fn + uint64_t(func) * 2))(newCtx, (uint8_t*)g_memory.base);
|
||||
g_memory.FindFunction(func)(newCtx, g_memory.base);
|
||||
|
||||
currentCtx.fpscr = newCtx.fpscr;
|
||||
SetPPCContext(currentCtx);
|
||||
|
|
|
@ -8,10 +8,7 @@ constexpr size_t RESERVED_END = 0xA0000000;
|
|||
|
||||
void Heap::Init()
|
||||
{
|
||||
g_memory.Alloc(0x20000, RESERVED_BEGIN - 0x20000, MEM_COMMIT);
|
||||
heap = o1heapInit(g_memory.Translate(0x20000), RESERVED_BEGIN - 0x20000);
|
||||
|
||||
g_memory.Alloc(RESERVED_END, 0x100000000 - RESERVED_END, MEM_COMMIT);
|
||||
physicalHeap = o1heapInit(g_memory.Translate(RESERVED_END), 0x100000000 - RESERVED_END);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +1,30 @@
|
|||
#include <stdafx.h>
|
||||
#include "memory.h"
|
||||
|
||||
Memory::Memory(void* address, size_t size) : size(size)
|
||||
Memory::Memory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
base = (char*)VirtualAlloc(address, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
base = (uint8_t*)VirtualAlloc((void*)0x100000000ull, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
if (base == nullptr)
|
||||
base = (char*)VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
#else
|
||||
base = (char*)mmap(address, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
base = (uint8_t*)VirtualAlloc(nullptr, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
if (base == (char*)MAP_FAILED)
|
||||
base = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(base, 4096, PAGE_NOACCESS, &oldProtect);
|
||||
#else
|
||||
base = (uint8_t*)mmap((void*)0x100000000ull, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
if (base == (uint8_t*)MAP_FAILED)
|
||||
base = (uint8_t*)mmap(NULL, PPC_MEMORY_SIZE + PPC_FUNC_TABLE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
mprotect(base, 4096, PROT_NONE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* Memory::Alloc(size_t offset, size_t size, uint32_t type)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return VirtualAlloc(base + offset, size, type, PAGE_READWRITE);
|
||||
#else
|
||||
return base + offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
void* Memory::Commit(size_t offset, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return Alloc(offset, size, MEM_COMMIT);
|
||||
#else
|
||||
return base + offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
void* Memory::Reserve(size_t offset, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return Alloc(offset, size, MEM_RESERVE);
|
||||
#else
|
||||
return base + offset;
|
||||
#endif
|
||||
for (size_t i = 0; PPCFuncMappings[i].guest != 0; i++)
|
||||
{
|
||||
if (PPCFuncMappings[i].host != nullptr)
|
||||
InsertFunction(PPCFuncMappings[i].guest, PPCFuncMappings[i].host);
|
||||
}
|
||||
}
|
||||
|
||||
void* MmGetHostAddress(uint32_t ptr)
|
||||
|
|
|
@ -5,29 +5,21 @@
|
|||
#define MEM_RESERVE 0x00002000
|
||||
#endif
|
||||
|
||||
class Memory
|
||||
struct Memory
|
||||
{
|
||||
public:
|
||||
char* base{};
|
||||
size_t size{};
|
||||
size_t guestBase{};
|
||||
uint8_t* base{};
|
||||
|
||||
Memory(void* address, size_t size);
|
||||
|
||||
void* Alloc(size_t offset, size_t size, uint32_t type);
|
||||
|
||||
void* Commit(size_t offset, size_t size);
|
||||
void* Reserve(size_t offset, size_t size);
|
||||
Memory();
|
||||
|
||||
bool IsInMemoryRange(const void* host) const noexcept
|
||||
{
|
||||
return host >= base && host < (base + size);
|
||||
return host >= base && host < (base + PPC_MEMORY_SIZE);
|
||||
}
|
||||
|
||||
void* Translate(size_t offset) const noexcept
|
||||
{
|
||||
if (offset)
|
||||
assert(offset < 0x100000000ull);
|
||||
assert(offset < PPC_MEMORY_SIZE);
|
||||
|
||||
return base + offset;
|
||||
}
|
||||
|
@ -37,7 +29,17 @@ public:
|
|||
if (host)
|
||||
assert(IsInMemoryRange(host));
|
||||
|
||||
return static_cast<uint32_t>(static_cast<const char*>(host) - base);
|
||||
return static_cast<uint32_t>(static_cast<const uint8_t*>(host) - base);
|
||||
}
|
||||
|
||||
PPCFunc* FindFunction(uint32_t guest) const noexcept
|
||||
{
|
||||
return *reinterpret_cast<PPCFunc**>(base + PPC_FUNC_TABLE_OFFSET + (uint64_t(guest) * 2));
|
||||
}
|
||||
|
||||
void InsertFunction(uint32_t guest, PPCFunc* host)
|
||||
{
|
||||
*reinterpret_cast<PPCFunc**>(base + PPC_FUNC_TABLE_OFFSET + (uint64_t(guest) * 2)) = host;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <stdafx.h>
|
||||
#include <cpu/code_cache.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <gpu/video.h>
|
||||
#include <kernel/function.h>
|
||||
|
@ -25,9 +24,8 @@
|
|||
const size_t XMAIOBegin = 0x7FEA0000;
|
||||
const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
|
||||
|
||||
Memory g_memory{ reinterpret_cast<void*>(0x100000000), 0x100000000 };
|
||||
Memory g_memory;
|
||||
Heap g_userHeap;
|
||||
CodeCache g_codeCache;
|
||||
XDBFWrapper g_xdbfWrapper;
|
||||
std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
|
||||
|
||||
|
@ -37,11 +35,7 @@ void HostStartup()
|
|||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
#endif
|
||||
|
||||
g_memory.Alloc(0x10000, 0x1000, MEM_COMMIT);
|
||||
g_userHeap.Init();
|
||||
g_codeCache.Init();
|
||||
|
||||
g_memory.Alloc(XMAIOBegin, 0xFFFF, MEM_COMMIT);
|
||||
|
||||
hid::Init();
|
||||
}
|
||||
|
@ -109,8 +103,6 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
|||
auto* xex = reinterpret_cast<XEX_HEADER*>(loadResult.data());
|
||||
auto security = reinterpret_cast<XEX2_SECURITY_INFO*>((char*)xex + xex->AddressOfSecurityInfo);
|
||||
|
||||
g_memory.Alloc(security->ImageBase, security->SizeOfImage, MEM_COMMIT);
|
||||
|
||||
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
|
||||
auto entry = *Xex2FindOptionalHeader<uint32_t>(xex, XEX_HEADER_ENTRY_POINT);
|
||||
ByteSwapInplace(entry);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <user/config.h>
|
||||
#include <kernel/function.h>
|
||||
#include <os/media.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <cpu/code_cache.h>
|
||||
#include <cpu/guest_code.h>
|
||||
#include <kernel/memory.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
|
@ -87,13 +86,13 @@ bool LoadingUpdateMidAsmHook(PPCRegister& r31)
|
|||
double deltaTime = std::min(std::chrono::duration<double>(now - g_prev).count(), 1.0 / 15.0);
|
||||
g_prev = now;
|
||||
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(g_memory.base);
|
||||
uint8_t* base = g_memory.base;
|
||||
uint32_t application = PPC_LOAD_U32(PPC_LOAD_U32(r31.u32 + 4));
|
||||
uint32_t update = PPC_LOAD_U32(PPC_LOAD_U32(application) + 20);
|
||||
|
||||
g_ppcContext->r3.u32 = application;
|
||||
g_ppcContext->f1.f64 = deltaTime;
|
||||
reinterpret_cast<PPCFunc*>(g_codeCache.Find(update))(*g_ppcContext, base);
|
||||
g_memory.FindFunction(update)(*g_ppcContext, base);
|
||||
|
||||
bool loading = PPC_LOAD_U8(0x83367A4C);
|
||||
if (loading)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/achievement_data.h>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
|
||||
// CObjFlame::CObjFlame
|
||||
// A field is not zero initialized,
|
||||
// causing collisions to constantly get created
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <ui/window_events.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <user/achievement_data.h>
|
||||
#include <user/config.h>
|
||||
#include <api/SWA.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <kernel/function.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/achievement_menu.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <locale/locale.h>
|
||||
#include <ui/fader.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <locale/locale.h>
|
||||
#include <ui/button_guide.h>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <user/config.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/game_window.h>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 4650dc69fb40d0e5857fe28c40e85eec7c97edf7
|
||||
Subproject commit de2840970ffc3161a4cb8743b10ddd4da93bdc9f
|
Loading…
Add table
Add a link
Reference in a new issue