#include "r3000a.h"
#include "psxhw.h"
#include "debug.h"
-#include <sys/mman.h>
+
+#include "memmap.h"
+
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#endif
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
+boolean writeok = TRUE;
+
+#ifndef NDEBUG
+#include "debug.h"
+#else
+void DebugCheckBP(u32 address, enum breakpoint_types type) {}
+#endif
+
void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
enum psxMapTag tag);
void (*psxUnmapHook)(void *ptr, size_t size, enum psxMapTag tag);
void *psxMap(unsigned long addr, size_t size, int is_fixed,
enum psxMapTag tag)
{
+#ifdef LIGHTREC
+#ifdef MAP_FIXED_NOREPLACE
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE;
+#else
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
+#endif
+#else
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
- int tried_to_align = 0;
+#endif
+
+ int try_ = 0;
unsigned long mask;
void *req, *ret;
retry:
if (psxMapHook != NULL) {
- ret = psxMapHook(addr, size, is_fixed, tag);
- goto out;
+ ret = psxMapHook(addr, size, 0, tag);
+ if (ret == NULL)
+ return NULL;
+ }
+ else {
+ /* avoid MAP_FIXED, it overrides existing mappings.. */
+ /* if (is_fixed)
+ flags |= MAP_FIXED; */
+
+ req = (void *)addr;
+ ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (ret == MAP_FAILED)
+ return NULL;
}
- if (is_fixed)
- flags |= MAP_FIXED;
-
- req = (void *)addr;
- ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
- if (ret == MAP_FAILED)
- return NULL;
-
-out:
if (addr != 0 && ret != (void *)addr) {
SysMessage("psxMap: warning: wanted to map @%08x, got %p\n",
addr, ret);
- if (ret != NULL && ((addr ^ (long)ret) & 0x00ffffff)
- && !tried_to_align)
+ if (is_fixed) {
+ psxUnmap(ret, size, tag);
+ return NULL;
+ }
+
+ if (((addr ^ (unsigned long)ret) & ~0xff000000l) && try_ < 2)
{
psxUnmap(ret, size, tag);
// try to use similarly aligned memory instead
// (recompiler needs this)
- mask = (addr - 1) & ~addr & 0x07ffffff;
- addr = (unsigned long)(ret + mask) & ~mask;
- tried_to_align = 1;
+ mask = try_ ? 0xffff : 0xffffff;
+ addr = ((unsigned long)ret + mask) & ~mask;
+ try_++;
goto retry;
}
}
return;
}
- munmap(ptr, size);
+ if (ptr)
+ munmap(ptr, size);
}
s8 *psxM = NULL; // Kernel & User Memory (2 Meg)
memset(psxMemRLUT, 0, 0x10000 * sizeof(void *));
memset(psxMemWLUT, 0, 0x10000 * sizeof(void *));
+#ifdef LIGHTREC
+ psxM = psxMap(0x30000000, 0x00210000, 1, MAP_TAG_RAM);
+ if (psxM == NULL)
+ psxM = psxMap(0x70000000, 0x00210000, 1, MAP_TAG_RAM);
+
+#else
psxM = psxMap(0x80000000, 0x00210000, 1, MAP_TAG_RAM);
+#endif
#ifndef RAM_FIXED
if (psxM == NULL)
- psxM = psxMap(0x78000000, 0x00210000, 0, MAP_TAG_RAM);
+ psxM = psxMap(0x77000000, 0x00210000, 0, MAP_TAG_RAM);
#endif
if (psxM == NULL) {
SysMessage(_("mapping main RAM failed"));
}
psxP = &psxM[0x200000];
- psxH = psxMap(0x1f800000, 0x10000, 1, MAP_TAG_OTHER);
+#ifdef LIGHTREC
+ psxH = psxMap(0x4f800000, 0x10000, 0, MAP_TAG_OTHER);
+ if (psxH == NULL)
+ psxH = psxMap(0x8f800000, 0x10000, 0, MAP_TAG_OTHER);
+
+ psxR = psxMap(0x4fc00000, 0x80000, 0, MAP_TAG_OTHER);
+ if (psxR == NULL)
+ psxR = psxMap(0x8fc00000, 0x80000, 0, MAP_TAG_OTHER);
+#else
+ psxH = psxMap(0x1f800000, 0x10000, 0, MAP_TAG_OTHER);
psxR = psxMap(0x1fc00000, 0x80000, 0, MAP_TAG_OTHER);
+#endif
if (psxMemRLUT == NULL || psxMemWLUT == NULL ||
- psxR == NULL || psxP == NULL || psxH != (void *)0x1f800000) {
+ psxR == NULL || psxP == NULL || psxH == NULL) {
SysMessage(_("Error allocating memory!"));
+ psxMemShutdown();
return -1;
}
char bios[1024];
memset(psxM, 0, 0x00200000);
- memset(psxP, 0, 0x00010000);
+ memset(psxP, 0xff, 0x00010000);
+
+ Config.HLE = TRUE;
if (strcmp(Config.Bios, "HLE") != 0) {
sprintf(bios, "%s/%s", Config.BiosDir, Config.Bios);
if (f == NULL) {
SysMessage(_("Could not open BIOS:\"%s\". Enabling HLE Bios!\n"), bios);
memset(psxR, 0, 0x80000);
- Config.HLE = TRUE;
} else {
- fread(psxR, 1, 0x80000, f);
+ if (fread(psxR, 1, 0x80000, f) == 0x80000) {
+ Config.HLE = FALSE;
+ } else {
+ SysMessage(_("The selected BIOS:\"%s\" is of wrong size. Enabling HLE Bios!\n"), bios);
+ }
fclose(f);
- Config.HLE = FALSE;
}
- } else Config.HLE = TRUE;
+ }
}
void psxMemShutdown() {
- psxUnmap(psxM, 0x00210000, MAP_TAG_RAM);
- psxUnmap(psxH, 0x1f800000, MAP_TAG_OTHER);
- psxUnmap(psxR, 0x80000, MAP_TAG_OTHER);
+ psxUnmap(psxM, 0x00210000, MAP_TAG_RAM); psxM = NULL;
+ psxUnmap(psxH, 0x10000, MAP_TAG_OTHER); psxH = NULL;
+ psxUnmap(psxR, 0x80000, MAP_TAG_OTHER); psxR = NULL;
- free(psxMemRLUT);
- free(psxMemWLUT);
+ free(psxMemRLUT); psxMemRLUT = NULL;
+ free(psxMemWLUT); psxMemWLUT = NULL;
}
-static int writeok = 1;
-
u8 psxMemRead8(u32 mem) {
char *p;
u32 t;
#ifdef PSXMEM_LOG
PSXMEM_LOG("err lb %8.8lx\n", mem);
#endif
- return 0;
+ return 0xFF;
}
}
}
#ifdef PSXMEM_LOG
PSXMEM_LOG("err lh %8.8lx\n", mem);
#endif
- return 0;
+ return 0xFFFF;
}
}
}
#ifdef PSXMEM_LOG
if (writeok) { PSXMEM_LOG("err lw %8.8lx\n", mem); }
#endif
- return 0;
+ return 0xFFFFFFFF;
}
}
}
void psxMemWrite32(u32 mem, u32 value) {
char *p;
+#if defined(ICACHE_EMULATION)
+ /* Stores in PS1 code during cache isolation invalidate cachelines.
+ * It is assumed that cache-flush routines write to the lowest 4KB of
+ * address space for Icache, or 1KB for Dcache/scratchpad.
+ * Originally, stores had to check 'writeok' in psxRegs struct before
+ * writing to RAM. To eliminate this necessity, we could simply patch the
+ * BIOS 0x44 FlushCache() A0 jumptable entry. Unfortunately, this won't
+ * work for some games that use less-buggy non-BIOS cache-flush routines
+ * like '007 Tomorrow Never Dies', often provided by SN-systems, the PS1
+ * toolchain provider.
+ * Instead, we backup the lowest 64KB PS1 RAM when the cache is isolated.
+ * All stores write to RAM regardless of cache state. Thus, cache-flush
+ * routines temporarily trash the lowest 4KB of PS1 RAM. Fortunately, they
+ * ran in a 'critical section' with interrupts disabled, so there's little
+ * worry of PS1 code ever reading the trashed contents.
+ * We point the relevant portions of psxMemRLUT[] to the 64KB backup while
+ * cache is isolated. This is in case the dynarec needs to recompile some
+ * code during isolation. As long as it reads code using psxMemRLUT[] ptrs,
+ * it should never see trashed RAM contents.
+ *
+ * -senquack, mips dynarec team, 2017
+ */
+ static u32 mem_bak[0x10000/4];
+#endif
u32 t;
-
+ u32 m = mem & 0xffff;
// if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n");
t = mem >> 16;
if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
- if ((mem & 0xffff) < 0x400)
+ if (m < 0x400)
psxHu32ref(mem) = SWAPu32(value);
else
psxHwWrite32(mem, value);
switch (value) {
case 0x800: case 0x804:
- if (writeok == 0) break;
- writeok = 0;
+ if (writeok == FALSE) break;
+ writeok = FALSE;
memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(void *));
memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(void *));
memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(void *));
+#ifdef ICACHE_EMULATION
+ /* Cache is now isolated, pending cache-flush sequence:
+ * Backup lower 64KB of PS1 RAM, adjust psxMemRLUT[].
+ */
+ memcpy((void*)mem_bak, (void*)psxM, sizeof(mem_bak));
+ psxMemRLUT[0x0000] = psxMemRLUT[0x0020] = psxMemRLUT[0x0040] = psxMemRLUT[0x0060] = (u8 *)mem_bak;
+ psxMemRLUT[0x8000] = psxMemRLUT[0x8020] = psxMemRLUT[0x8040] = psxMemRLUT[0x8060] = (u8 *)mem_bak;
+ psxMemRLUT[0xa000] = psxMemRLUT[0xa020] = psxMemRLUT[0xa040] = psxMemRLUT[0xa060] = (u8 *)mem_bak;
+ psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
+#endif
break;
case 0x00: case 0x1e988:
- if (writeok == 1) break;
- writeok = 1;
+ if (writeok == TRUE) break;
+ writeok = TRUE;
for (i = 0; i < 0x80; i++) psxMemWLUT[i + 0x0000] = (void *)&psxM[(i & 0x1f) << 16];
memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void *));
memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void *));
+#ifdef ICACHE_EMULATION
+ /* Cache is now unisolated:
+ * Restore lower 64KB RAM contents and psxMemRLUT[].
+ */
+ memcpy((void*)psxM, (void*)mem_bak, sizeof(mem_bak));
+ psxMemRLUT[0x0000] = psxMemRLUT[0x0020] = psxMemRLUT[0x0040] = psxMemRLUT[0x0060] = (u8 *)psxM;
+ psxMemRLUT[0x8000] = psxMemRLUT[0x8020] = psxMemRLUT[0x8040] = psxMemRLUT[0x8060] = (u8 *)psxM;
+ psxMemRLUT[0xa000] = psxMemRLUT[0xa020] = psxMemRLUT[0xa040] = psxMemRLUT[0xa060] = (u8 *)psxM;
+ /* Dynarecs might take this opportunity to flush their code cache */
+ psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
+#endif
break;
default:
#ifdef PSXMEM_LOG