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 \
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)
--- /dev/null
+//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
+
+/** @} */
#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;
--- /dev/null
+// 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);
+}
}
}
+#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)