2021-03-21 21:32:26 +00:00
|
|
|
/*
|
2023-11-03 23:21:46 +00:00
|
|
|
Copyright 2016-2023 melonDS team
|
2021-03-21 21:32:26 +00:00
|
|
|
|
|
|
|
This file is part of melonDS.
|
|
|
|
|
|
|
|
melonDS 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, either version 3 of the License, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
melonDS 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 for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
|
|
*/
|
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#if defined(__SWITCH__)
|
2020-12-09 17:58:51 +00:00
|
|
|
#include <switch.h>
|
2020-06-30 21:50:41 +00:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
#include <windows.h>
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
|
2020-11-30 14:33:43 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <linux/ashmem.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
#include "ARMJIT.h"
|
2020-06-14 19:04:25 +00:00
|
|
|
#include "ARMJIT_Memory.h"
|
|
|
|
|
|
|
|
#include "ARMJIT_Internal.h"
|
|
|
|
#include "ARMJIT_Compiler.h"
|
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#include "DSi.h"
|
2020-06-14 19:04:25 +00:00
|
|
|
#include "GPU.h"
|
|
|
|
#include "GPU3D.h"
|
|
|
|
#include "Wifi.h"
|
|
|
|
#include "NDSCart.h"
|
|
|
|
#include "SPU.h"
|
|
|
|
|
2020-12-09 17:58:51 +00:00
|
|
|
#include <stdlib.h>
|
2020-06-14 19:04:25 +00:00
|
|
|
|
|
|
|
/*
|
2020-07-23 15:43:25 +00:00
|
|
|
We're handling fastmem here.
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
Basically we're repurposing a big piece of virtual memory
|
|
|
|
and map the memory regions as they're structured on the DS
|
|
|
|
in it.
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2022-03-06 20:21:50 +00:00
|
|
|
On most systems you have a single piece of main ram,
|
2020-07-23 15:43:25 +00:00
|
|
|
maybe some video ram and faster cache RAM and that's about it.
|
|
|
|
Here we have not only a lot more different memory regions,
|
|
|
|
but also two address spaces. Not only that but they all have
|
|
|
|
mirrors (the worst case is 16kb SWRAM which is mirrored 1024x).
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
We handle this by only mapping those regions which are actually
|
|
|
|
used and by praying the games don't go wild.
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-11-09 19:43:31 +00:00
|
|
|
Beware, this file is full of platform specific code and copied
|
|
|
|
from Dolphin, so enjoy the copied comments!
|
2020-06-14 19:04:25 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2021-02-25 21:17:11 +00:00
|
|
|
// Yes I know this looks messy, but better here than somewhere else in the code
|
2022-11-05 21:37:27 +00:00
|
|
|
#if defined(__x86_64__)
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#define CONTEXT_PC Rip
|
|
|
|
#elif defined(__linux__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.gregs[REG_RIP]
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
#define CONTEXT_PC uc_mcontext->__ss.__rip
|
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.mc_rip
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.__gregs[_REG_RIP]
|
|
|
|
#endif
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#define CONTEXT_PC Pc
|
|
|
|
#elif defined(__linux__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.pc
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
#define CONTEXT_PC uc_mcontext->__ss.__pc
|
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.mc_gpregs.gp_elr
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
#define CONTEXT_PC uc_mcontext.__gregs[_REG_PC]
|
2021-02-25 21:17:11 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2023-11-25 17:32:09 +00:00
|
|
|
namespace melonDS
|
|
|
|
{
|
|
|
|
|
|
|
|
using Platform::Log;
|
|
|
|
using Platform::LogLevel;
|
|
|
|
|
2020-11-30 14:33:43 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
#define ASHMEM_DEVICE "/dev/ashmem"
|
|
|
|
#endif
|
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#if defined(__SWITCH__)
|
2020-06-14 19:04:25 +00:00
|
|
|
// with LTO the symbols seem to be not properly overriden
|
|
|
|
// if they're somewhere else
|
|
|
|
|
2021-03-02 23:43:56 +00:00
|
|
|
void HandleFault(u64 pc, u64 lr, u64 fp, u64 faultAddr, u32 desc);
|
|
|
|
|
2020-06-14 19:04:25 +00:00
|
|
|
extern "C"
|
|
|
|
{
|
2022-03-06 20:21:50 +00:00
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
void ARM_RestoreContext(u64* registers) __attribute__((noreturn));
|
|
|
|
|
2020-06-14 19:04:25 +00:00
|
|
|
extern char __start__;
|
|
|
|
extern char __rodata_start;
|
|
|
|
|
|
|
|
alignas(16) u8 __nx_exception_stack[0x8000];
|
|
|
|
u64 __nx_exception_stack_size = 0x8000;
|
|
|
|
|
|
|
|
void __libnx_exception_handler(ThreadExceptionDump* ctx)
|
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
ARMJIT_Memory::FaultDescription desc;
|
|
|
|
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
|
|
|
|
desc.EmulatedFaultAddr = (u8*)ctx->far.x - curArea;
|
2020-11-09 19:43:31 +00:00
|
|
|
desc.FaultPC = (u8*)ctx->pc.x;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
|
|
|
u64 integerRegisters[33];
|
|
|
|
memcpy(integerRegisters, &ctx->cpu_gprs[0].x, 8*29);
|
|
|
|
integerRegisters[29] = ctx->fp.x;
|
|
|
|
integerRegisters[30] = ctx->lr.x;
|
|
|
|
integerRegisters[31] = ctx->sp.x;
|
|
|
|
integerRegisters[32] = ctx->pc.x;
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
if (Melon::FaultHandler(desc))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2020-11-09 19:43:31 +00:00
|
|
|
integerRegisters[32] = (u64)desc.FaultPC;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2022-03-06 20:21:50 +00:00
|
|
|
ARM_RestoreContext(integerRegisters);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 17:58:51 +00:00
|
|
|
HandleFault(ctx->pc.x, ctx->lr.x, ctx->fp.x, ctx->far.x, ctx->error_desc);
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
LONG ARMJIT_Memory::ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
2020-06-30 21:50:41 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
if (exceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
|
|
|
{
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
u8* curArea = (u8*)(NDS::Current->CurCPU == 0 ? NDS::Current->JIT.Memory.FastMem9Start : NDS::Current->JIT.Memory.FastMem7Start);
|
2023-11-18 15:40:54 +00:00
|
|
|
FaultDescription desc {};
|
2020-07-23 15:43:25 +00:00
|
|
|
desc.EmulatedFaultAddr = (u8*)exceptionInfo->ExceptionRecord->ExceptionInformation[1] - curArea;
|
2021-02-25 21:17:11 +00:00
|
|
|
desc.FaultPC = (u8*)exceptionInfo->ContextRecord->CONTEXT_PC;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
if (FaultHandler(desc, *NDS::Current))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2021-02-25 21:17:11 +00:00
|
|
|
exceptionInfo->ContextRecord->CONTEXT_PC = (u64)desc.FaultPC;
|
2020-07-23 15:43:25 +00:00
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
2020-06-30 21:50:41 +00:00
|
|
|
}
|
|
|
|
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
|
|
|
|
2020-11-09 19:43:31 +00:00
|
|
|
static struct sigaction OldSaSegv;
|
|
|
|
static struct sigaction OldSaBus;
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
|
2020-07-04 16:58:00 +00:00
|
|
|
{
|
2020-11-09 19:43:31 +00:00
|
|
|
if (sig != SIGSEGV && sig != SIGBUS)
|
|
|
|
{
|
|
|
|
// We are not interested in other signals - handle it as usual.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (info->si_code != SEGV_MAPERR && info->si_code != SEGV_ACCERR)
|
|
|
|
{
|
|
|
|
// Huh? Return.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
ucontext_t* context = (ucontext_t*)rawContext;
|
2020-11-09 19:43:31 +00:00
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
FaultDescription desc {};
|
2023-11-28 22:16:41 +00:00
|
|
|
u8* curArea = (u8*)(NDS::Current->CurCPU == 0 ? NDS::Current->JIT.Memory.FastMem9Start : NDS::Current->JIT.Memory.FastMem7Start);
|
2021-02-25 21:17:11 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
desc.EmulatedFaultAddr = (u8*)info->si_addr - curArea;
|
2021-02-25 21:17:11 +00:00
|
|
|
desc.FaultPC = (u8*)context->CONTEXT_PC;
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
if (FaultHandler(desc, *NDS::Current))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2021-02-25 21:17:11 +00:00
|
|
|
context->CONTEXT_PC = (u64)desc.FaultPC;
|
2020-07-23 15:43:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2020-11-09 19:43:31 +00:00
|
|
|
struct sigaction* oldSa;
|
|
|
|
if (sig == SIGSEGV)
|
|
|
|
oldSa = &OldSaSegv;
|
|
|
|
else
|
|
|
|
oldSa = &OldSaBus;
|
|
|
|
|
|
|
|
if (oldSa->sa_flags & SA_SIGINFO)
|
2020-07-04 16:58:00 +00:00
|
|
|
{
|
2020-11-09 19:43:31 +00:00
|
|
|
oldSa->sa_sigaction(sig, info, rawContext);
|
2020-07-04 16:58:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-11-09 19:43:31 +00:00
|
|
|
if (oldSa->sa_handler == SIG_DFL)
|
2020-07-04 16:58:00 +00:00
|
|
|
{
|
|
|
|
signal(sig, SIG_DFL);
|
|
|
|
return;
|
|
|
|
}
|
2020-11-09 19:43:31 +00:00
|
|
|
if (oldSa->sa_handler == SIG_IGN)
|
2020-07-04 16:58:00 +00:00
|
|
|
{
|
|
|
|
// Ignore signal
|
|
|
|
return;
|
|
|
|
}
|
2020-11-09 19:43:31 +00:00
|
|
|
oldSa->sa_handler(sig);
|
2020-07-04 16:58:00 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
const u32 OffsetsPerRegion[ARMJIT_Memory::memregions_Count] =
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
MemBlockDTCMOffset,
|
|
|
|
UINT32_MAX,
|
|
|
|
MemBlockMainRAMOffset,
|
|
|
|
MemBlockSWRAMOffset,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
MemBlockARM7WRAMOffset,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
UINT32_MAX,
|
|
|
|
MemBlockNWRAM_AOffset,
|
|
|
|
MemBlockNWRAM_BOffset,
|
|
|
|
MemBlockNWRAM_COffset
|
2020-06-14 19:04:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
memstate_Unmapped,
|
|
|
|
memstate_MappedRW,
|
2020-11-09 19:43:31 +00:00
|
|
|
// on Switch this is unmapped as well
|
2020-07-23 15:43:25 +00:00
|
|
|
memstate_MappedProtected,
|
2020-06-14 19:04:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
bool ARMJIT_Memory::MapIntoRange(u32 addr, u32 num, u32 offset, u32 size) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
|
2020-06-14 19:04:25 +00:00
|
|
|
#ifdef __SWITCH__
|
2022-03-06 20:21:50 +00:00
|
|
|
Result r = (svcMapProcessMemory(dst, envGetOwnProcessHandle(),
|
2020-07-23 15:43:25 +00:00
|
|
|
(u64)(MemoryBaseCodeMem + offset), size));
|
|
|
|
return R_SUCCEEDED(r);
|
2020-06-30 21:50:41 +00:00
|
|
|
#elif defined(_WIN32)
|
2020-07-23 15:43:25 +00:00
|
|
|
bool r = MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, offset, size, dst) == dst;
|
|
|
|
return r;
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-07-23 15:43:25 +00:00
|
|
|
return mmap(dst, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, offset) != MAP_FAILED;
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
bool ARMJIT_Memory::UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
|
2020-06-14 19:04:25 +00:00
|
|
|
#ifdef __SWITCH__
|
2020-07-23 15:43:25 +00:00
|
|
|
Result r = svcUnmapProcessMemory(dst, envGetOwnProcessHandle(),
|
|
|
|
(u64)(MemoryBaseCodeMem + offset), size);
|
|
|
|
return R_SUCCEEDED(r);
|
2020-07-04 16:58:00 +00:00
|
|
|
#elif defined(_WIN32)
|
2020-07-23 15:43:25 +00:00
|
|
|
return UnmapViewOfFile(dst);
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-07-23 15:43:25 +00:00
|
|
|
return munmap(dst, size) == 0;
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-09-11 17:29:06 +00:00
|
|
|
#ifndef __SWITCH__
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection) noexcept
|
2020-06-30 21:50:41 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
|
2020-06-30 21:50:41 +00:00
|
|
|
#if defined(_WIN32)
|
2020-07-23 15:43:25 +00:00
|
|
|
DWORD winProtection, oldProtection;
|
|
|
|
if (protection == 0)
|
|
|
|
winProtection = PAGE_NOACCESS;
|
|
|
|
else if (protection == 1)
|
|
|
|
winProtection = PAGE_READONLY;
|
|
|
|
else
|
|
|
|
winProtection = PAGE_READWRITE;
|
|
|
|
bool success = VirtualProtect(dst, size, winProtection, &oldProtection);
|
|
|
|
assert(success);
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-07-23 15:43:25 +00:00
|
|
|
int posixProt;
|
|
|
|
if (protection == 0)
|
|
|
|
posixProt = PROT_NONE;
|
|
|
|
else if (protection == 1)
|
|
|
|
posixProt = PROT_READ;
|
|
|
|
else
|
|
|
|
posixProt = PROT_READ | PROT_WRITE;
|
|
|
|
mprotect(dst, size, posixProt);
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
2020-09-11 17:29:06 +00:00
|
|
|
#endif
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
void ARMJIT_Memory::Mapping::Unmap(int region, melonDS::NDS& nds) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
u32 dtcmStart = nds.ARM9.DTCMBase;
|
|
|
|
u32 dtcmSize = ~nds.ARM9.DTCMMask + 1;
|
2023-11-18 15:40:54 +00:00
|
|
|
bool skipDTCM = Num == 0 && region != memregion_DTCM;
|
2023-11-28 22:16:41 +00:00
|
|
|
u8* statuses = Num == 0 ? nds.JIT.Memory.MappingStatus9 : nds.JIT.Memory.MappingStatus7;
|
2023-11-18 15:40:54 +00:00
|
|
|
u32 offset = 0;
|
|
|
|
while (offset < Size)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
if (skipDTCM && Addr + offset == dtcmStart)
|
|
|
|
{
|
|
|
|
offset += dtcmSize;
|
|
|
|
}
|
|
|
|
else
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
u32 segmentOffset = offset;
|
|
|
|
u8 status = statuses[(Addr + offset) >> 12];
|
|
|
|
while (statuses[(Addr + offset) >> 12] == status
|
|
|
|
&& offset < Size
|
|
|
|
&& (!skipDTCM || Addr + offset != dtcmStart))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
assert(statuses[(Addr + offset) >> 12] != memstate_Unmapped);
|
|
|
|
statuses[(Addr + offset) >> 12] = memstate_Unmapped;
|
|
|
|
offset += 0x1000;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#ifdef __SWITCH__
|
2023-11-18 15:40:54 +00:00
|
|
|
if (status == memstate_MappedRW)
|
|
|
|
{
|
|
|
|
u32 segmentSize = offset - segmentOffset;
|
|
|
|
Log(LogLevel::Debug, "unmapping %x %x %x %x\n", Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
|
|
|
|
bool success = memory.UnmapFromRange(Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
|
|
|
|
assert(success);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2023-11-18 15:40:54 +00:00
|
|
|
#endif
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2023-11-18 15:40:54 +00:00
|
|
|
}
|
2020-11-13 14:20:53 +00:00
|
|
|
|
2020-07-04 16:58:00 +00:00
|
|
|
#ifndef __SWITCH__
|
2020-11-13 14:20:53 +00:00
|
|
|
#ifndef _WIN32
|
2023-11-18 15:40:54 +00:00
|
|
|
u32 dtcmEnd = dtcmStart + dtcmSize;
|
|
|
|
if (Num == 0
|
|
|
|
&& dtcmEnd >= Addr
|
|
|
|
&& dtcmStart < Addr + Size)
|
|
|
|
{
|
|
|
|
bool success;
|
|
|
|
if (dtcmStart > Addr)
|
2020-11-13 14:20:53 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
success = nds.JIT.Memory.UnmapFromRange(Addr, 0, OffsetsPerRegion[region] + LocalOffset, dtcmStart - Addr);
|
2023-11-18 15:40:54 +00:00
|
|
|
assert(success);
|
2020-11-13 14:20:53 +00:00
|
|
|
}
|
2023-11-18 15:40:54 +00:00
|
|
|
if (dtcmEnd < Addr + Size)
|
2020-11-13 14:20:53 +00:00
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
u32 offset = dtcmStart - Addr + dtcmSize;
|
2023-11-28 22:16:41 +00:00
|
|
|
success = nds.JIT.Memory.UnmapFromRange(dtcmEnd, 0, OffsetsPerRegion[region] + LocalOffset + offset, Size - offset);
|
2023-11-18 15:40:54 +00:00
|
|
|
assert(success);
|
2020-11-13 14:20:53 +00:00
|
|
|
}
|
2023-11-18 15:40:54 +00:00
|
|
|
}
|
|
|
|
else
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
2023-11-18 15:40:54 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
bool succeded = nds.JIT.Memory.UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
|
2023-11-18 15:40:54 +00:00
|
|
|
assert(succeded);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2023-11-18 15:40:54 +00:00
|
|
|
#endif
|
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::SetCodeProtection(int region, u32 offset, bool protect) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
offset &= ~0xFFF;
|
2020-07-28 23:31:57 +00:00
|
|
|
//printf("set code protection %d %x %d\n", region, offset, protect);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
for (int i = 0; i < Mappings[region].Length; i++)
|
|
|
|
{
|
|
|
|
Mapping& mapping = Mappings[region][i];
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
if (offset < mapping.LocalOffset || offset >= mapping.LocalOffset + mapping.Size)
|
|
|
|
continue;
|
2020-07-08 21:08:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u32 effectiveAddr = mapping.Addr + (offset - mapping.LocalOffset);
|
|
|
|
if (mapping.Num == 0
|
2022-03-06 20:21:50 +00:00
|
|
|
&& region != memregion_DTCM
|
2023-11-28 22:16:41 +00:00
|
|
|
&& (effectiveAddr & NDS.ARM9.DTCMMask) == NDS.ARM9.DTCMBase)
|
2020-07-23 15:43:25 +00:00
|
|
|
continue;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* states = (u8*)(mapping.Num == 0 ? MappingStatus9 : MappingStatus7);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-28 23:31:57 +00:00
|
|
|
//printf("%x %d %x %x %x %d\n", effectiveAddr, mapping.Num, mapping.Addr, mapping.LocalOffset, mapping.Size, states[effectiveAddr >> 12]);
|
2020-07-23 15:43:25 +00:00
|
|
|
assert(states[effectiveAddr >> 12] == (protect ? memstate_MappedRW : memstate_MappedProtected));
|
|
|
|
states[effectiveAddr >> 12] = protect ? memstate_MappedProtected : memstate_MappedRW;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#if defined(__SWITCH__)
|
2020-07-23 15:43:25 +00:00
|
|
|
bool success;
|
|
|
|
if (protect)
|
|
|
|
success = UnmapFromRange(effectiveAddr, mapping.Num, OffsetsPerRegion[region] + offset, 0x1000);
|
|
|
|
else
|
|
|
|
success = MapIntoRange(effectiveAddr, mapping.Num, OffsetsPerRegion[region] + offset, 0x1000);
|
|
|
|
assert(success);
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-07-23 15:43:25 +00:00
|
|
|
SetCodeProtectionRange(effectiveAddr, 0x1000, mapping.Num, protect ? 1 : 2);
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::RemapDTCM(u32 newBase, u32 newSize) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
// this first part could be made more efficient
|
|
|
|
// by unmapping DTCM first and then map the holes
|
2023-11-28 22:16:41 +00:00
|
|
|
u32 oldDTCMBase = NDS.ARM9.DTCMBase;
|
|
|
|
u32 oldDTCMSize = ~NDS.ARM9.DTCMMask + 1;
|
|
|
|
u32 oldDTCMEnd = oldDTCMBase + NDS.ARM9.DTCMMask;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
|
|
|
u32 newEnd = newBase + newSize;
|
|
|
|
|
2023-03-23 17:04:38 +00:00
|
|
|
Log(LogLevel::Debug, "remapping DTCM %x %x %x %x\n", newBase, newEnd, oldDTCMBase, oldDTCMEnd);
|
2020-07-23 15:43:25 +00:00
|
|
|
// unmap all regions containing the old or the current DTCM mapping
|
|
|
|
for (int region = 0; region < memregions_Count; region++)
|
|
|
|
{
|
|
|
|
if (region == memregion_DTCM)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int i = 0; i < Mappings[region].Length;)
|
|
|
|
{
|
|
|
|
Mapping& mapping = Mappings[region][i];
|
|
|
|
|
|
|
|
u32 start = mapping.Addr;
|
|
|
|
u32 end = mapping.Addr + mapping.Size;
|
|
|
|
|
2023-03-23 17:04:38 +00:00
|
|
|
Log(LogLevel::Debug, "unmapping %d %x %x %x %x\n", region, mapping.Addr, mapping.Size, mapping.Num, mapping.LocalOffset);
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2021-10-29 10:09:00 +00:00
|
|
|
bool overlap = (oldDTCMSize > 0 && oldDTCMBase < end && oldDTCMEnd > start)
|
2020-11-13 14:20:53 +00:00
|
|
|
|| (newSize > 0 && newBase < end && newEnd > start);
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2020-11-13 14:20:53 +00:00
|
|
|
if (mapping.Num == 0 && overlap)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mapping.Unmap(region, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
Mappings[region].Remove(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < Mappings[memregion_DTCM].Length; i++)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
Mappings[memregion_DTCM][i].Unmap(memregion_DTCM, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
Mappings[memregion_DTCM].Clear();
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::RemapNWRAM(int num) noexcept
|
2020-06-30 21:50:41 +00:00
|
|
|
{
|
2023-12-06 14:10:30 +00:00
|
|
|
if (NDS.ConsoleType == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto* dsi = static_cast<DSi*>(&NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
|
|
|
|
{
|
|
|
|
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
|
2023-11-28 22:16:41 +00:00
|
|
|
if (dsi->NWRAMStart[mapping.Num][num] < mapping.Addr + mapping.Size
|
|
|
|
&& dsi->NWRAMEnd[mapping.Num][num] > mapping.Addr)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mapping.Unmap(memregion_SharedWRAM, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
Mappings[memregion_SharedWRAM].Remove(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < Mappings[memregion_NewSharedWRAM_A + num].Length; i++)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
Mappings[memregion_NewSharedWRAM_A + num][i].Unmap(memregion_NewSharedWRAM_A + num, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
Mappings[memregion_NewSharedWRAM_A + num].Clear();
|
2020-06-30 21:50:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::RemapSWRAM() noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-03-23 17:04:38 +00:00
|
|
|
Log(LogLevel::Debug, "remapping SWRAM\n");
|
2020-07-23 15:43:25 +00:00
|
|
|
for (int i = 0; i < Mappings[memregion_WRAM7].Length;)
|
|
|
|
{
|
|
|
|
Mapping& mapping = Mappings[memregion_WRAM7][i];
|
2020-11-13 14:20:53 +00:00
|
|
|
if (mapping.Addr + mapping.Size <= 0x03800000)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mapping.Unmap(memregion_WRAM7, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
Mappings[memregion_WRAM7].Remove(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length; i++)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
Mappings[memregion_SharedWRAM][i].Unmap(memregion_SharedWRAM, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
Mappings[memregion_SharedWRAM].Clear();
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
u32 num = NDS.CurCPU;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
int region = num == 0
|
|
|
|
? ClassifyAddress9(addr)
|
|
|
|
: ClassifyAddress7(addr);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
if (!IsFastmemCompatible(region))
|
|
|
|
return false;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u32 mirrorStart, mirrorSize, memoryOffset;
|
|
|
|
bool isMapped = GetMirrorLocation(region, num, addr, memoryOffset, mirrorStart, mirrorSize);
|
|
|
|
if (!isMapped)
|
|
|
|
return false;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* states = num == 0 ? MappingStatus9 : MappingStatus7;
|
2021-06-07 17:01:57 +00:00
|
|
|
//printf("mapping mirror %x, %x %x %d %d\n", mirrorStart, mirrorSize, memoryOffset, region, num);
|
2023-11-28 22:16:41 +00:00
|
|
|
bool isExecutable = NDS.JIT.CodeMemRegions[region];
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
u32 dtcmStart = NDS.ARM9.DTCMBase;
|
|
|
|
u32 dtcmSize = ~NDS.ARM9.DTCMMask + 1;
|
2020-11-13 14:20:53 +00:00
|
|
|
u32 dtcmEnd = dtcmStart + dtcmSize;
|
2020-07-04 16:58:00 +00:00
|
|
|
#ifndef __SWITCH__
|
2020-11-13 14:20:53 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
if (num == 0
|
|
|
|
&& dtcmEnd >= mirrorStart
|
|
|
|
&& dtcmStart < mirrorStart + mirrorSize)
|
2020-11-09 19:43:31 +00:00
|
|
|
{
|
2020-11-13 14:20:53 +00:00
|
|
|
bool success;
|
|
|
|
if (dtcmStart > mirrorStart)
|
2020-11-09 19:43:31 +00:00
|
|
|
{
|
2020-11-13 14:20:53 +00:00
|
|
|
success = MapIntoRange(mirrorStart, 0, OffsetsPerRegion[region] + memoryOffset, dtcmStart - mirrorStart);
|
|
|
|
assert(success);
|
|
|
|
}
|
|
|
|
if (dtcmEnd < mirrorStart + mirrorSize)
|
|
|
|
{
|
|
|
|
u32 offset = dtcmStart - mirrorStart + dtcmSize;
|
|
|
|
success = MapIntoRange(dtcmEnd, 0, OffsetsPerRegion[region] + memoryOffset + offset, mirrorSize - offset);
|
|
|
|
assert(success);
|
2020-11-09 19:43:31 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-13 14:20:53 +00:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
|
|
|
|
assert(succeded);
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
AddressRange* range = NDS.JIT.CodeMemRegions[region] + memoryOffset / 512;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
|
|
|
// this overcomplicated piece of code basically just finds whole pieces of code memory
|
2020-11-13 14:20:53 +00:00
|
|
|
// which can be mapped/protected
|
2022-03-06 20:21:50 +00:00
|
|
|
u32 offset = 0;
|
2020-07-23 15:43:25 +00:00
|
|
|
bool skipDTCM = num == 0 && region != memregion_DTCM;
|
|
|
|
while (offset < mirrorSize)
|
|
|
|
{
|
2020-11-13 14:20:53 +00:00
|
|
|
if (skipDTCM && mirrorStart + offset == dtcmStart)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2020-11-13 14:20:53 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
SetCodeProtectionRange(dtcmStart, dtcmSize, 0, 0);
|
|
|
|
#endif
|
|
|
|
offset += dtcmSize;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 sectionOffset = offset;
|
2023-11-25 17:32:09 +00:00
|
|
|
bool hasCode = isExecutable && PageContainsCode(&range[offset / 512]);
|
2020-08-25 16:13:17 +00:00
|
|
|
while (offset < mirrorSize
|
2023-11-25 17:32:09 +00:00
|
|
|
&& (!isExecutable || PageContainsCode(&range[offset / 512]) == hasCode)
|
2023-11-28 22:16:41 +00:00
|
|
|
&& (!skipDTCM || mirrorStart + offset != NDS.ARM9.DTCMBase))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
assert(states[(mirrorStart + offset) >> 12] == memstate_Unmapped);
|
|
|
|
states[(mirrorStart + offset) >> 12] = hasCode ? memstate_MappedProtected : memstate_MappedRW;
|
|
|
|
offset += 0x1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 sectionSize = offset - sectionOffset;
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-06-30 21:50:41 +00:00
|
|
|
#if defined(__SWITCH__)
|
2020-07-23 15:43:25 +00:00
|
|
|
if (!hasCode)
|
|
|
|
{
|
2021-06-07 17:01:57 +00:00
|
|
|
//printf("trying to map %x (size: %x) from %x\n", mirrorStart + sectionOffset, sectionSize, sectionOffset + memoryOffset + OffsetsPerRegion[region]);
|
2020-07-23 15:43:25 +00:00
|
|
|
bool succeded = MapIntoRange(mirrorStart + sectionOffset, num, sectionOffset + memoryOffset + OffsetsPerRegion[region], sectionSize);
|
|
|
|
assert(succeded);
|
|
|
|
}
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-07-23 15:43:25 +00:00
|
|
|
if (hasCode)
|
|
|
|
{
|
|
|
|
SetCodeProtectionRange(mirrorStart + sectionOffset, sectionSize, num, 1);
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
assert(num == 0 || num == 1);
|
|
|
|
Mapping mapping{mirrorStart, mirrorSize, memoryOffset, num};
|
|
|
|
Mappings[region].Add(mapping);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-11-13 14:20:53 +00:00
|
|
|
//printf("mapped mirror at %08x-%08x\n", mirrorStart, mirrorStart + mirrorSize - 1);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
bool ARMJIT_Memory::FaultHandler(FaultDescription& faultDesc, melonDS::NDS& nds)
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
if (nds.JIT.JITCompiler.IsJITFault(faultDesc.FaultPC))
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
bool rewriteToSlowPath = true;
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
u8* memStatus = nds.CurCPU == 0 ? nds.JIT.Memory.MappingStatus9 : nds.JIT.Memory.MappingStatus7;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2020-11-09 19:43:31 +00:00
|
|
|
if (memStatus[faultDesc.EmulatedFaultAddr >> 12] == memstate_Unmapped)
|
2023-11-28 22:16:41 +00:00
|
|
|
rewriteToSlowPath = !nds.JIT.Memory.MapAtAddress(faultDesc.EmulatedFaultAddr);
|
2020-07-23 15:43:25 +00:00
|
|
|
|
|
|
|
if (rewriteToSlowPath)
|
2023-11-28 22:16:41 +00:00
|
|
|
faultDesc.FaultPC = nds.JIT.JITCompiler.RewriteMemAccess(faultDesc.FaultPC);
|
2020-11-09 19:43:31 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 17:58:51 +00:00
|
|
|
const u64 AddrSpaceSize = 0x100000000;
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
|
|
|
#if defined(__SWITCH__)
|
2020-12-09 17:58:51 +00:00
|
|
|
MemoryBase = (u8*)aligned_alloc(0x1000, MemoryTotalSize);
|
2021-01-05 13:36:15 +00:00
|
|
|
virtmemLock();
|
|
|
|
MemoryBaseCodeMem = (u8*)virtmemFindCodeMemory(MemoryTotalSize, 0x1000);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2022-03-06 20:21:50 +00:00
|
|
|
bool succeded = R_SUCCEEDED(svcMapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem,
|
2020-06-14 19:04:25 +00:00
|
|
|
(u64)MemoryBase, MemoryTotalSize));
|
|
|
|
assert(succeded);
|
2022-03-06 20:21:50 +00:00
|
|
|
succeded = R_SUCCEEDED(svcSetProcessMemoryPermission(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem,
|
2020-06-14 19:04:25 +00:00
|
|
|
MemoryTotalSize, Perm_Rw));
|
2020-07-23 15:43:25 +00:00
|
|
|
assert(succeded);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
// 8 GB of address space, just don't ask...
|
2021-01-05 13:36:15 +00:00
|
|
|
FastMem9Start = virtmemFindAslr(AddrSpaceSize, 0x1000);
|
2020-07-23 15:43:25 +00:00
|
|
|
assert(FastMem9Start);
|
2021-01-05 13:36:15 +00:00
|
|
|
FastMem7Start = virtmemFindAslr(AddrSpaceSize, 0x1000);
|
2020-07-23 15:43:25 +00:00
|
|
|
assert(FastMem7Start);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2021-01-05 13:36:15 +00:00
|
|
|
FastMem9Reservation = virtmemAddReservation(FastMem9Start, AddrSpaceSize);
|
|
|
|
FastMem7Reservation = virtmemAddReservation(FastMem7Start, AddrSpaceSize);
|
|
|
|
virtmemUnlock();
|
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* basePtr = MemoryBaseCodeMem;
|
2020-06-30 21:50:41 +00:00
|
|
|
#elif defined(_WIN32)
|
2020-07-23 15:43:25 +00:00
|
|
|
ExceptionHandlerHandle = AddVectoredExceptionHandler(1, ExceptionHandler);
|
2020-06-30 21:50:41 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MemoryTotalSize, NULL);
|
2020-06-14 19:04:25 +00:00
|
|
|
|
2021-02-09 21:19:44 +00:00
|
|
|
MemoryBase = (u8*)VirtualAlloc(NULL, AddrSpaceSize*4, MEM_RESERVE, PAGE_READWRITE);
|
2020-07-23 15:43:25 +00:00
|
|
|
VirtualFree(MemoryBase, 0, MEM_RELEASE);
|
2021-02-09 22:36:46 +00:00
|
|
|
// this is incredible hacky
|
|
|
|
// but someone else is trying to go into our address space!
|
|
|
|
// Windows will very likely give them virtual memory starting at the same address
|
|
|
|
// as it is giving us now.
|
|
|
|
// That's why we don't use this address, but instead 4gb inwards
|
|
|
|
// I know this is terrible
|
|
|
|
FastMem9Start = MemoryBase + AddrSpaceSize;
|
|
|
|
FastMem7Start = MemoryBase + AddrSpaceSize*2;
|
|
|
|
MemoryBase = MemoryBase + AddrSpaceSize*3;
|
2020-06-30 21:50:41 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, MemoryTotalSize, MemoryBase);
|
2020-07-04 16:58:00 +00:00
|
|
|
#else
|
2020-11-09 19:43:31 +00:00
|
|
|
// this used to be allocated with three different mmaps
|
2022-03-06 20:21:50 +00:00
|
|
|
// The idea was to give the OS more freedom where to position the buffers,
|
2020-11-09 19:43:31 +00:00
|
|
|
// but something was bad about this so instead we take this vmem eating monster
|
|
|
|
// which seems to work better.
|
|
|
|
MemoryBase = (u8*)mmap(NULL, AddrSpaceSize*4, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
|
|
munmap(MemoryBase, AddrSpaceSize*4);
|
|
|
|
FastMem9Start = MemoryBase;
|
|
|
|
FastMem7Start = MemoryBase + AddrSpaceSize;
|
|
|
|
MemoryBase = MemoryBase + AddrSpaceSize*2;
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2020-11-30 14:33:43 +00:00
|
|
|
#if defined(__ANDROID__)
|
2023-08-18 20:50:57 +00:00
|
|
|
Libandroid = Platform::DynamicLibrary_Load("libandroid.so");
|
2020-11-30 14:33:43 +00:00
|
|
|
using type_ASharedMemory_create = int(*)(const char* name, size_t size);
|
2023-08-18 20:50:57 +00:00
|
|
|
auto ASharedMemory_create = reinterpret_cast<type_ASharedMemory_create>(Platform::DynamicLibrary_LoadFunction(Libandroid, "ASharedMemory_create"));
|
2020-11-30 14:33:43 +00:00
|
|
|
|
2023-08-18 20:50:57 +00:00
|
|
|
if (ASharedMemory_create)
|
2020-11-30 14:33:43 +00:00
|
|
|
{
|
2023-08-18 20:50:57 +00:00
|
|
|
MemoryFile = ASharedMemory_create("melondsfastmem", MemoryTotalSize);
|
2020-11-30 14:33:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int fd = open(ASHMEM_DEVICE, O_RDWR);
|
|
|
|
ioctl(fd, ASHMEM_SET_NAME, "melondsfastmem");
|
|
|
|
ioctl(fd, ASHMEM_SET_SIZE, MemoryTotalSize);
|
|
|
|
MemoryFile = fd;
|
|
|
|
}
|
|
|
|
#else
|
2021-01-22 18:20:32 +00:00
|
|
|
char fastmemPidName[snprintf(NULL, 0, "/melondsfastmem%d", getpid()) + 1];
|
|
|
|
sprintf(fastmemPidName, "/melondsfastmem%d", getpid());
|
|
|
|
MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600);
|
|
|
|
if (MemoryFile == -1)
|
|
|
|
{
|
2023-08-18 20:50:57 +00:00
|
|
|
Log(LogLevel::Error, "Failed to open memory using shm_open! (%s)", strerror(errno));
|
2021-01-22 18:20:32 +00:00
|
|
|
}
|
|
|
|
shm_unlink(fastmemPidName);
|
2020-11-30 14:33:43 +00:00
|
|
|
#endif
|
2021-01-22 18:20:32 +00:00
|
|
|
if (ftruncate(MemoryFile, MemoryTotalSize) < 0)
|
|
|
|
{
|
2023-08-18 20:50:57 +00:00
|
|
|
Log(LogLevel::Error, "Failed to allocate memory using ftruncate! (%s)", strerror(errno));
|
2021-01-22 18:20:32 +00:00
|
|
|
}
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2020-11-09 19:43:31 +00:00
|
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = nullptr;
|
|
|
|
sa.sa_sigaction = &SigsegvHandler;
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sigaction(SIGSEGV, &sa, &OldSaSegv);
|
|
|
|
#ifdef __APPLE__
|
|
|
|
sigaction(SIGBUS, &sa, &OldSaBus);
|
|
|
|
#endif
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
|
2020-07-04 16:58:00 +00:00
|
|
|
|
2020-07-23 15:43:25 +00:00
|
|
|
u8* basePtr = MemoryBase;
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
ARMJIT_Memory::~ARMJIT_Memory() noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
|
|
|
#if defined(__SWITCH__)
|
2021-01-05 13:36:15 +00:00
|
|
|
virtmemLock();
|
2023-09-15 13:31:05 +00:00
|
|
|
if (FastMem9Reservation)
|
|
|
|
virtmemRemoveReservation(FastMem9Reservation);
|
|
|
|
|
|
|
|
if (FastMem7Reservation)
|
|
|
|
virtmemRemoveReservation(FastMem7Reservation);
|
|
|
|
|
|
|
|
FastMem9Reservation = nullptr;
|
|
|
|
FastMem7Reservation = nullptr;
|
2021-01-05 13:36:15 +00:00
|
|
|
virtmemUnlock();
|
2020-06-14 19:04:25 +00:00
|
|
|
|
|
|
|
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
|
|
|
|
free(MemoryBase);
|
2023-09-15 13:31:05 +00:00
|
|
|
MemoryBase = nullptr;
|
2020-06-30 21:50:41 +00:00
|
|
|
#elif defined(_WIN32)
|
2023-09-15 13:31:05 +00:00
|
|
|
if (MemoryBase)
|
|
|
|
{
|
|
|
|
bool viewUnmapped = UnmapViewOfFile(MemoryBase);
|
|
|
|
assert(viewUnmapped);
|
|
|
|
MemoryBase = nullptr;
|
|
|
|
FastMem9Start = nullptr;
|
|
|
|
FastMem7Start = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MemoryFile)
|
|
|
|
{
|
|
|
|
CloseHandle(MemoryFile);
|
|
|
|
MemoryFile = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
|
2023-09-15 13:31:05 +00:00
|
|
|
if (ExceptionHandlerHandle)
|
|
|
|
{
|
|
|
|
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
|
|
|
ExceptionHandlerHandle = nullptr;
|
|
|
|
}
|
2020-11-09 19:43:31 +00:00
|
|
|
#else
|
|
|
|
sigaction(SIGSEGV, &OldSaSegv, nullptr);
|
|
|
|
#ifdef __APPLE__
|
|
|
|
sigaction(SIGBUS, &OldSaBus, nullptr);
|
|
|
|
#endif
|
2023-09-15 13:31:05 +00:00
|
|
|
if (MemoryBase)
|
|
|
|
{
|
|
|
|
munmap(MemoryBase, MemoryTotalSize);
|
|
|
|
MemoryBase = nullptr;
|
|
|
|
FastMem9Start = nullptr;
|
|
|
|
FastMem7Start = nullptr;
|
|
|
|
}
|
2020-11-09 19:43:31 +00:00
|
|
|
|
2023-09-15 13:31:05 +00:00
|
|
|
if (MemoryFile >= 0)
|
|
|
|
{
|
|
|
|
close(MemoryFile);
|
|
|
|
MemoryFile = -1;
|
|
|
|
}
|
2023-08-18 20:50:57 +00:00
|
|
|
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
if (Libandroid)
|
|
|
|
{
|
|
|
|
Platform::DynamicLibrary_Unload(Libandroid);
|
|
|
|
Libandroid = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-06-14 19:04:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void ARMJIT_Memory::Reset() noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
for (int region = 0; region < memregions_Count; region++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < Mappings[region].Length; i++)
|
2023-11-28 22:16:41 +00:00
|
|
|
Mappings[region][i].Unmap(region, NDS);
|
2020-07-23 15:43:25 +00:00
|
|
|
Mappings[region].Clear();
|
|
|
|
}
|
|
|
|
|
2021-05-03 12:36:21 +00:00
|
|
|
for (size_t i = 0; i < sizeof(MappingStatus9); i++)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
assert(MappingStatus9[i] == memstate_Unmapped);
|
|
|
|
assert(MappingStatus7[i] == memstate_Unmapped);
|
|
|
|
}
|
|
|
|
|
2023-03-23 17:04:38 +00:00
|
|
|
Log(LogLevel::Debug, "done resetting jit mem\n");
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
bool ARMJIT_Memory::IsFastmemCompatible(int region) const noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-06-30 21:50:41 +00:00
|
|
|
#ifdef _WIN32
|
2020-07-23 15:43:25 +00:00
|
|
|
/*
|
|
|
|
TODO: with some hacks, the smaller shared WRAM regions
|
|
|
|
could be mapped in some occaisons as well
|
|
|
|
*/
|
2022-03-06 20:21:50 +00:00
|
|
|
if (region == memregion_DTCM
|
2020-07-23 15:43:25 +00:00
|
|
|
|| region == memregion_SharedWRAM
|
|
|
|
|| region == memregion_NewSharedWRAM_B
|
|
|
|
|| region == memregion_NewSharedWRAM_C)
|
|
|
|
return false;
|
2020-06-30 21:50:41 +00:00
|
|
|
#endif
|
2020-11-13 14:20:53 +00:00
|
|
|
return OffsetsPerRegion[region] != UINT32_MAX;
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
bool ARMJIT_Memory::GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize) const noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
memoryOffset = 0;
|
|
|
|
switch (region)
|
|
|
|
{
|
|
|
|
case memregion_ITCM:
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
mirrorStart = addr & ~(ITCMPhysicalSize - 1);
|
|
|
|
mirrorSize = ITCMPhysicalSize;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_DTCM:
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
mirrorStart = addr & ~(DTCMPhysicalSize - 1);
|
|
|
|
mirrorSize = DTCMPhysicalSize;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_MainRAM:
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorStart = addr & ~NDS.MainRAMMask;
|
|
|
|
mirrorSize = NDS.MainRAMMask + 1;
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
case memregion_BIOS9:
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
mirrorStart = addr & ~0xFFF;
|
|
|
|
mirrorSize = 0x1000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_BIOS7:
|
|
|
|
if (num == 1)
|
|
|
|
{
|
|
|
|
mirrorStart = 0;
|
|
|
|
mirrorSize = 0x4000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_SharedWRAM:
|
2023-11-28 22:16:41 +00:00
|
|
|
if (num == 0 && NDS.SWRAM_ARM9.Mem)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorStart = addr & ~NDS.SWRAM_ARM9.Mask;
|
|
|
|
mirrorSize = NDS.SWRAM_ARM9.Mask + 1;
|
|
|
|
memoryOffset = NDS.SWRAM_ARM9.Mem - GetSharedWRAM();
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
2023-11-28 22:16:41 +00:00
|
|
|
else if (num == 1 && NDS.SWRAM_ARM7.Mem)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorStart = addr & ~NDS.SWRAM_ARM7.Mask;
|
|
|
|
mirrorSize = NDS.SWRAM_ARM7.Mask + 1;
|
|
|
|
memoryOffset = NDS.SWRAM_ARM7.Mem - GetSharedWRAM();
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_WRAM7:
|
|
|
|
if (num == 1)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorStart = addr & ~(ARM7WRAMSize - 1);
|
|
|
|
mirrorSize = ARM7WRAMSize;
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_VRAM:
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
mirrorStart = addr & ~0xFFFFF;
|
|
|
|
mirrorSize = 0x100000;
|
2020-08-09 11:29:04 +00:00
|
|
|
return true;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_VWRAM:
|
|
|
|
if (num == 1)
|
|
|
|
{
|
|
|
|
mirrorStart = addr & ~0x3FFFF;
|
|
|
|
mirrorSize = 0x40000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_NewSharedWRAM_A:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_A[num][(addr >> 16) & dsi->NWRAMMask[num][0]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
memoryOffset = ptr - GetNWRAM_A();
|
2020-07-23 15:43:25 +00:00
|
|
|
mirrorStart = addr & ~0xFFFF;
|
|
|
|
mirrorSize = 0x10000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false; // zero filled memory
|
|
|
|
}
|
|
|
|
case memregion_NewSharedWRAM_B:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_B[num][(addr >> 15) & dsi->NWRAMMask[num][1]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
memoryOffset = ptr - GetNWRAM_B();
|
2020-07-23 15:43:25 +00:00
|
|
|
mirrorStart = addr & ~0x7FFF;
|
|
|
|
mirrorSize = 0x8000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false; // zero filled memory
|
|
|
|
}
|
|
|
|
case memregion_NewSharedWRAM_C:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_C[num][(addr >> 15) & dsi->NWRAMMask[num][2]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
|
|
|
{
|
2023-11-18 15:40:54 +00:00
|
|
|
memoryOffset = ptr - GetNWRAM_C();
|
2020-07-23 15:43:25 +00:00
|
|
|
mirrorStart = addr & ~0x7FFF;
|
|
|
|
mirrorSize = 0x8000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false; // zero filled memory
|
|
|
|
}
|
|
|
|
case memregion_BIOS9DSi:
|
|
|
|
if (num == 0)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
2020-07-23 15:43:25 +00:00
|
|
|
mirrorStart = addr & ~0xFFFF;
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorSize = dsi->SCFG_BIOS & (1<<0) ? 0x8000 : 0x10000;
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case memregion_BIOS7DSi:
|
|
|
|
if (num == 1)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
2020-07-23 15:43:25 +00:00
|
|
|
mirrorStart = addr & ~0xFFFF;
|
2023-11-28 22:16:41 +00:00
|
|
|
mirrorSize = dsi->SCFG_BIOS & (1<<8) ? 0x8000 : 0x10000;
|
2020-07-23 15:43:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
assert(false && "For the time being this should only be used for code");
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
u32 ARMJIT_Memory::LocaliseAddress(int region, u32 num, u32 addr) const noexcept
|
2020-06-30 21:50:41 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
switch (region)
|
|
|
|
{
|
|
|
|
case memregion_ITCM:
|
|
|
|
return (addr & (ITCMPhysicalSize - 1)) | (memregion_ITCM << 27);
|
|
|
|
case memregion_MainRAM:
|
2023-11-28 22:16:41 +00:00
|
|
|
return (addr & NDS.MainRAMMask) | (memregion_MainRAM << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
case memregion_BIOS9:
|
|
|
|
return (addr & 0xFFF) | (memregion_BIOS9 << 27);
|
|
|
|
case memregion_BIOS7:
|
|
|
|
return (addr & 0x3FFF) | (memregion_BIOS7 << 27);
|
|
|
|
case memregion_SharedWRAM:
|
|
|
|
if (num == 0)
|
2023-11-28 22:16:41 +00:00
|
|
|
return ((addr & NDS.SWRAM_ARM9.Mask) + (NDS.SWRAM_ARM9.Mem - GetSharedWRAM())) | (memregion_SharedWRAM << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
else
|
2023-11-28 22:16:41 +00:00
|
|
|
return ((addr & NDS.SWRAM_ARM7.Mask) + (NDS.SWRAM_ARM7.Mem - GetSharedWRAM())) | (memregion_SharedWRAM << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
case memregion_WRAM7:
|
2023-11-28 22:16:41 +00:00
|
|
|
return (addr & (melonDS::ARM7WRAMSize - 1)) | (memregion_WRAM7 << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
case memregion_VRAM:
|
|
|
|
// TODO: take mapping properly into account
|
|
|
|
return (addr & 0xFFFFF) | (memregion_VRAM << 27);
|
|
|
|
case memregion_VWRAM:
|
|
|
|
// same here
|
|
|
|
return (addr & 0x3FFFF) | (memregion_VWRAM << 27);
|
|
|
|
case memregion_NewSharedWRAM_A:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_A[num][(addr >> 16) & dsi->NWRAMMask[num][0]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
2023-11-18 15:40:54 +00:00
|
|
|
return (ptr - GetNWRAM_A() + (addr & 0xFFFF)) | (memregion_NewSharedWRAM_A << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
else
|
|
|
|
return memregion_Other << 27; // zero filled memory
|
|
|
|
}
|
|
|
|
case memregion_NewSharedWRAM_B:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_B[num][(addr >> 15) & dsi->NWRAMMask[num][1]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
2023-11-18 15:40:54 +00:00
|
|
|
return (ptr - GetNWRAM_B() + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_B << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
else
|
|
|
|
return memregion_Other << 27;
|
|
|
|
}
|
|
|
|
case memregion_NewSharedWRAM_C:
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
auto* dsi = dynamic_cast<DSi*>(&NDS);
|
|
|
|
assert(dsi != nullptr);
|
|
|
|
u8* ptr = dsi->NWRAMMap_C[num][(addr >> 15) & dsi->NWRAMMask[num][2]];
|
2020-07-23 15:43:25 +00:00
|
|
|
if (ptr)
|
2023-11-18 15:40:54 +00:00
|
|
|
return (ptr - GetNWRAM_C() + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_C << 27);
|
2020-07-23 15:43:25 +00:00
|
|
|
else
|
|
|
|
return memregion_Other << 27;
|
|
|
|
}
|
|
|
|
case memregion_BIOS9DSi:
|
|
|
|
case memregion_BIOS7DSi:
|
|
|
|
return (addr & 0xFFFF) | (region << 27);
|
|
|
|
default:
|
|
|
|
assert(false && "This should only be needed for regions which can contain code");
|
|
|
|
return memregion_Other << 27;
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
int ARMJIT_Memory::ClassifyAddress9(u32 addr) const noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr < NDS.ARM9.ITCMSize)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
return memregion_ITCM;
|
|
|
|
}
|
2023-11-28 22:16:41 +00:00
|
|
|
else if ((addr & NDS.ARM9.DTCMMask) == NDS.ARM9.DTCMBase)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
return memregion_DTCM;
|
|
|
|
}
|
2022-03-06 20:21:50 +00:00
|
|
|
else
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
if (NDS.ConsoleType == 1)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
auto& dsi = static_cast<DSi&>(NDS);
|
|
|
|
if (addr >= 0xFFFF0000 && !(dsi.SCFG_BIOS & (1<<1)))
|
|
|
|
{
|
|
|
|
if ((addr >= 0xFFFF8000) && (dsi.SCFG_BIOS & (1<<0)))
|
|
|
|
return memregion_Other;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2023-12-05 14:20:57 +00:00
|
|
|
return memregion_BIOS9DSi;
|
|
|
|
}
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2023-12-05 14:20:57 +00:00
|
|
|
|
|
|
|
if ((addr & 0xFFFFF000) == 0xFFFF0000)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
return memregion_BIOS9;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (addr & 0xFF000000)
|
|
|
|
{
|
|
|
|
case 0x02000000:
|
|
|
|
return memregion_MainRAM;
|
|
|
|
case 0x03000000:
|
2023-11-28 22:16:41 +00:00
|
|
|
if (NDS.ConsoleType == 1)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
auto& dsi = static_cast<DSi&>(NDS);
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[0][0] && addr < dsi.NWRAMEnd[0][0])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_A;
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[0][1] && addr < dsi.NWRAMEnd[0][1])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_B;
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[0][2] && addr < dsi.NWRAMEnd[0][2])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_C;
|
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
if (NDS.SWRAM_ARM9.Mem)
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_SharedWRAM;
|
|
|
|
return memregion_Other;
|
|
|
|
case 0x04000000:
|
|
|
|
return memregion_IO9;
|
|
|
|
case 0x06000000:
|
|
|
|
return memregion_VRAM;
|
2022-04-10 12:54:40 +00:00
|
|
|
case 0x0C000000:
|
2023-11-28 22:16:41 +00:00
|
|
|
return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
|
2020-07-23 15:43:25 +00:00
|
|
|
default:
|
|
|
|
return memregion_Other;
|
|
|
|
}
|
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
int ARMJIT_Memory::ClassifyAddress7(u32 addr) const noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
if (NDS.ConsoleType == 1)
|
2020-06-30 21:50:41 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
auto& dsi = static_cast<DSi&>(NDS);
|
|
|
|
if (addr < 0x00010000 && !(dsi.SCFG_BIOS & (1<<9)))
|
|
|
|
{
|
|
|
|
if (addr >= 0x00008000 && dsi.SCFG_BIOS & (1<<8))
|
|
|
|
return memregion_Other;
|
2020-06-30 21:50:41 +00:00
|
|
|
|
2023-12-05 14:20:57 +00:00
|
|
|
return memregion_BIOS7DSi;
|
|
|
|
}
|
2020-06-30 21:50:41 +00:00
|
|
|
}
|
2023-12-05 14:20:57 +00:00
|
|
|
|
|
|
|
if (addr < 0x00004000)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
return memregion_BIOS7;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (addr & 0xFF800000)
|
|
|
|
{
|
|
|
|
case 0x02000000:
|
|
|
|
case 0x02800000:
|
|
|
|
return memregion_MainRAM;
|
|
|
|
case 0x03000000:
|
2023-11-28 22:16:41 +00:00
|
|
|
if (NDS.ConsoleType == 1)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-12-05 14:20:57 +00:00
|
|
|
auto& dsi = static_cast<DSi&>(NDS);
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[1][0] && addr < dsi.NWRAMEnd[1][0])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_A;
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[1][1] && addr < dsi.NWRAMEnd[1][1])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_B;
|
2023-11-28 22:16:41 +00:00
|
|
|
if (addr >= dsi.NWRAMStart[1][2] && addr < dsi.NWRAMEnd[1][2])
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_NewSharedWRAM_C;
|
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
if (NDS.SWRAM_ARM7.Mem)
|
2020-07-23 15:43:25 +00:00
|
|
|
return memregion_SharedWRAM;
|
|
|
|
return memregion_WRAM7;
|
|
|
|
case 0x03800000:
|
|
|
|
return memregion_WRAM7;
|
|
|
|
case 0x04000000:
|
|
|
|
return memregion_IO7;
|
|
|
|
case 0x04800000:
|
|
|
|
return memregion_Wifi;
|
|
|
|
case 0x06000000:
|
|
|
|
case 0x06800000:
|
|
|
|
return memregion_VWRAM;
|
2022-04-10 12:54:40 +00:00
|
|
|
case 0x0C000000:
|
|
|
|
case 0x0C800000:
|
2023-11-28 22:16:41 +00:00
|
|
|
return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
|
2020-11-09 19:43:31 +00:00
|
|
|
default:
|
|
|
|
return memregion_Other;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 16:00:12 +00:00
|
|
|
/*void WifiWrite32(u32 addr, u32 val)
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
Wifi::Write(addr, val & 0xFFFF);
|
|
|
|
Wifi::Write(addr + 2, val >> 16);
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 WifiRead32(u32 addr)
|
|
|
|
{
|
2020-08-14 21:38:47 +00:00
|
|
|
return (u32)Wifi::Read(addr) | ((u32)Wifi::Read(addr + 2) << 16);
|
2023-11-04 16:00:12 +00:00
|
|
|
}*/
|
2020-06-14 19:04:25 +00:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void VRAMWrite(u32 addr, T val)
|
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
switch (addr & 0x00E00000)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
case 0x00000000: NDS::Current->GPU.WriteVRAM_ABG<T>(addr, val); return;
|
|
|
|
case 0x00200000: NDS::Current->GPU.WriteVRAM_BBG<T>(addr, val); return;
|
|
|
|
case 0x00400000: NDS::Current->GPU.WriteVRAM_AOBJ<T>(addr, val); return;
|
|
|
|
case 0x00600000: NDS::Current->GPU.WriteVRAM_BOBJ<T>(addr, val); return;
|
|
|
|
default: NDS::Current->GPU.WriteVRAM_LCDC<T>(addr, val); return;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
template <typename T>
|
|
|
|
T VRAMRead(u32 addr)
|
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
switch (addr & 0x00E00000)
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
case 0x00000000: return NDS::Current->GPU.ReadVRAM_ABG<T>(addr);
|
|
|
|
case 0x00200000: return NDS::Current->GPU.ReadVRAM_BBG<T>(addr);
|
|
|
|
case 0x00400000: return NDS::Current->GPU.ReadVRAM_AOBJ<T>(addr);
|
|
|
|
case 0x00600000: return NDS::Current->GPU.ReadVRAM_BOBJ<T>(addr);
|
|
|
|
default: return NDS::Current->GPU.ReadVRAM_LCDC<T>(addr);
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 20:54:51 +00:00
|
|
|
static u8 GPU3D_Read8(u32 addr) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
return NDS::Current->GPU.GPU3D.Read8(addr);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static u16 GPU3D_Read16(u32 addr) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
return NDS::Current->GPU.GPU3D.Read16(addr);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static u32 GPU3D_Read32(u32 addr) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
return NDS::Current->GPU.GPU3D.Read32(addr);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void GPU3D_Write8(u32 addr, u8 val) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
NDS::Current->GPU.GPU3D.Write8(addr, val);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void GPU3D_Write16(u32 addr, u16 val) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
NDS::Current->GPU.GPU3D.Write16(addr, val);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void GPU3D_Write32(u32 addr, u32 val) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
NDS::Current->GPU.GPU3D.Write32(addr, val);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
static T GPU_ReadVRAM_ARM7(u32 addr) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
return NDS::Current->GPU.ReadVRAM_ARM7<T>(addr);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
static void GPU_WriteVRAM_ARM7(u32 addr, T val) noexcept
|
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
NDS::Current->GPU.WriteVRAM_ARM7<T>(addr, val);
|
2023-11-09 20:54:51 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 17:57:16 +00:00
|
|
|
u32 NDSCartSlot_ReadROMData()
|
|
|
|
{ // TODO: Add a NDS* parameter, when NDS* is eventually implemented
|
2023-11-28 22:16:41 +00:00
|
|
|
return NDS::Current->NDSCartSlot.ReadROMData();
|
|
|
|
}
|
|
|
|
|
|
|
|
static u8 NDS_ARM9IORead8(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM9IORead8(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u16 NDS_ARM9IORead16(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM9IORead16(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 NDS_ARM9IORead32(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM9IORead32(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM9IOWrite8(u32 addr, u8 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM9IOWrite8(addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM9IOWrite16(u32 addr, u16 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM9IOWrite16(addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM9IOWrite32(u32 addr, u32 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM9IOWrite32(addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u8 NDS_ARM7IORead8(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM7IORead8(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u16 NDS_ARM7IORead16(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM7IORead16(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 NDS_ARM7IORead32(u32 addr)
|
|
|
|
{
|
|
|
|
return NDS::Current->ARM7IORead32(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM7IOWrite8(u32 addr, u8 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM7IOWrite8(addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM7IOWrite16(u32 addr, u16 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM7IOWrite16(addr, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NDS_ARM7IOWrite32(u32 addr, u32 val)
|
|
|
|
{
|
|
|
|
NDS::Current->ARM7IOWrite32(addr, val);
|
2023-11-09 17:57:16 +00:00
|
|
|
}
|
|
|
|
|
2023-11-18 15:40:54 +00:00
|
|
|
void* ARMJIT_Memory::GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) const noexcept
|
2020-06-14 19:04:25 +00:00
|
|
|
{
|
2020-07-23 15:43:25 +00:00
|
|
|
if (cpu->Num == 0)
|
|
|
|
{
|
|
|
|
switch (addr & 0xFF000000)
|
|
|
|
{
|
|
|
|
case 0x04000000:
|
2023-11-28 22:16:41 +00:00
|
|
|
if (!store && size == 32 && addr == 0x04100010 && NDS.ExMemCnt[0] & (1<<11))
|
2023-11-09 17:57:16 +00:00
|
|
|
return (void*)NDSCartSlot_ReadROMData;
|
2020-07-23 15:43:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
unfortunately we can't map GPU2D this way
|
|
|
|
since it's hidden inside an object
|
|
|
|
|
|
|
|
though GPU3D registers are accessed much more intensive
|
|
|
|
*/
|
|
|
|
if (addr >= 0x04000320 && addr < 0x040006A4)
|
|
|
|
{
|
|
|
|
switch (size | store)
|
|
|
|
{
|
2023-11-09 20:54:51 +00:00
|
|
|
case 8: return (void*)GPU3D_Read8;
|
|
|
|
case 9: return (void*)GPU3D_Write8;
|
|
|
|
case 16: return (void*)GPU3D_Read16;
|
|
|
|
case 17: return (void*)GPU3D_Write16;
|
|
|
|
case 32: return (void*)GPU3D_Read32;
|
|
|
|
case 33: return (void*)GPU3D_Write32;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
switch (size | store)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
case 8: return (void*)NDS_ARM9IORead8;
|
|
|
|
case 9: return (void*)NDS_ARM9IOWrite8;
|
|
|
|
case 16: return (void*)NDS_ARM9IORead16;
|
|
|
|
case 17: return (void*)NDS_ARM9IOWrite16;
|
|
|
|
case 32: return (void*)NDS_ARM9IORead32;
|
|
|
|
case 33: return (void*)NDS_ARM9IOWrite32;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
2023-11-28 22:16:41 +00:00
|
|
|
// NDS::Current will delegate to the DSi versions of these methods
|
|
|
|
// if it's really a DSi
|
2020-07-23 15:43:25 +00:00
|
|
|
break;
|
|
|
|
case 0x06000000:
|
|
|
|
switch (size | store)
|
|
|
|
{
|
2022-03-06 20:21:50 +00:00
|
|
|
case 8: return (void*)VRAMRead<u8>;
|
2020-07-23 15:43:25 +00:00
|
|
|
case 9: return NULL;
|
|
|
|
case 16: return (void*)VRAMRead<u16>;
|
|
|
|
case 17: return (void*)VRAMWrite<u16>;
|
|
|
|
case 32: return (void*)VRAMRead<u32>;
|
|
|
|
case 33: return (void*)VRAMWrite<u32>;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (addr & 0xFF800000)
|
|
|
|
{
|
|
|
|
case 0x04000000:
|
2023-11-04 13:20:58 +00:00
|
|
|
/*if (addr >= 0x04000400 && addr < 0x04000520)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
|
|
|
switch (size | store)
|
|
|
|
{
|
2022-03-06 20:21:50 +00:00
|
|
|
case 8: return (void*)SPU::Read8;
|
|
|
|
case 9: return (void*)SPU::Write8;
|
2020-07-23 15:43:25 +00:00
|
|
|
case 16: return (void*)SPU::Read16;
|
|
|
|
case 17: return (void*)SPU::Write16;
|
|
|
|
case 32: return (void*)SPU::Read32;
|
|
|
|
case 33: return (void*)SPU::Write32;
|
|
|
|
}
|
2023-11-04 13:20:58 +00:00
|
|
|
}*/
|
2020-07-23 15:43:25 +00:00
|
|
|
|
2023-11-28 22:16:41 +00:00
|
|
|
switch (size | store)
|
2020-07-23 15:43:25 +00:00
|
|
|
{
|
2023-11-28 22:16:41 +00:00
|
|
|
case 8: return (void*)NDS_ARM7IORead8;
|
|
|
|
case 9: return (void*)NDS_ARM7IOWrite8;
|
|
|
|
case 16: return (void*)NDS_ARM7IORead16;
|
|
|
|
case 17: return (void*)NDS_ARM7IOWrite16;
|
|
|
|
case 32: return (void*)NDS_ARM7IORead32;
|
|
|
|
case 33: return (void*)NDS_ARM7IOWrite32;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
break;
|
2023-11-04 16:00:12 +00:00
|
|
|
// TODO: the wifi funcs also ought to check POWCNT
|
|
|
|
/*case 0x04800000:
|
2020-07-23 15:43:25 +00:00
|
|
|
if (addr < 0x04810000 && size >= 16)
|
|
|
|
{
|
|
|
|
switch (size | store)
|
|
|
|
{
|
|
|
|
case 16: return (void*)Wifi::Read;
|
|
|
|
case 17: return (void*)Wifi::Write;
|
|
|
|
case 32: return (void*)WifiRead32;
|
|
|
|
case 33: return (void*)WifiWrite32;
|
|
|
|
}
|
|
|
|
}
|
2023-11-04 16:00:12 +00:00
|
|
|
break;*/
|
2020-07-23 15:43:25 +00:00
|
|
|
case 0x06000000:
|
|
|
|
case 0x06800000:
|
|
|
|
switch (size | store)
|
|
|
|
{
|
2023-11-09 20:54:51 +00:00
|
|
|
case 8: return (void*)GPU_ReadVRAM_ARM7<u8>;
|
|
|
|
case 9: return (void*)GPU_WriteVRAM_ARM7<u8>;
|
|
|
|
case 16: return (void*)GPU_ReadVRAM_ARM7<u16>;
|
|
|
|
case 17: return (void*)GPU_WriteVRAM_ARM7<u16>;
|
|
|
|
case 32: return (void*)GPU_ReadVRAM_ARM7<u32>;
|
|
|
|
case 33: return (void*)GPU_WriteVRAM_ARM7<u32>;
|
2020-07-23 15:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
2020-06-14 19:04:25 +00:00
|
|
|
}
|
2023-11-25 17:32:09 +00:00
|
|
|
}
|