Initial fastmem support

* PCSX2 fastmem depression

* Move away from PCSX2 fastmem

* Add enum_flag_ops.hpp

* Finally building on Windows

* Almost got a PoC

* Fix arm64 builds

* This somehow works

* This also works...

* Properly fix fastmem

* Add free region manager

* Update boost

* Add ScopeExit

* Comment out asserts on Linux/Mac/Android

* Comment out ASSERT_MSG asserts too

* Fix derp

* Attempt to fix Android

* Disable fastmem on Android

* Fix Android again maybe pt 2

* android pls

* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

* Update host_memory.cpp

* Properly reset memory arena on reset

* Proper ashmem code for Android

* more

* Add temporary Android buildjet script for faster prototype builds

* Fix fastmem (again)

* Clean up shared memory
This commit is contained in:
wheremyfoodat 2024-12-03 22:51:46 +02:00 committed by GitHub
parent 28461a1d44
commit c088911168
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 2139 additions and 13 deletions

View file

@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
namespace Common {
/**
* Provides a platform-independent interface for loading a dynamic library and retrieving symbols.
* The interface maintains an internal reference count to allow one handle to be shared between
* multiple users.
*/
class DynamicLibrary final {
public:
/// Default constructor, does not load a library.
explicit DynamicLibrary();
/// Automatically loads the specified library. Call IsOpen() to check validity before use.
explicit DynamicLibrary(const char* filename);
/// Initializes the dynamic library with an already opened handle.
explicit DynamicLibrary(void* handle_);
/// Moves the library.
DynamicLibrary(DynamicLibrary&&) noexcept;
DynamicLibrary& operator=(DynamicLibrary&&) noexcept;
/// Delete copies, we can't copy a dynamic library.
DynamicLibrary(const DynamicLibrary&) = delete;
DynamicLibrary& operator=(const DynamicLibrary&) = delete;
/// Closes the library.
~DynamicLibrary();
/// Returns the specified library name with the platform-specific suffix added.
[[nodiscard]] static std::string getUnprefixedFilename(const char* filename);
/// Returns the specified library name in platform-specific format.
/// Major/minor versions will not be included if set to -1.
/// If libname already contains the "lib" prefix, it will not be added again.
/// Windows: LIBNAME-MAJOR-MINOR.dll
/// Linux: libLIBNAME.so.MAJOR.MINOR
/// Mac: libLIBNAME.MAJOR.MINOR.dylib
[[nodiscard]] static std::string getVersionedFilename(const char* libname, int major = -1, int minor = -1);
/// Returns true if a module is loaded, otherwise false.
[[nodiscard]] bool isOpen() const { return handle != nullptr; }
/// Loads (or replaces) the handle with the specified library file name.
/// Returns true if the library was loaded and can be used.
[[nodiscard]] bool open(const char* filename);
/// Unloads the library, any function pointers from this library are no longer valid.
void close();
/// Returns the address of the specified symbol (function or variable) as an untyped pointer.
/// If the specified symbol does not exist in this library, nullptr is returned.
[[nodiscard]] void* getSymbolAddress(const char* name) const;
/// Obtains the address of the specified symbol, automatically casting to the correct type.
/// Returns true if the symbol was found and assigned, otherwise false.
template <typename T>
[[nodiscard]] bool getSymbol(const char* name, T* ptr) const {
*ptr = reinterpret_cast<T>(getSymbolAddress(name));
return *ptr != nullptr;
}
private:
/// Platform-dependent data type representing a dynamic library handle.
void* handle = nullptr;
};
} // namespace Common

View file

