2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (C) 2003 Dolphin Project / 2012 PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-12-30 09:49:05 +00:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2012-11-01 15:19:01 +00:00
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
2013-09-23 19:46:45 +00:00
|
|
|
#pragma once
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2016-10-12 15:32:52 +00:00
|
|
|
#include "ppsspp_config.h"
|
|
|
|
|
2013-12-30 09:49:05 +00:00
|
|
|
#include <cstring>
|
2019-02-13 17:00:57 +00:00
|
|
|
#include <cstdint>
|
2014-07-24 13:20:09 +00:00
|
|
|
#ifndef offsetof
|
2014-06-06 04:17:47 +00:00
|
|
|
#include <stddef.h>
|
2014-05-28 17:29:54 +00:00
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-12-30 09:49:05 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2017-08-31 15:13:18 +00:00
|
|
|
#include "Common/Swap.h"
|
2014-03-15 09:45:39 +00:00
|
|
|
#include "Core/Opcode.h"
|
2013-06-21 05:19:47 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
// PPSSPP is very aggressive about trying to do memory accesses directly, for speed.
|
|
|
|
// This can be a problem when debugging though, as stray memory reads and writes will
|
|
|
|
// crash the whole emulator.
|
|
|
|
// If safe memory is enabled and JIT is disabled, all memory access will go through the proper
|
|
|
|
// memory access functions, and thus won't crash the emu when they go out of bounds.
|
|
|
|
#if defined(_DEBUG)
|
2012-11-23 11:42:35 +00:00
|
|
|
//#define SAFE_MEMORY
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
2013-02-17 05:23:56 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
// Global declarations
|
|
|
|
class PointerWrap;
|
|
|
|
|
|
|
|
typedef void (*writeFn8 )(const u8, const u32);
|
|
|
|
typedef void (*writeFn16)(const u16,const u32);
|
|
|
|
typedef void (*writeFn32)(const u32,const u32);
|
|
|
|
typedef void (*writeFn64)(const u64,const u32);
|
|
|
|
|
2014-03-03 16:16:53 +00:00
|
|
|
typedef void (*readFn8 )(u8&, const u32);
|
2012-11-01 15:19:01 +00:00
|
|
|
typedef void (*readFn16)(u16&, const u32);
|
|
|
|
typedef void (*readFn32)(u32&, const u32);
|
|
|
|
typedef void (*readFn64)(u64&, const u32);
|
|
|
|
|
2020-07-04 18:30:33 +00:00
|
|
|
namespace Memory {
|
2012-11-01 15:19:01 +00:00
|
|
|
// Base is a pointer to the base of the memory map. Yes, some MMU tricks
|
2013-12-30 09:49:05 +00:00
|
|
|
// are used to set up a full GC or Wii memory map in process memory. on
|
2012-11-01 15:19:01 +00:00
|
|
|
// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that
|
|
|
|
// some things are mirrored too many times, but eh... it works.
|
|
|
|
|
|
|
|
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
|
|
|
// so be sure to load it into a 64-bit register.
|
|
|
|
extern u8 *base;
|
|
|
|
|
2014-05-06 07:41:49 +00:00
|
|
|
// This replaces RAM_NORMAL_SIZE at runtime.
|
2013-07-17 21:49:57 +00:00
|
|
|
extern u32 g_MemorySize;
|
2013-11-28 20:34:11 +00:00
|
|
|
extern u32 g_PSPModel;
|
2013-06-21 17:34:57 +00:00
|
|
|
|
2017-02-28 00:47:13 +00:00
|
|
|
// UWP has such limited memory management that we need to mask
|
2018-01-31 13:22:38 +00:00
|
|
|
// even in 64-bit mode. Also, when using the sanitizer, we need to mask as well.
|
2023-08-12 19:38:35 +00:00
|
|
|
#if PPSSPP_ARCH(32BIT) || PPSSPP_PLATFORM(UWP) || USE_ASAN || PPSSPP_PLATFORM(IOS) || defined(__EMSCRIPTEN__)
|
2017-02-28 00:47:13 +00:00
|
|
|
#define MASKED_PSP_MEMORY
|
|
|
|
#endif
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
enum
|
|
|
|
{
|
2013-09-09 07:19:26 +00:00
|
|
|
// This may be adjusted by remaster games.
|
|
|
|
RAM_NORMAL_SIZE = 0x02000000,
|
2013-11-28 19:37:10 +00:00
|
|
|
// Used if the PSP model is PSP-2000 (Slim).
|
|
|
|
RAM_DOUBLE_SIZE = RAM_NORMAL_SIZE * 2,
|
|
|
|
|
2014-05-06 07:41:49 +00:00
|
|
|
VRAM_SIZE = 0x00200000,
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2020-06-03 09:55:14 +00:00
|
|
|
SCRATCHPAD_SIZE = 0x00004000,
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-12-30 09:49:05 +00:00
|
|
|
// This wraparound should work for PSP too.
|
2014-03-03 16:16:53 +00:00
|
|
|
MEMVIEW32_MASK = 0x3FFFFFFF,
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2014-05-28 17:29:54 +00:00
|
|
|
enum {
|
|
|
|
MV_MIRROR_PREVIOUS = 1,
|
|
|
|
MV_IS_PRIMARY_RAM = 0x100,
|
|
|
|
MV_IS_EXTRA1_RAM = 0x200,
|
|
|
|
MV_IS_EXTRA2_RAM = 0x400,
|
2017-01-25 17:35:09 +00:00
|
|
|
MV_KERNEL = 0x800 // Can be skipped on platforms where memory is tight.
|
2014-05-28 17:29:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct MemoryView
|
|
|
|
{
|
|
|
|
u8 **out_ptr;
|
|
|
|
u32 virtual_address;
|
|
|
|
u32 size;
|
|
|
|
u32 flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Uses a memory arena to set up an emulator-friendly memory map
|
2017-01-25 14:43:24 +00:00
|
|
|
bool MemoryMap_Setup(u32 flags);
|
2014-05-28 17:29:54 +00:00
|
|
|
void MemoryMap_Shutdown(u32 flags);
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
// Init and Shutdown
|
2020-07-19 18:32:15 +00:00
|
|
|
bool Init();
|
2012-11-01 15:19:01 +00:00
|
|
|
void Shutdown();
|
|
|
|
void DoState(PointerWrap &p);
|
|
|
|
void Clear();
|
2016-05-20 04:17:17 +00:00
|
|
|
// False when shutdown has already been called.
|
|
|
|
bool IsActive();
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2017-02-28 00:47:13 +00:00
|
|
|
class MemoryInitedLock {
|
2014-07-20 06:25:32 +00:00
|
|
|
public:
|
|
|
|
MemoryInitedLock();
|
|
|
|
~MemoryInitedLock();
|
|
|
|
};
|
|
|
|
|
|
|
|
// This doesn't lock memory access or anything, it just makes sure memory isn't freed.
|
|
|
|
// Use it when accessing PSP memory from external threads.
|
|
|
|
MemoryInitedLock Lock();
|
|
|
|
|
2013-12-18 15:27:23 +00:00
|
|
|
// used by JIT to read instructions. Does not resolve replacements.
|
2013-08-24 21:43:49 +00:00
|
|
|
Opcode Read_Opcode_JIT(const u32 _Address);
|
2013-12-18 15:27:23 +00:00
|
|
|
// used by JIT. Reads in the "Locked cache" mode
|
2014-12-25 02:42:41 +00:00
|
|
|
void Write_Opcode_JIT(const u32 _Address, const Opcode& _Value);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-12-18 15:27:23 +00:00
|
|
|
// Should be used by analyzers, disassemblers etc. Does resolve replacements.
|
2013-12-20 12:51:26 +00:00
|
|
|
Opcode Read_Instruction(const u32 _Address, bool resolveReplacements = false);
|
2014-03-02 05:15:17 +00:00
|
|
|
Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = false);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2014-05-27 15:52:38 +00:00
|
|
|
u8 Read_U8(const u32 _Address);
|
2012-11-01 15:19:01 +00:00
|
|
|
u16 Read_U16(const u32 _Address);
|
|
|
|
u32 Read_U32(const u32 _Address);
|
|
|
|
u64 Read_U64(const u32 _Address);
|
|
|
|
|
2022-07-20 10:40:22 +00:00
|
|
|
inline u8* GetPointerWriteUnchecked(const u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-08-10 23:46:21 +00:00
|
|
|
return (u8 *)(base + (address & MEMVIEW32_MASK));
|
|
|
|
#else
|
|
|
|
return (u8 *)(base + address);
|
|
|
|
#endif
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2022-07-20 10:40:22 +00:00
|
|
|
inline const u8* GetPointerUnchecked(const u32 address) {
|
|
|
|
#ifdef MASKED_PSP_MEMORY
|
|
|
|
return (const u8 *)(base + (address & MEMVIEW32_MASK));
|
|
|
|
#else
|
|
|
|
return (const u8 *)(base + address);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-23 11:42:35 +00:00
|
|
|
inline u32 ReadUnchecked_U32(const u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-12-30 09:49:05 +00:00
|
|
|
return *(u32_le *)(base + (address & MEMVIEW32_MASK));
|
2012-11-01 15:19:01 +00:00
|
|
|
#else
|
2013-12-30 09:49:05 +00:00
|
|
|
return *(u32_le *)(base + address);
|
2012-11-23 11:42:35 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-05-08 00:03:11 +00:00
|
|
|
inline float ReadUnchecked_Float(const u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2021-02-19 06:25:24 +00:00
|
|
|
return *(float_le *)(base + (address & MEMVIEW32_MASK));
|
2016-05-08 00:03:11 +00:00
|
|
|
#else
|
2021-02-19 06:25:24 +00:00
|
|
|
return *(float_le *)(base + address);
|
2016-05-08 00:03:11 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-23 11:42:35 +00:00
|
|
|
inline u16 ReadUnchecked_U16(const u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-08-17 06:48:08 +00:00
|
|
|
return *(u16_le *)(base + (address & MEMVIEW32_MASK));
|
2012-11-01 15:19:01 +00:00
|
|
|
#else
|
2013-08-17 06:48:08 +00:00
|
|
|
return *(u16_le *)(base + address);
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
2012-11-23 11:42:35 +00:00
|
|
|
|
|
|
|
inline u8 ReadUnchecked_U8(const u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
|
|
|
return (*(u8 *)(base + (address & MEMVIEW32_MASK)));
|
2012-11-23 11:42:35 +00:00
|
|
|
#else
|
|
|
|
return (*(u8 *)(base + address));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void WriteUnchecked_U32(u32 data, u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-08-17 06:48:08 +00:00
|
|
|
*(u32_le *)(base + (address & MEMVIEW32_MASK)) = data;
|
2012-11-23 11:42:35 +00:00
|
|
|
#else
|
2013-08-17 06:48:08 +00:00
|
|
|
*(u32_le *)(base + address) = data;
|
2012-11-23 11:42:35 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-05-08 00:03:11 +00:00
|
|
|
inline void WriteUnchecked_Float(float data, u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2021-02-19 06:25:24 +00:00
|
|
|
*(float_le *)(base + (address & MEMVIEW32_MASK)) = data;
|
2016-05-08 00:03:11 +00:00
|
|
|
#else
|
2021-02-19 06:25:24 +00:00
|
|
|
*(float_le *)(base + address) = data;
|
2016-05-08 00:03:11 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-23 11:42:35 +00:00
|
|
|
inline void WriteUnchecked_U16(u16 data, u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-08-17 06:48:08 +00:00
|
|
|
*(u16_le *)(base + (address & MEMVIEW32_MASK)) = data;
|
2012-11-23 11:42:35 +00:00
|
|
|
#else
|
2013-08-17 06:48:08 +00:00
|
|
|
*(u16_le *)(base + address) = data;
|
2012-11-23 11:42:35 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void WriteUnchecked_U8(u8 data, u32 address) {
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2012-11-23 11:42:35 +00:00
|
|
|
(*(u8 *)(base + (address & MEMVIEW32_MASK))) = data;
|
|
|
|
#else
|
|
|
|
(*(u8 *)(base + address)) = data;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
inline float Read_Float(u32 address)
|
|
|
|
{
|
2013-12-30 09:49:05 +00:00
|
|
|
u32 ifloat = Read_U32(address);
|
|
|
|
float f;
|
|
|
|
memcpy(&f, &ifloat, sizeof(float));
|
|
|
|
return f;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// used by JIT. Return zero-extended 32bit values
|
|
|
|
u32 Read_U8_ZX(const u32 address);
|
|
|
|
u32 Read_U16_ZX(const u32 address);
|
|
|
|
|
|
|
|
void Write_U8(const u8 data, const u32 address);
|
|
|
|
void Write_U16(const u16 data, const u32 address);
|
|
|
|
void Write_U32(const u32 data, const u32 address);
|
|
|
|
void Write_U64(const u64 data, const u32 address);
|
|
|
|
|
|
|
|
inline void Write_Float(float f, u32 address)
|
|
|
|
{
|
2013-12-30 09:49:05 +00:00
|
|
|
u32 u;
|
|
|
|
memcpy(&u, &f, sizeof(float));
|
|
|
|
Write_U32(u, address);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2022-07-20 10:40:22 +00:00
|
|
|
u8* GetPointerWrite(const u32 address);
|
|
|
|
const u8* GetPointer(const u32 address);
|
2023-01-01 18:25:40 +00:00
|
|
|
|
|
|
|
u8 *GetPointerWriteRange(const u32 address, const u32 size);
|
|
|
|
const u8 *GetPointerRange(const u32 address, const u32 size);
|
|
|
|
|
2013-09-21 16:52:30 +00:00
|
|
|
bool IsRAMAddress(const u32 address);
|
2020-08-31 22:05:37 +00:00
|
|
|
inline bool IsVRAMAddress(const u32 address) {
|
|
|
|
return ((address & 0x3F800000) == 0x04000000);
|
|
|
|
}
|
|
|
|
inline bool IsDepthTexVRAMAddress(const u32 address) {
|
|
|
|
return ((address & 0x3FE00000) == 0x04200000) || ((address & 0x3FE00000) == 0x04600000);
|
|
|
|
}
|
2020-10-13 22:08:10 +00:00
|
|
|
|
|
|
|
// 0x08000000 -> 0x08800000
|
2020-09-22 19:13:30 +00:00
|
|
|
inline bool IsKernelAddress(const u32 address) {
|
|
|
|
return ((address & 0x3F800000) == 0x08000000);
|
|
|
|
}
|
|
|
|
|
2020-10-13 22:08:10 +00:00
|
|
|
// 0x08000000 -> 0x08400000
|
|
|
|
inline bool IsKernelAndNotVolatileAddress(const u32 address) {
|
|
|
|
return ((address & 0x3FC00000) == 0x08000000);
|
|
|
|
}
|
|
|
|
|
2014-07-05 23:25:16 +00:00
|
|
|
bool IsScratchpadAddress(const u32 address);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2020-07-04 18:30:33 +00:00
|
|
|
inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) {
|
2015-04-06 01:03:50 +00:00
|
|
|
memcpy(to_data, GetPointerUnchecked(from_address), len);
|
2013-08-10 23:46:21 +00:00
|
|
|
}
|
|
|
|
|
2020-07-04 18:30:33 +00:00
|
|
|
inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len) {
|
2022-07-20 10:40:22 +00:00
|
|
|
memcpy(GetPointerWriteUnchecked(to_address), from_data, len);
|
2013-08-10 23:46:21 +00:00
|
|
|
}
|
|
|
|
|
2020-07-04 18:30:33 +00:00
|
|
|
inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) {
|
2023-01-01 19:48:03 +00:00
|
|
|
MemcpyUnchecked(GetPointerWriteUnchecked(to_address), from_address, len);
|
2013-08-10 23:46:21 +00:00
|
|
|
}
|
|
|
|
|
2013-11-11 23:18:49 +00:00
|
|
|
inline bool IsValidAddress(const u32 address) {
|
|
|
|
if ((address & 0x3E000000) == 0x08000000) {
|
|
|
|
return true;
|
2015-04-13 05:37:55 +00:00
|
|
|
} else if ((address & 0x3F800000) == 0x04000000) {
|
|
|
|
return true;
|
2021-04-22 02:32:22 +00:00
|
|
|
} else if ((address & 0xBFFFC000) == 0x00010000) {
|
|
|
|
return true;
|
2015-04-13 05:37:55 +00:00
|
|
|
} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-10 21:21:51 +00:00
|
|
|
inline bool IsValid4AlignedAddress(const u32 address) {
|
|
|
|
if ((address & 0x3E000003) == 0x08000000) {
|
|
|
|
return true;
|
|
|
|
} else if ((address & 0x3F800003) == 0x04000000) {
|
|
|
|
return true;
|
|
|
|
} else if ((address & 0xBFFFC003) == 0x00010000) {
|
|
|
|
return true;
|
|
|
|
} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
|
|
|
|
return (address & 3) == 0;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-05-03 11:42:50 +00:00
|
|
|
inline u32 MaxSizeAtAddress(const u32 address){
|
2015-04-13 05:37:55 +00:00
|
|
|
if ((address & 0x3E000000) == 0x08000000) {
|
2024-05-03 11:42:50 +00:00
|
|
|
return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);
|
2019-09-28 15:40:41 +00:00
|
|
|
} else if ((address & 0x3F800000) == 0x04000000) {
|
2024-05-03 11:42:50 +00:00
|
|
|
return 0x04800000 - (address & 0x3FFFFFFF);
|
2021-04-22 02:32:22 +00:00
|
|
|
} else if ((address & 0xBFFFC000) == 0x00010000) {
|
2024-05-03 11:42:50 +00:00
|
|
|
return 0x00014000 - (address & 0x3FFFFFFF);
|
2019-09-28 15:40:41 +00:00
|
|
|
} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
|
2024-05-03 11:42:50 +00:00
|
|
|
return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);
|
2015-04-13 05:37:55 +00:00
|
|
|
} else {
|
2024-05-03 11:42:50 +00:00
|
|
|
return 0;
|
2013-11-11 23:18:49 +00:00
|
|
|
}
|
2024-05-03 11:42:50 +00:00
|
|
|
}
|
2015-04-13 05:37:55 +00:00
|
|
|
|
2024-05-05 10:23:43 +00:00
|
|
|
inline const char *GetCharPointerUnchecked(const u32 address) {
|
|
|
|
return (const char *)GetPointerUnchecked(address);
|
|
|
|
}
|
|
|
|
|
2024-05-05 10:17:29 +00:00
|
|
|
// NOTE: Unlike the similar IsValidRange/IsValidAddress functions, this one is linear cost vs the size of the string,
|
|
|
|
// for hopefully-obvious reasons.
|
2024-05-03 11:42:50 +00:00
|
|
|
inline bool IsValidNullTerminatedString(const u32 address) {
|
|
|
|
u32 max_size = MaxSizeAtAddress(address);
|
|
|
|
if (max_size == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *c = GetCharPointerUnchecked(address);
|
2024-05-05 10:17:29 +00:00
|
|
|
if (memchr(c, '\0', max_size)) {
|
|
|
|
return true;
|
2024-05-03 11:42:50 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u32 ValidSize(const u32 address, const u32 requested_size) {
|
|
|
|
u32 max_size = MaxSizeAtAddress(address);
|
2015-04-13 05:37:55 +00:00
|
|
|
if (requested_size > max_size) {
|
|
|
|
return max_size;
|
|
|
|
}
|
|
|
|
return requested_size;
|
|
|
|
}
|
|
|
|
|
2024-05-10 11:50:49 +00:00
|
|
|
// NOTE: If size == 0, any address will be accepted. This may not be ideal for all cases.
|
2015-04-13 05:37:55 +00:00
|
|
|
inline bool IsValidRange(const u32 address, const u32 size) {
|
2023-04-12 03:58:59 +00:00
|
|
|
return ValidSize(address, size) == size;
|
2013-11-11 23:18:49 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 10:08:41 +00:00
|
|
|
// Used for auto-converted char * parameters, which can sometimes legitimately be null -
|
2024-05-05 10:23:43 +00:00
|
|
|
// so we don't want to get caught in GetPointer's crash reporting
|
|
|
|
// TODO: This should use IsValidNullTerminatedString, but may be expensive since this is used so much - needs evaluation.
|
2024-05-05 10:08:41 +00:00
|
|
|
inline const char *GetCharPointer(const u32 address) {
|
2024-05-05 10:23:43 +00:00
|
|
|
if (address && IsValidAddress(address)) {
|
2024-05-05 10:08:41 +00:00
|
|
|
return GetCharPointerUnchecked(address);
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-04 18:30:33 +00:00
|
|
|
} // namespace Memory
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2022-09-03 14:48:52 +00:00
|
|
|
// Avoiding a global include for NotifyMemInfo.
|
|
|
|
void PSPPointerNotifyRW(int rw, uint32_t ptr, uint32_t bytes, const char *tag, size_t tagLen);
|
|
|
|
|
2013-05-31 06:32:13 +00:00
|
|
|
template <typename T>
|
|
|
|
struct PSPPointer
|
|
|
|
{
|
2013-07-25 06:23:35 +00:00
|
|
|
u32_le ptr;
|
2013-05-31 06:32:13 +00:00
|
|
|
|
2013-06-02 21:26:12 +00:00
|
|
|
inline T &operator*() const
|
2013-05-31 06:32:13 +00:00
|
|
|
{
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-09-23 19:46:45 +00:00
|
|
|
return *(T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
|
|
|
|
#else
|
2013-09-23 19:51:34 +00:00
|
|
|
return *(T *)(Memory::base + ptr);
|
2013-09-23 19:46:45 +00:00
|
|
|
#endif
|
2013-05-31 06:32:13 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 21:26:12 +00:00
|
|
|
inline T &operator[](int i) const
|
2013-05-31 06:32:13 +00:00
|
|
|
{
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-09-23 19:46:45 +00:00
|
|
|
return *((T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK)) + i);
|
|
|
|
#else
|
2013-05-31 06:32:13 +00:00
|
|
|
return *((T *)(Memory::base + ptr) + i);
|
2013-09-23 19:46:45 +00:00
|
|
|
#endif
|
2013-05-31 06:32:13 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 21:26:12 +00:00
|
|
|
inline T *operator->() const
|
|
|
|
{
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-09-23 19:46:45 +00:00
|
|
|
return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
|
|
|
|
#else
|
2013-06-02 21:26:12 +00:00
|
|
|
return (T *)(Memory::base + ptr);
|
2013-09-23 19:46:45 +00:00
|
|
|
#endif
|
2013-06-02 21:26:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> operator+(int i) const
|
|
|
|
{
|
|
|
|
PSPPointer other;
|
|
|
|
other.ptr = ptr + i * sizeof(T);
|
|
|
|
return other;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> &operator=(u32 p)
|
|
|
|
{
|
|
|
|
ptr = p;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> &operator+=(int i)
|
|
|
|
{
|
|
|
|
ptr = ptr + i * sizeof(T);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> operator-(int i) const
|
|
|
|
{
|
|
|
|
PSPPointer other;
|
|
|
|
other.ptr = ptr - i * sizeof(T);
|
|
|
|
return other;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> &operator-=(int i)
|
|
|
|
{
|
|
|
|
ptr = ptr - i * sizeof(T);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> &operator++()
|
|
|
|
{
|
|
|
|
ptr += sizeof(T);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> operator++(int i)
|
|
|
|
{
|
|
|
|
PSPPointer<T> other;
|
|
|
|
other.ptr = ptr;
|
|
|
|
ptr += sizeof(T);
|
|
|
|
return other;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> &operator--()
|
|
|
|
{
|
|
|
|
ptr -= sizeof(T);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PSPPointer<T> operator--(int i)
|
|
|
|
{
|
|
|
|
PSPPointer<T> other;
|
|
|
|
other.ptr = ptr;
|
|
|
|
ptr -= sizeof(T);
|
|
|
|
return other;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline operator T*()
|
2013-05-31 06:32:13 +00:00
|
|
|
{
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2013-09-23 20:06:39 +00:00
|
|
|
return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
|
|
|
|
#else
|
2013-05-31 06:32:13 +00:00
|
|
|
return (T *)(Memory::base + ptr);
|
2013-09-23 20:06:39 +00:00
|
|
|
#endif
|
2013-05-31 06:32:13 +00:00
|
|
|
}
|
|
|
|
|
2014-04-20 07:01:16 +00:00
|
|
|
inline operator const T*() const
|
|
|
|
{
|
2017-02-28 00:47:13 +00:00
|
|
|
#ifdef MASKED_PSP_MEMORY
|
2014-04-20 07:01:16 +00:00
|
|
|
return (const T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
|
|
|
|
#else
|
|
|
|
return (const T *)(Memory::base + ptr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-09-03 17:37:58 +00:00
|
|
|
bool IsValid() const {
|
2022-09-03 14:48:52 +00:00
|
|
|
return Memory::IsValidRange(ptr, (u32)sizeof(T));
|
|
|
|
}
|
|
|
|
|
2022-09-03 17:37:58 +00:00
|
|
|
T *PtrOrNull() {
|
|
|
|
if (IsValid())
|
|
|
|
return (T *)*this;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
const T *PtrOrNull() const {
|
|
|
|
if (IsValid())
|
|
|
|
return (const T *)*this;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-09-03 14:48:52 +00:00
|
|
|
template <size_t tagLen>
|
|
|
|
void NotifyWrite(const char(&tag)[tagLen]) const {
|
|
|
|
PSPPointerNotifyRW(1, (uint32_t)ptr, (uint32_t)sizeof(T), tag, tagLen - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <size_t tagLen>
|
|
|
|
void NotifyRead(const char(&tag)[tagLen]) const {
|
|
|
|
PSPPointerNotifyRW(2, (uint32_t)ptr, (uint32_t)sizeof(T), tag, tagLen - 1);
|
2013-05-31 06:32:13 +00:00
|
|
|
}
|
2013-12-17 07:47:34 +00:00
|
|
|
|
2022-09-03 22:41:52 +00:00
|
|
|
size_t ElementSize() const
|
|
|
|
{
|
|
|
|
return sizeof(T);
|
|
|
|
}
|
|
|
|
|
2013-12-17 07:47:34 +00:00
|
|
|
static PSPPointer<T> Create(u32 ptr) {
|
|
|
|
PSPPointer<T> p;
|
|
|
|
p = ptr;
|
|
|
|
return p;
|
|
|
|
}
|
2013-05-31 06:32:13 +00:00
|
|
|
};
|
|
|
|
|
2021-04-05 04:27:30 +00:00
|
|
|
constexpr u32 PSP_GetScratchpadMemoryBase() { return 0x00010000;}
|
|
|
|
constexpr u32 PSP_GetScratchpadMemoryEnd() { return 0x00014000;}
|
2013-06-22 08:05:28 +00:00
|
|
|
|
2021-04-05 04:27:30 +00:00
|
|
|
constexpr u32 PSP_GetKernelMemoryBase() { return 0x08000000;}
|
2014-03-03 16:16:53 +00:00
|
|
|
inline u32 PSP_GetUserMemoryEnd() { return PSP_GetKernelMemoryBase() + Memory::g_MemorySize;}
|
2021-04-05 04:27:30 +00:00
|
|
|
constexpr u32 PSP_GetKernelMemoryEnd() { return 0x08400000;}
|
2021-01-18 19:07:21 +00:00
|
|
|
|
2013-06-22 08:05:28 +00:00
|
|
|
// "Volatile" RAM is between 0x08400000 and 0x08800000, can be requested by the
|
|
|
|
// game through sceKernelVolatileMemTryLock.
|
2021-04-05 04:27:30 +00:00
|
|
|
constexpr u32 PSP_GetVolatileMemoryStart() { return 0x08400000; }
|
|
|
|
constexpr u32 PSP_GetVolatileMemoryEnd() { return 0x08800000; }
|
2013-06-22 08:05:28 +00:00
|
|
|
|
2021-04-05 04:27:30 +00:00
|
|
|
constexpr u32 PSP_GetUserMemoryBase() { return 0x08800000; }
|
|
|
|
constexpr u32 PSP_GetDefaultLoadAddress() { return 0; }
|
|
|
|
constexpr u32 PSP_GetVidMemBase() { return 0x04000000; }
|
|
|
|
constexpr u32 PSP_GetVidMemEnd() { return 0x04800000; }
|
2013-06-21 17:34:57 +00:00
|
|
|
|
2013-06-02 21:26:12 +00:00
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator==(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr == rhs.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator!=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr != rhs.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator<(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr < rhs.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator>(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr > rhs.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator<=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr <= rhs.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-07-04 18:30:33 +00:00
|
|
|
inline bool operator>=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
|
2013-06-02 21:26:12 +00:00
|
|
|
return lhs.ptr >= rhs.ptr;
|
|
|
|
}
|