Update GameCube/Wii/WiiU targets
authorAsh Logan <ash@heyquark.com>
Sun, 29 May 2022 12:53:18 +0000 (22:53 +1000)
committerPaul Cercueil <paul@crapouillou.net>
Sun, 23 Jul 2023 18:10:25 +0000 (20:10 +0200)
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 <paul@crapouillou.net>
Makefile
Makefile.libretro
frontend/wiiu/coreinit/memorymap.h [new file with mode: 0644]
libpcsxcore/lightrec/mem.h
libpcsxcore/lightrec/mem_wiiu.c [new file with mode: 0644]
libpcsxcore/lightrec/plugin.c

index c95f422..14c67be 100644 (file)
--- 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 \
index 42843bc..82e98f0 100644 (file)
@@ -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 (file)
index 0000000..1e06871
--- /dev/null
@@ -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 <stdint.h>
+#include <stdbool.h>
+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
+
+/** @} */
index 98dbbde..f746650 100644 (file)
@@ -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 (file)
index 0000000..a9c1c4f
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 Ash Logan <ash@heyquark.com>
+ */
+
+#include <coreinit/memorymap.h>
+#include <malloc.h>
+#include <stdbool.h>
+
+#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);
+}
index ec99110..16770a7 100644 (file)
@@ -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)