From 323bb280df855a9ab8474018f1f5e4de65c398b2 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Sun, 29 May 2022 22:53:18 +1000 Subject: [PATCH] Update GameCube/Wii/WiiU targets Update the GameCube/Wii/WiiU targets to make sure they compile and work; and add support for the Lightrec dynarec, using a custom memory map on the WiiU target (and unoptimized regular malloc'd addresses on NGC/Wii). Signed-off-by: Paul Cercueil --- Makefile | 3 +- Makefile.libretro | 43 +++++-- frontend/wiiu/coreinit/memorymap.h | 199 +++++++++++++++++++++++++++++ libpcsxcore/lightrec/mem.h | 8 +- libpcsxcore/lightrec/mem_wiiu.c | 108 ++++++++++++++++ libpcsxcore/lightrec/plugin.c | 19 +++ 6 files changed, 365 insertions(+), 15 deletions(-) create mode 100644 frontend/wiiu/coreinit/memorymap.h create mode 100644 libpcsxcore/lightrec/mem_wiiu.c diff --git a/Makefile b/Makefile index c95f4223..14c67bef 100644 --- a/Makefile +++ b/Makefile @@ -94,12 +94,13 @@ ifeq "$(DYNAREC)" "lightrec" CFLAGS += -Ideps/lightning/include -Ideps/lightrec -Iinclude/lightning -Iinclude/lightrec \ -DLIGHTREC -DLIGHTREC_STATIC LIGHTREC_CUSTOM_MAP ?= 0 +LIGHTREC_CUSTOM_MAP_OBJ ?= libpcsxcore/lightrec/mem.o LIGHTREC_THREADED_COMPILER ?= 0 CFLAGS += -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP) \ -DLIGHTREC_ENABLE_THREADED_COMPILER=$(LIGHTREC_THREADED_COMPILER) ifeq ($(LIGHTREC_CUSTOM_MAP),1) LDLIBS += -lrt -OBJS += libpcsxcore/lightrec/mem.o +OBJS += $(LIGHTREC_CUSTOM_MAP_OBJ) endif ifeq ($(LIGHTREC_THREADED_COMPILER),1) OBJS += deps/lightrec/recompiler.o \ diff --git a/Makefile.libretro b/Makefile.libretro index 42843bc6..82e98f09 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -300,19 +300,36 @@ else ifeq ($(platform), xenon) AR = xenon-ar$(EXE_EXT) CFLAGS += -D__LIBXENON__ -m32 -D__ppc__ -# Nintendo Game Cube -else ifeq ($(platform), ngc) - TARGET := $(TARGET_NAME)_libretro_ngc.a - CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) - AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__ - -# Nintendo Wii -else ifeq ($(platform), wii) - TARGET := libretro_$(TARGET_NAME)_wii.a - CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) - AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__ +# Nintendo GC/Wii/WiiU +else ifneq (,$(filter $(platform),ngc wii wiiu)) + TARGET := $(TARGET_NAME)_libretro_$(platform).a + CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) + CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) + AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) + ifeq ($(platform), ngc) + CFLAGS += -DHW_DOL -mogc + else ifeq ($(platform), wii) + CFLAGS += -DHW_RVL -mrvl + else ifeq ($(platform), wiiu) + # -mwup was removed in newer devkitPPC versions + CFLAGS += -DHW_WUP + CFLAGS += -I frontend/wiiu + LIGHTREC_CUSTOM_MAP := 1 + LIGHTREC_CUSTOM_MAP_OBJ := libpcsxcore/lightrec/mem_wiiu.o + endif + ARCH = powerpc + BUILTIN_GPU = peops + CFLAGS += -D__ppc__ -D__powerpc__ + CFLAGS += -DGEKKO -mcpu=750 -meabi -mhard-float + CFLAGS += -DNO_SOCKET -DNO_DYLIB + STATIC_LINKING := 1 + THREAD_RENDERING := 0 + NO_PTHREAD := 1 + NO_MMAP := 1 + NO_POSIX_MEMALIGN := 1 + LIBDL := + LIBPTHREAD := + LIBRT := # QNX else ifeq ($(platform), qnx) diff --git a/frontend/wiiu/coreinit/memorymap.h b/frontend/wiiu/coreinit/memorymap.h new file mode 100644 index 00000000..1e068719 --- /dev/null +++ b/frontend/wiiu/coreinit/memorymap.h @@ -0,0 +1,199 @@ +//SPDX-License-Identifier: GPL-2.0-or-later +/* From wut: + * https://github.com/devkitPro/wut/blob/0b196e8abcedeb0238105f3ffab7cb0093638b86/include/coreinit/memorymap.h + */ + +#pragma once +#include +#include +typedef bool BOOL; + +/** + * \defgroup coreinit_memorymap Memory Map + * \ingroup coreinit + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum OSMemoryMapMode +{ + OS_MAP_MEMORY_INVALID = 0, + OS_MAP_MEMORY_READ_ONLY = 1, + OS_MAP_MEMORY_READ_WRITE = 2, + OS_MAP_MEMORY_FREE = 3, + OS_MAP_MEMORY_ALLOCATED = 4, +} OSMemoryMapMode; + +#define OS_PAGE_SIZE (128 * 1024) + +uint32_t +OSEffectiveToPhysical(uint32_t virtualAddress); + +BOOL +OSIsAddressValid(uint32_t virtualAddress); + +BOOL +__OSValidateAddressSpaceRange(int /* unused */, + uint32_t virtualAddress, + uint32_t size); + +/** + * Allocates virtual address range for later mapping. + * + * \param virtualAddress + * Requested start address for the range. If there is no preference, NULL can be + * used. + * + * \param size + * Size of address range to allocate. + * + * \param align + * Alignment of address range to allocate. + * + * \return + * The starting address of the newly allocated range, or NULL on failure. + * + * \sa + * - OSFreeVirtAddr() + * - OSMapMemory() + */ +uint32_t +OSAllocVirtAddr(uint32_t virtualAddress, + uint32_t size, + uint32_t align); + +/** + * Frees a previously allocated virtual address range back to the system. + * + * \param virtualAddress + * The start of the virtual address range to free. + * + * \param size + * The size of the virtual address range to free. + * + * \return + * \c true on success. + */ +BOOL +OSFreeVirtAddr(uint32_t virtualAddress, + uint32_t size); + +/** + * Determines the status of the given virtual memory address - mapped read-write + * or read-only, free, allocated or invalid. + * + * \param virtualAddress + * The virtual address to query. + * + * \return + * The status of the memory address - see #OSMemoryMapMode. + */ +OSMemoryMapMode +OSQueryVirtAddr(uint32_t virtualAddress); + +/** + * Maps a physical address to a virtual address, with a given size and set of + * permissions. + * + * \param virtualAddress + * The target virtual address for the mapping. + * + * \param physicalAddress + * Physical address of the memory to back the mapping. + * + * \param size + * Size, in bytes, of the desired mapping. Likely has an alignment requirement. + * + * \param mode + * Permissions to map the memory with - see #OSMemoryMapMode. + * + * \return + * \c true on success. + * + * \sa + * - OSAllocVirtAddr() + * - OSUnmapMemory() + */ +BOOL +OSMapMemory(uint32_t virtualAddress, + uint32_t physicalAddress, + uint32_t size, + OSMemoryMapMode mode); + +/** + * Unmaps previously mapped memory. + * + * \param virtualAddress + * Starting address of the area to unmap. + * + * \param size + * Size of the memory area to unmap. + * + * \return + * \c true on success. + */ +BOOL +OSUnmapMemory(uint32_t virtualAddress, + uint32_t size); + +/** + * Gets the range of virtual addresses available for mapping. + * + * \param outVirtualAddress + * Pointer to write the starting address of the memory area to. + * + * \param outSize + * Pointer to write the size of the memory area to. + * + * \sa + * - OSMapMemory() + */ +void +OSGetMapVirtAddrRange(uint32_t *outVirtualAddress, + uint32_t *outSize); + +/** + * Gets the range of available physical memory (not reserved for app code or + * data). + * + * \param outPhysicalAddress + * Pointer to write the starting physical address of the memory area to. + * + * \param outSize + * Pointer to write the size of the memory area to. + * + * \if false + * Is memory returned by this function actually safe to map and use? couldn't + * get a straight answer from decaf-emu's kernel_memory.cpp... + * \endif + */ +void +OSGetAvailPhysAddrRange(uint32_t *outPhysicalAddress, + uint32_t *outSize); + +/** + * Gets the range of physical memory used for the application's data. + * + * \param outPhysicalAddress + * Pointer to write the starting physical address of the memory area to. + * + * \param outSize + * Pointer to write the size of the memory area to. + * + * \if false + * does this include the main heap? + * \endif + */ +void +OSGetDataPhysAddrRange(uint32_t *outPhysicalAddress, + uint32_t *outSize); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libpcsxcore/lightrec/mem.h b/libpcsxcore/lightrec/mem.h index 98dbbdeb..f746650b 100644 --- a/libpcsxcore/lightrec/mem.h +++ b/libpcsxcore/lightrec/mem.h @@ -8,7 +8,13 @@ #ifdef LIGHTREC -#define CODE_BUFFER_SIZE (8 * 1024 * 1024) +#ifdef HW_WUP /* WiiU */ +# define WUP_RWX_MEM_BASE 0x00802000 +# define WUP_RWX_MEM_END 0x01000000 +# define CODE_BUFFER_SIZE (WUP_RWX_MEM_END - WUP_RWX_MEM_BASE) +#else +# define CODE_BUFFER_SIZE (8 * 1024 * 1024) +#endif extern void *code_buffer; diff --git a/libpcsxcore/lightrec/mem_wiiu.c b/libpcsxcore/lightrec/mem_wiiu.c new file mode 100644 index 00000000..a9c1c4fe --- /dev/null +++ b/libpcsxcore/lightrec/mem_wiiu.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Ash Logan + */ + +#include +#include +#include + +#include "../memmap.h" +#include "../psxhw.h" +#include "../psxmem.h" +#include "../r3000a.h" + +#include "mem.h" + +void* code_buffer; + +static void* wiiu_mmap(uint32_t requested_va, size_t length, void* backing_mem) { + if (length < OS_PAGE_SIZE) length = OS_PAGE_SIZE; + + uint32_t va = OSAllocVirtAddr(requested_va, length, 0); + if (!va) return MAP_FAILED; + + BOOL mapped = OSMapMemory(va, OSEffectiveToPhysical((uint32_t)backing_mem), + length, OS_MAP_MEMORY_READ_WRITE); + if (!mapped) { + OSFreeVirtAddr(va, length); + return MAP_FAILED; + } + + return (void*)va; +} + +static void wiiu_unmap(void* va, size_t length) { + if (va == MAP_FAILED) return; + OSUnmapMemory((uint32_t)va, length); + OSFreeVirtAddr((uint32_t)va, length); +} + +static void* psx_mem; +static void* psx_parallel; +static void* psx_scratch; +static void* psx_bios; + +int lightrec_init_mmap(void) { + psx_mem = memalign(OS_PAGE_SIZE, 0x200000); + psx_parallel = memalign(OS_PAGE_SIZE, 0x10000); + psx_scratch = memalign(OS_PAGE_SIZE, 0x10000); + psx_bios = memalign(OS_PAGE_SIZE, 0x80000); + if (!psx_mem || !psx_parallel || !psx_scratch || !psx_bios) + goto cleanup_allocations; + + uint32_t avail_va; + uint32_t avail_va_size; + OSGetMapVirtAddrRange(&avail_va, &avail_va_size); + if (!avail_va || avail_va_size < 0x20000000) + goto cleanup_allocations; + + // Map 4x ram mirrors + int i; + for (i = 0; i < 4; i++) { + void* ret = wiiu_mmap(avail_va + 0x200000 * i, 0x200000, psx_mem); + if (ret == MAP_FAILED) break; + } + if (i != 4) { + for (int i = 0; i < 4; i++) + wiiu_unmap(avail_va + 0x200000 * i, 0x200000); + goto cleanup_allocations; + } + psxM = (void*)avail_va; + + psxP = wiiu_mmap(avail_va + 0x1f000000, 0x10000, psx_parallel); + psxH = wiiu_mmap(avail_va + 0x1f800000, 0x10000, psx_scratch); + psxR = wiiu_mmap(avail_va + 0x1fc00000, 0x80000, psx_bios); + + if (psxP == MAP_FAILED || psxH == MAP_FAILED || psxR == MAP_FAILED) { + for (int i = 0; i < 4; i++) + wiiu_unmap(psxM + 0x200000 * i, 0x200000); + wiiu_unmap(psxP, 0x10000); + wiiu_unmap(psxH, 0x10000); + wiiu_unmap(psxR, 0x80000); + goto cleanup_allocations; + } + + code_buffer = WUP_RWX_MEM_BASE; + + return 0; + +cleanup_allocations: + free(psx_mem); + free(psx_parallel); + free(psx_scratch); + free(psx_bios); + return -1; +} + +void lightrec_free_mmap(void) { + for (int i = 0; i < 4; i++) + wiiu_unmap(psxM + 0x200000 * i, 0x200000); + wiiu_unmap(psxP, 0x10000); + wiiu_unmap(psxH, 0x10000); + wiiu_unmap(psxR, 0x80000); + free(psx_mem); + free(psx_parallel); + free(psx_scratch); + free(psx_bios); +} diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c index ec991105..16770a70 100644 --- a/libpcsxcore/lightrec/plugin.c +++ b/libpcsxcore/lightrec/plugin.c @@ -399,10 +399,29 @@ static bool lightrec_can_hw_direct(u32 kaddr, bool is_write, u8 size) } } +#if defined(HW_DOL) || defined(HW_RVL) +static void lightrec_code_inv(void *ptr, uint32_t len) +{ + extern void DCFlushRange(void *ptr, u32 len); + extern void ICInvalidateRange(void *ptr, u32 len); + + DCFlushRange(ptr, len); + ICInvalidateRange(ptr, len); +} +#elif defined(HW_WUP) +static void lightrec_code_inv(void *ptr, uint32_t len) +{ + wiiu_clear_cache(ptr, (void *)((uintptr_t)ptr + len)); +} +#endif + static const struct lightrec_ops lightrec_ops = { .cop2_op = cop2_op, .enable_ram = lightrec_enable_ram, .hw_direct = lightrec_can_hw_direct, +#if defined(HW_DOL) || defined(HW_RVL) || defined(HW_WUP) + .code_inv = lightrec_code_inv, +#endif }; static int lightrec_plugin_init(void) -- 2.39.2