@ -40,9 +40,9 @@ enum class ROMType {
class Emulator {
EmulatorConfig config;
Memory memory;
CPU cpu;
GPU gpu;
Memory memory;
Kernel kernel;
std::unique_ptr<Audio::DSPCore> dsp;
Scheduler scheduler;
@ -55,7 +55,7 @@ class Emulator {
static constexpr u32 width = 400;
static constexpr u32 height = 240 * 2; // * 2 because 2 screens
ROMType romType = ROMType::None;
bool running = false; // Is the emulator running a game?
bool running = false; // Is the emulator running a game?
private:
#ifdef PANDA3DS_ENABLE_HTTP_SERVER

60
include/enum_flag_ops.hpp Normal file
View file

@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <type_traits>
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator<<(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) << static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator>>(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) >> static_cast<T>(b)); \
} \
constexpr type& operator|=(type& a, type b) noexcept { \
a = a | b; \
return a; \
} \
constexpr type& operator&=(type& a, type b) noexcept { \
a = a & b; \
return a; \
} \
constexpr type& operator^=(type& a, type b) noexcept { \
a = a ^ b; \
return a; \
} \
constexpr type& operator<<=(type& a, type b) noexcept { \
a = a << b; \
return a; \
} \
constexpr type& operator>>=(type& a, type b) noexcept { \
a = a >> b; \
return a; \
} \
[[nodiscard]] constexpr type operator~(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(~static_cast<T>(key)); \
} \
[[nodiscard]] constexpr bool True(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<T>(key) != 0; \
} \
[[nodiscard]] constexpr bool False(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<T>(key) == 0; \
}

View file

@ -3,6 +3,7 @@
#include <bitset>
#include <filesystem>
#include <fstream>
#include <memory>
#include <optional>
#include <vector>
@ -10,8 +11,9 @@
#include "crypto/aes_engine.hpp"
#include "handles.hpp"
#include "helpers.hpp"
#include "loader/ncsd.hpp"
#include "host_memory/host_memory.h"
#include "loader/3dsx.hpp"
#include "loader/ncsd.hpp"
#include "services/region_codes.hpp"
namespace PhysicalAddrs {
@ -108,7 +110,7 @@ class Memory {
u8* dspRam; // Provided to us by Audio
u8* vram; // Provided to the memory class by the GPU class
u64& cpuTicks; // Reference to the CPU tick counter
const u64* cpuTicks = nullptr; // Pointer to the CPU tick counter, provided to us by the CPU class
using SharedMemoryBlock = KernelMemoryTypes::SharedMemoryBlock;
// Our dynarmic core uses page tables for reads and writes with 4096 byte pages
@ -141,6 +143,36 @@ public:
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
private:
// We also use MMU-accelerated fastmem for fast memory emulation
// This means that we've got a 4GB memory arena which is organized the same way as the emulated 3DS' memory map
// And we can access this directly instead of calling the memory read/write functions, which would be slower
// Regions that are not mapped or can't be accelerated this way will segfault, and the caller (eg dynarmic), will
// handle this segfault and call the Slower memory read/write functions
bool useFastmem = false;
static constexpr size_t FASTMEM_FCRAM_OFFSET = 0; // Offset of FCRAM in the fastmem arena
static constexpr size_t FASTMEM_DSP_RAM_OFFSET = FASTMEM_FCRAM_OFFSET + FCRAM_SIZE; // Offset of DSP RAM
static constexpr size_t FASTMEM_BACKING_SIZE = FCRAM_SIZE + DSP_RAM_SIZE;
// Total size of the virtual address space we will occupy (4GB)
static constexpr size_t FASTMEM_VIRTUAL_SIZE = 4_GB;
Common::HostMemory* arena;
void addFastmemView(u32 guestVaddr, size_t arenaOffset, size_t size, bool w, bool x = false) {
if (useFastmem) {
Common::MemoryPermission perms = Common::MemoryPermission::Read;
if (w) {
perms |= Common::MemoryPermission::Write;
}
if (x) {
//perms |= Common::MemoryPermission::Execute;
}
arena->Map(guestVaddr, arenaOffset, size, perms, false);
}
}
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
std::optional<u32> findPaddr(u32 size);
u64 timeSince3DSEpoch();
@ -172,7 +204,7 @@ private:
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
Memory(u64& cpuTicks, const EmulatorConfig& config);
Memory(const EmulatorConfig& config);
void reset();
void* getReadPointer(u32 address);
void* getWritePointer(u32 address);
@ -295,8 +327,12 @@ private:
void setVRAM(u8* pointer) { vram = pointer; }
void setDSPMem(u8* pointer) { dspRam = pointer; }
void setCPUTicks(const u64& ticks) { cpuTicks = &ticks; }
bool allocateMainThreadStack(u32 size);
Regions getConsoleRegion();
void copySharedFont(u8* ptr, u32 vaddr);
bool isFastmemEnabled() { return useFastmem; }
u8* getFastmemArenaBase() { return arena->VirtualBasePointer(); }
};