From a093e81fbfc1c588b091656844b26684ec3dc01d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 11 May 2022 16:54:16 +0100 Subject: [PATCH] lightrec: Add new memory init functions Lightrec can greatly benefit from having the RAM/BIOS/scratchpad and RAM mirrors mapped to specific addresses. For the same value of (offset): - If the RAM is mapped to (offset), the BIOS is mapped to (offset + 0x1fc00000) and the scratchpad to (offset + 0x1f800000), the generated code will be better; - If the RAM is also mirrored to (offset + 0x200000), (offset + 0x400000) and (offset + 0x600000), the generated code will be even better; - If the offset is 0x0, the generated code will be even better. Additionally, the new memory init code will attempt to use huge pages when possible, in order to greatly reduce the overhead of the MMU. Signed-off-by: Paul Cercueil --- Makefile | 10 +- Makefile.libretro | 4 + libpcsxcore/lightrec/mem.c | 190 +++++++++++++++++++++++++++++++++++++ libpcsxcore/lightrec/mem.h | 12 +++ 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 libpcsxcore/lightrec/mem.c create mode 100644 libpcsxcore/lightrec/mem.h diff --git a/Makefile b/Makefile index 6a83f46b..bff1a1c3 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,8 @@ ifdef PCNT CFLAGS += -DPCNT endif +LIGHTREC_CUSTOM_MAP ?= 0 + # core OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/database.o \ libpcsxcore/decode_xa.o libpcsxcore/mdec.o \ @@ -89,7 +91,12 @@ libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull # dynarec ifeq "$(DYNAREC)" "lightrec" CFLAGS += -Ideps/lightning/include -Ideps/lightrec -Iinclude/lightning -Iinclude/lightrec \ - -DLIGHTREC -DLIGHTREC_STATIC + -DLIGHTREC -DLIGHTREC_STATIC \ + -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP) +LDLIBS += -lrt +ifeq ($(LIGHTREC_CUSTOM_MAP),1) +OBJS += libpcsxcore/lightrec/mem.o +endif OBJS += libpcsxcore/lightrec/plugin.o OBJS += deps/lightning/lib/jit_disasm.o \ deps/lightning/lib/jit_memory.o \ @@ -108,6 +115,7 @@ OBJS += deps/lightning/lib/jit_disasm.o \ deps/lightrec/regcache.o \ deps/lightrec/recompiler.o \ deps/lightrec/reaper.o +libpcsxcore/lightrec/mem.o: CFLAGS += -D_GNU_SOURCE ifeq ($(MMAP_WIN32),1) CFLAGS += -Iinclude/mman OBJS += deps/mman/mman.o diff --git a/Makefile.libretro b/Makefile.libretro index dd896820..3edda648 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -51,6 +51,9 @@ ifeq ($(platform), unix) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC THREAD_RENDERING = 1 +ifeq ($(shell uname),Linux) + LIGHTREC_CUSTOM_MAP := 1 +endif ifneq ($(findstring SunOS,$(shell uname -s)),) CC = gcc endif @@ -92,6 +95,7 @@ else ifeq ($(platform), linux-portable) LIBDL := LIBM := NO_UNDEF_CHECK = 1 + LIGHTREC_CUSTOM_MAP := 1 # OS X else ifeq ($(platform), osx) diff --git a/libpcsxcore/lightrec/mem.c b/libpcsxcore/lightrec/mem.c new file mode 100644 index 00000000..76608ea4 --- /dev/null +++ b/libpcsxcore/lightrec/mem.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2022 Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../psxhw.h" +#include "../psxmem.h" +#include "../r3000a.h" + +#include "mem.h" + +#define ARRAY_SIZE(a) (sizeof(a) ? (sizeof(a) / sizeof((a)[0])) : 0) + +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0x100000 +#endif + +static const uintptr_t supported_io_bases[] = { + 0x0, + 0x10000000, + 0x40000000, + 0x80000000, +}; + +static void * mmap_huge(void *addr, size_t length, int prot, int flags, + int fd, off_t offset) +{ + void *map = MAP_FAILED; + + if (length >= 0x200000) { + map = mmap(addr, length, prot, + flags | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT), + fd, offset); + if (map != MAP_FAILED) + printf("Hugetlb mmap to address 0x%lx succeeded\n", (uintptr_t) addr); + } + + if (map == MAP_FAILED) { + map = mmap(addr, length, prot, flags, fd, offset); + if (map != MAP_FAILED) + printf("Regular mmap to address 0x%lx succeeded\n", (uintptr_t) addr); + } + + return map; +} + +static int lightrec_mmap_ram(bool hugetlb) +{ + unsigned int i, j; + int err, memfd, flags = 0; + uintptr_t base; + void *map; + + if (hugetlb) + flags |= MFD_HUGETLB; + + memfd = memfd_create("/lightrec_memfd", flags); + if (memfd < 0) { + err = -errno; + fprintf(stderr, "Failed to create memfd: %d\n", err); + return err; + } + + err = ftruncate(memfd, 0x200000); + if (err < 0) { + err = -errno; + fprintf(stderr, "Could not trim memfd: %d\n", err); + goto err_close_memfd; + } + + for (i = 0; i < ARRAY_SIZE(supported_io_bases); i++) { + base = supported_io_bases[i]; + + for (j = 0; j < 4; j++) { + map = mmap_huge((void *)(base + j * 0x200000), + 0x200000, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, memfd, 0); + if (map == MAP_FAILED) + break; + } + + /* Impossible to map using this base */ + if (j == 0) + continue; + + /* All mirrors mapped - we got a match! */ + if (j == 4) + break; + + /* Only some mirrors mapped - clean the mess and try again */ + for (; j > 0; j--) + munmap((void *)(base + (j - 1) * 0x200000), 0x200000); + } + + if (i == ARRAY_SIZE(supported_io_bases)) { + err = -EINVAL; + goto err_close_memfd; + } + + err = 0; + psxM = (s8 *)base; + +err_close_memfd: + close(memfd); + return err; +} + +int lightrec_init_mmap(void) +{ + unsigned int i; + uintptr_t base; + void *map; + int err; + + err = lightrec_mmap_ram(true); + if (err) { + err = lightrec_mmap_ram(false); + if (err) { + fprintf(stderr, "Unable to mmap RAM and mirrors\n"); + return err; + } + } + + base = (uintptr_t) psxM; + + map = mmap((void *)(base + 0x1f000000), 0x10000, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0); + if (map == MAP_FAILED) { + err = -EINVAL; + fprintf(stderr, "Unable to mmap parallel port\n"); + goto err_unmap; + } + + psxP = (s8 *)map; + + map = mmap_huge((void *)(base + 0x1fc00000), 0x200000, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0); + if (map == MAP_FAILED) { + err = -EINVAL; + fprintf(stderr, "Unable to mmap BIOS\n"); + goto err_unmap_parallel; + } + + psxR = (s8 *)map; + + map = mmap((void *)(base + 0x1f800000), 0x10000, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_ANONYMOUS, 0, 0); + if (map == MAP_FAILED) { + err = -EINVAL; + fprintf(stderr, "Unable to mmap scratchpad\n"); + goto err_unmap_bios; + } + + psxH = (s8 *)map; + + return 0; + +err_unmap_bios: + munmap(psxR, 0x80000); +err_unmap_parallel: + munmap(psxP, 0x10000); +err_unmap: + for (i = 0; i < 4; i++) + munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000); + return err; +} + +void lightrec_free_mmap(void) +{ + unsigned int i; + + munmap(psxH, 0x10000); + munmap(psxR, 0x80000); + munmap(psxP, 0x10000); + for (i = 0; i < 4; i++) + munmap((void *)((uintptr_t)psxM + i * 0x200000), 0x200000); +} diff --git a/libpcsxcore/lightrec/mem.h b/libpcsxcore/lightrec/mem.h new file mode 100644 index 00000000..7f04ce59 --- /dev/null +++ b/libpcsxcore/lightrec/mem.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Paul Cercueil + */ + +#ifndef __LIGHTREC_MEM_H__ +#define __LIGHTREC_MEM_H__ + +int lightrec_init_mmap(void); +void lightrec_free_mmap(void); + +#endif /* __LIGHTREC_MEM_H__ */ -- 2.39.2