mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
runtime: add opt-in 8 MB main RAM mod
Adapt the 8 MB RAM work from the rbengine branch into a master-targeted change. The builtin package is disabled by default, activation requests expanded RAM before memory init, and runtime/state/digest/dispatch paths respect the live RAM map.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
id = "psx.enhancement.8mb-ram"
|
||||
version = "1.0.0"
|
||||
name = "8 MB Main RAM"
|
||||
author = "psxrecomp"
|
||||
description = "Enables an opt-in 8 MB main RAM map for patches that require expanded PS1 memory. Disabled by default."
|
||||
|
||||
[[feature]]
|
||||
id = "8mb-ram"
|
||||
name = "8 MB Main RAM"
|
||||
description = "Use expanded 8 MB main RAM instead of stock 2 MB mirroring. Both netplay peers must use the same setting."
|
||||
category = "enhancement"
|
||||
default_enabled = false
|
||||
hidden = true
|
||||
|
||||
[[plugin]]
|
||||
feature = "8mb-ram"
|
||||
id = "psx.8mb-ram"
|
||||
@@ -2137,6 +2137,7 @@ void FullFunctionEmitter::emit_dispatch(
|
||||
out += "extern int dirty_ram_dispatch(CPUState* cpu, uint32_t addr, uint32_t stop_addr);\n";
|
||||
out += "extern int dirty_ram_is_dirty(uint32_t phys);\n";
|
||||
out += "extern int psx_kernel_bless_dispatchable(uint32_t phys);\n";
|
||||
out += "extern uint32_t psx_ram_canon_code_addr(uint32_t addr);\n";
|
||||
out += "extern void fntrace_record(CPUState* cpu, uint32_t target);\n";
|
||||
out += "extern uint64_t g_dispatch_static_hits;\n";
|
||||
out += "\n";
|
||||
@@ -2189,7 +2190,8 @@ void FullFunctionEmitter::emit_dispatch(
|
||||
out += " * physical 0x30000-0x5AFFF. If the target belongs to the\n";
|
||||
out += " * active game text range, route it through the game/dirty-RAM\n";
|
||||
out += " * path before normalizing it to shell ROM. */\n";
|
||||
out += " uint32_t game_phys = addr & 0x1FFFFFFFu;\n";
|
||||
out += " uint32_t game_addr = psx_ram_canon_code_addr(addr);\n";
|
||||
out += " uint32_t game_phys = game_addr & 0x1FFFFFFFu;\n";
|
||||
out += " /* Class-A shell-window collision fix: post-game-start the BIOS shell\n";
|
||||
out += " * copy at RAM 0x30000-0x5AFFF is DEAD (overwritten by the game EXE,\n";
|
||||
out += " * its runtime-loaded overlays, or CD streaming), so normalize()->shell\n";
|
||||
@@ -2233,13 +2235,13 @@ void FullFunctionEmitter::emit_dispatch(
|
||||
out += fmt::format(
|
||||
" game_phys >= 0x{:08X}u && game_phys <= 0x{:08X}u &&\n",
|
||||
addr_model().rom_keyed_ram_lo(), addr_model().rom_keyed_ram_hi_incl());
|
||||
out += " psx_game_address_in_text(addr) && dirty_ram_text_native_ok(game_phys);\n";
|
||||
out += " psx_game_address_in_text(game_addr) && dirty_ram_text_native_ok(game_phys);\n";
|
||||
} else {
|
||||
out += " int game_text_in_shell_window = 0;\n";
|
||||
}
|
||||
out += " if (!found && (game_shell_overlap || game_text_in_shell_window ||\n";
|
||||
out += " (psx_game_address_in_text(addr) && dirty_ram_is_dirty(game_phys)))) {\n";
|
||||
out += " found = dirty_ram_dispatch(cpu, addr, stop_addr);\n";
|
||||
out += " (psx_game_address_in_text(game_addr) && dirty_ram_is_dirty(game_phys)))) {\n";
|
||||
out += " found = dirty_ram_dispatch(cpu, game_addr, stop_addr);\n";
|
||||
out += " }\n";
|
||||
out += "#endif\n";
|
||||
out += " uint32_t phys = normalize(addr);\n";
|
||||
|
||||
@@ -1482,7 +1482,8 @@ int main(int argc, char** argv) {
|
||||
uint32_t game_text_start = exe->load_address() & 0x1FFFFFFFu;
|
||||
uint32_t game_text_end = game_text_start + exe->code_size();
|
||||
ds << "int psx_game_address_in_text(uint32_t addr) {\n";
|
||||
ds << " uint32_t phys = addr & 0x1FFFFFFFu;\n";
|
||||
ds << " extern uint32_t psx_ram_canon_code_addr(uint32_t);\n";
|
||||
ds << " uint32_t phys = psx_ram_canon_code_addr(addr) & 0x1FFFFFFFu;\n";
|
||||
ds << fmt::format(" return phys >= 0x{:08X}u && phys < 0x{:08X}u;\n",
|
||||
game_text_start, game_text_end);
|
||||
ds << "}\n\n";
|
||||
@@ -1639,6 +1640,8 @@ int main(int argc, char** argv) {
|
||||
ds << " * code to the interpreter. Compare the 29-bit physical address instead;\n";
|
||||
ds << " * the table is sorted by the same masked key. */\n";
|
||||
ds << "static const PsxGameDispatchEntry* psx_game_find_entry(uint32_t addr) {\n";
|
||||
ds << " extern uint32_t psx_ram_canon_code_addr(uint32_t);\n";
|
||||
ds << " addr = psx_ram_canon_code_addr(addr);\n";
|
||||
ds << " const uint32_t want = addr & 0x1FFFFFFFu;\n";
|
||||
if (indexed_lookup) {
|
||||
ds << fmt::format(" const uint32_t offset = want - 0x{:08X}u;\n", lookup_lo);
|
||||
|
||||
@@ -146,6 +146,11 @@ if(BUILD_TESTING)
|
||||
COMMAND psx_memory_geometry_${_ram_geometry}_test)
|
||||
endforeach()
|
||||
|
||||
add_executable(psx_ram_runtime_map_test
|
||||
tests/test_psx_ram_runtime_map.c)
|
||||
target_include_directories(psx_ram_runtime_map_test PRIVATE include)
|
||||
add_test(NAME psx_ram_runtime_map_test COMMAND psx_ram_runtime_map_test)
|
||||
|
||||
add_executable(host_keymap_test
|
||||
tests/test_host_keymap.c
|
||||
src/host_keymap.c)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define PSXRECOMP_MOD_MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "psx_ram.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -34,7 +35,7 @@ static inline int psx_mod_gpu_dma_aperture_offset_for(
|
||||
}
|
||||
|
||||
/*
|
||||
* Preserve the retail DMAC's 2 MiB folding unless the address is inside the
|
||||
* Fold DMA addresses through live main RAM unless the address is inside the
|
||||
* portion of the enhancement aperture that has actually been allocated.
|
||||
*/
|
||||
static inline uint32_t psx_mod_gpu_dma_resolve_address_for(
|
||||
@@ -43,7 +44,7 @@ static inline uint32_t psx_mod_gpu_dma_resolve_address_for(
|
||||
if (psx_mod_gpu_dma_aperture_offset_for(
|
||||
canonical, 4u, used, (uint32_t *)0))
|
||||
return canonical;
|
||||
return canonical & 0x001FFFFCu;
|
||||
return psx_ram_map_read(canonical) & ~3u;
|
||||
}
|
||||
|
||||
uint32_t psx_mod_gpu_dma_memory_alloc(uint32_t size, uint32_t alignment);
|
||||
|
||||
@@ -84,6 +84,13 @@ uint32_t psx_mod_alloc_guest_memory(uint32_t size, uint32_t alignment);
|
||||
*/
|
||||
uint32_t psx_mod_alloc_gpu_dma_memory(uint32_t size, uint32_t alignment);
|
||||
|
||||
/*
|
||||
* Opt into expanded 8 MiB main RAM for this launch. Default runtime behavior
|
||||
* remains stock 2 MiB mirroring unless a trusted activation plugin requests
|
||||
* this before memory_init().
|
||||
*/
|
||||
int psx_mod_set_main_ram_8mb(int enabled);
|
||||
|
||||
/* Current per-side widescreen reveal in native game pixels (zero at 4:3). */
|
||||
int32_t psx_mod_widescreen_x_margin(void);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#endif
|
||||
#include "cpu_state.h" /* CPUState (guard-safe: cpu_state.h includes us last) */
|
||||
#include "psx_cycles.h" /* inline psx_advance_cycles */
|
||||
#include "psx_ram.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -250,7 +251,7 @@ static inline uint32_t psx_cyc_load_word(CPUState* cpu, uint32_t addr,
|
||||
cpu->ld_which_t = (uint8_t)rt;
|
||||
}
|
||||
uint32_t value;
|
||||
memcpy(&value, g_psx_ram + (phys & 0x1FFFFFu), sizeof(value));
|
||||
memcpy(&value, g_psx_ram + psx_ram_map_read(phys), sizeof(value));
|
||||
return value;
|
||||
}
|
||||
return psx_cyc_load_word_slow(cpu, addr, rt, reg_mask);
|
||||
@@ -280,7 +281,7 @@ static inline uint16_t psx_cyc_load_half(CPUState* cpu, uint32_t addr,
|
||||
cpu->ld_which_t = (uint8_t)rt;
|
||||
}
|
||||
uint16_t value;
|
||||
memcpy(&value, g_psx_ram + (phys & 0x1FFFFFu), sizeof(value));
|
||||
memcpy(&value, g_psx_ram + psx_ram_map_read(phys), sizeof(value));
|
||||
return value;
|
||||
}
|
||||
return psx_cyc_load_half_slow(cpu, addr, rt, reg_mask);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef PSX_RAM_H
|
||||
#define PSX_RAM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Retail DRAM is 2 MiB, mirrored 4x across the 8 MiB decode window. The
|
||||
* opt-in 8 MB RAM enhancement keeps an 8 MiB host backing and switches the
|
||||
* live map to unique high pages only after a trusted package requests it.
|
||||
*/
|
||||
#define PSX_RAM_2MB 0x00200000u
|
||||
#define PSX_RAM_8MB 0x00800000u
|
||||
#define PSX_RAM_CAPACITY PSX_RAM_8MB
|
||||
#define PSX_RAM_WINDOW 0x00800000u
|
||||
|
||||
extern uint32_t g_psx_ram_size;
|
||||
extern uint32_t g_psx_ram_mask;
|
||||
|
||||
uint32_t memory_get_ram_bytes(void);
|
||||
int psx_ram_8mb_active(void);
|
||||
void psx_ram_reset_size_request(void);
|
||||
|
||||
#define PSX_RAM_HIGH_PAGE0 (PSX_RAM_2MB >> 12)
|
||||
#define PSX_RAM_HIGH_PAGES ((PSX_RAM_8MB - PSX_RAM_2MB) >> 12)
|
||||
#define PSX_RAM_HIGH_BITWORDS ((PSX_RAM_HIGH_PAGES + 31u) / 32u)
|
||||
extern uint32_t g_psx_ram_high_unique[PSX_RAM_HIGH_BITWORDS];
|
||||
|
||||
static inline int psx_ram_high_page_unique(uint32_t page) {
|
||||
uint32_t i, bit;
|
||||
if (page < PSX_RAM_HIGH_PAGE0 || page >= (PSX_RAM_8MB >> 12))
|
||||
return 1;
|
||||
i = page - PSX_RAM_HIGH_PAGE0;
|
||||
bit = 1u << (i & 31u);
|
||||
return (g_psx_ram_high_unique[i >> 5] & bit) != 0;
|
||||
}
|
||||
|
||||
static inline uint32_t psx_ram_map_read(uint32_t phys) {
|
||||
phys &= 0x1FFFFFFFu;
|
||||
if (phys >= PSX_RAM_WINDOW)
|
||||
return phys;
|
||||
if (g_psx_ram_size <= PSX_RAM_2MB)
|
||||
return phys & (PSX_RAM_2MB - 1u);
|
||||
if (phys < PSX_RAM_2MB)
|
||||
return phys;
|
||||
if (psx_ram_high_page_unique(phys >> 12))
|
||||
return phys;
|
||||
return phys & (PSX_RAM_2MB - 1u);
|
||||
}
|
||||
|
||||
static inline uint32_t psx_ram_map_write(uint32_t phys) {
|
||||
return psx_ram_map_read(phys);
|
||||
}
|
||||
|
||||
static inline uint32_t psx_ram_canon_code_addr_inline(uint32_t addr) {
|
||||
uint32_t seg = addr & 0xE0000000u;
|
||||
uint32_t phys = addr & 0x1FFFFFFFu;
|
||||
if (phys < PSX_RAM_WINDOW && phys >= PSX_RAM_2MB &&
|
||||
!psx_ram_high_page_unique(phys >> 12))
|
||||
phys &= (PSX_RAM_2MB - 1u);
|
||||
return seg | phys;
|
||||
}
|
||||
|
||||
void psx_ram_register_unique(uint32_t addr, uint32_t len);
|
||||
uint32_t psx_ram_canon_code_addr(uint32_t addr);
|
||||
void psx_ram_resync_high_after_restore(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PSX_RAM_H */
|
||||
@@ -415,6 +415,7 @@ set(PSXRECOMP_RUNTIME_SOURCES
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_builtin_speed.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_builtin_pgxp.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_builtin_bezel.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_builtin_ram.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_packages.cpp
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_runtime.cpp
|
||||
${PSXRECOMP_ROOT}/runtime/src/mod_texture_banks.c
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "interrupts.h"
|
||||
#include "psx_cycles.h"
|
||||
#include "psx_icache.h" /* g_psx_icache_tv — fetch-cost tags in BS_SEC_ICACHE */
|
||||
#include "psx_ram.h"
|
||||
#include "pst_wire.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -38,7 +39,6 @@ static double boot_state_mono_ms(void) {
|
||||
/* Compress payloads at/above this size (RAM/VRAM/SPU/dirty dominate I/O). */
|
||||
#define BOOT_STATE_ZLIB_MIN 256u
|
||||
|
||||
#define RAM_SIZE (2u * 1024u * 1024u)
|
||||
#define SPAD_SIZE (1024u)
|
||||
#define VRAM_W 1024
|
||||
#define VRAM_H 512
|
||||
@@ -46,6 +46,7 @@ static double boot_state_mono_ms(void) {
|
||||
|
||||
/* ---- core accessors (existing runtime modules) ---- */
|
||||
extern uint8_t* memory_get_ram_ptr(void);
|
||||
extern uint32_t memory_get_ram_bytes(void);
|
||||
extern uint8_t* memory_get_scratchpad_ptr(void);
|
||||
extern uint32_t i_stat;
|
||||
extern uint32_t i_mask;
|
||||
@@ -377,7 +378,7 @@ static int boot_state_save_to(BsOut* o, const CPUState* cpu,
|
||||
ok = write_header_le(o, &h);
|
||||
|
||||
if (ok) ok = write_cpu_section(o, cpu);
|
||||
if (ok) ok = write_section(o, BS_SEC_RAM, memory_get_ram_ptr(), RAM_SIZE);
|
||||
if (ok) ok = write_section(o, BS_SEC_RAM, memory_get_ram_ptr(), memory_get_ram_bytes());
|
||||
if (ok) ok = write_section(o, BS_SEC_SPAD, memory_get_scratchpad_ptr(), SPAD_SIZE);
|
||||
if (ok && psx_mod_memory_snapshot_bytes())
|
||||
ok = write_module_section(o, BS_SEC_MODMEM, psx_mod_memory_snapshot_bytes,
|
||||
@@ -490,8 +491,8 @@ static int boot_state_save_buffer_ex(const CPUState* cpu, uint32_t bios_checksum
|
||||
*out_len = 0;
|
||||
memset(&o, 0, sizeof o);
|
||||
o.no_zlib = no_zlib ? 1 : 0;
|
||||
/* Compressed MotK ~1.3–1.5 MiB; raw ~3.5–4 MiB (RAM+VRAM+SPU). */
|
||||
o.cap = no_zlib ? (5u * 1024u * 1024u) : (2u * 1024u * 1024u);
|
||||
/* Compressed MotK ~1.3-1.5 MiB; raw ~3.5-4 MiB (2 MB RAM) or ~9.5 MiB (8 MB). */
|
||||
o.cap = no_zlib ? (12u * 1024u * 1024u) : (2u * 1024u * 1024u);
|
||||
o.data = (uint8_t*)malloc(o.cap);
|
||||
if (!o.data) return 0;
|
||||
if (!boot_state_save_to(&o, cpu, bios_checksum, entry_pc)) {
|
||||
@@ -544,11 +545,12 @@ static int apply_section(uint32_t tag, const uint8_t* p, uint32_t len,
|
||||
return 1;
|
||||
}
|
||||
case BS_SEC_RAM:
|
||||
if (len != RAM_SIZE) return 0;
|
||||
memcpy(memory_get_ram_ptr(), p, RAM_SIZE);
|
||||
if (len != memory_get_ram_bytes()) return 0;
|
||||
memcpy(memory_get_ram_ptr(), p, memory_get_ram_bytes());
|
||||
{
|
||||
extern void psx_kernel_bless_note_range(uint32_t phys, uint32_t l);
|
||||
psx_kernel_bless_note_range(0, RAM_SIZE);
|
||||
psx_kernel_bless_note_range(0, memory_get_ram_bytes());
|
||||
psx_ram_resync_high_after_restore();
|
||||
}
|
||||
return 1;
|
||||
case BS_SEC_SPAD:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "psx_cycles.h"
|
||||
#include "psx_icache.h"
|
||||
#include "psx_instr_cost.h" /* psx_instr_base_cycles — single-source cycle cost */
|
||||
#include "psx_ram.h"
|
||||
#include "gpu.h" /* psx_ws_is_backdrop_site / psx_ws_backdrop_x (interp hook) */
|
||||
#include "ws_backdrop_detect.h" /* shared backdrop-window detector (auto_backdrop) */
|
||||
#include "lockstep.h"
|
||||
@@ -2382,6 +2383,9 @@ static int dirty_ram_dispatch_inner(CPUState* cpu, uint32_t addr, uint32_t stop_
|
||||
int dirty_ram_dispatch(CPUState* cpu, uint32_t addr, uint32_t stop_addr) {
|
||||
extern int g_psx_dispatch_depth;
|
||||
extern void psx_fatal_halt(const char *reason);
|
||||
addr = psx_ram_canon_code_addr(addr);
|
||||
if (stop_addr != 0u)
|
||||
stop_addr = psx_ram_canon_code_addr(stop_addr);
|
||||
#ifndef PSX_NO_DEBUG_TOOLS
|
||||
/* A0/B0/C0 kernel-vector stubs are runtime-written, so calls to them
|
||||
* land HERE, not in the static dispatcher — which meant the bioscall
|
||||
|
||||
+118
-14
@@ -25,13 +25,14 @@
|
||||
#include "dirty_ram_interp.h"
|
||||
#include "guest_tty.h"
|
||||
#include "psx_cycles.h"
|
||||
#include "psx_ram.h"
|
||||
#include "starvation_ring.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define RAM_SIZE (2 * 1024 * 1024)
|
||||
#define RAM_SIZE PSX_RAM_CAPACITY
|
||||
#define SCRATCHPAD_SIZE 1024
|
||||
#define BIOS_ROM_SIZE (512 * 1024)
|
||||
#define MOD_MEMORY_BASE 0x1F000000u
|
||||
@@ -44,6 +45,66 @@ static uint8_t mod_memory[MOD_MEMORY_SIZE];
|
||||
static uint32_t mod_memory_used;
|
||||
static uint8_t mod_gpu_dma_memory[PSX_MOD_GPU_DMA_APERTURE_SIZE];
|
||||
static uint32_t mod_gpu_dma_memory_used;
|
||||
static int s_ram_8mb_requested;
|
||||
|
||||
uint32_t g_psx_ram_size = PSX_RAM_2MB;
|
||||
uint32_t g_psx_ram_mask = PSX_RAM_2MB - 1u;
|
||||
static uint32_t s_ram_high_registered[PSX_RAM_HIGH_BITWORDS];
|
||||
uint32_t g_psx_ram_high_unique[PSX_RAM_HIGH_BITWORDS];
|
||||
|
||||
static inline void psx_ram_high_page_mark(uint32_t page) {
|
||||
uint32_t i, bit;
|
||||
if (page < PSX_RAM_HIGH_PAGE0 || page >= (PSX_RAM_8MB >> 12))
|
||||
return;
|
||||
i = page - PSX_RAM_HIGH_PAGE0;
|
||||
bit = 1u << (i & 31u);
|
||||
g_psx_ram_high_unique[i >> 5] |= bit;
|
||||
s_ram_high_registered[i >> 5] |= bit;
|
||||
}
|
||||
|
||||
static void psx_ram_apply_registered_bitmap(void) {
|
||||
memcpy(g_psx_ram_high_unique, s_ram_high_registered,
|
||||
sizeof(g_psx_ram_high_unique));
|
||||
}
|
||||
|
||||
void psx_ram_register_unique(uint32_t addr, uint32_t len) {
|
||||
uint32_t phys, end, page, last;
|
||||
if (len == 0u)
|
||||
return;
|
||||
phys = addr & 0x1FFFFFFFu;
|
||||
if (phys >= PSX_RAM_WINDOW)
|
||||
return;
|
||||
end = phys + len;
|
||||
if (end < phys || end > PSX_RAM_WINDOW)
|
||||
end = PSX_RAM_WINDOW;
|
||||
if (end <= PSX_RAM_2MB)
|
||||
return;
|
||||
if (phys < PSX_RAM_2MB)
|
||||
phys = PSX_RAM_2MB;
|
||||
page = phys >> 12;
|
||||
last = (end - 1u) >> 12;
|
||||
for (; page <= last; page++)
|
||||
psx_ram_high_page_mark(page);
|
||||
}
|
||||
|
||||
uint32_t psx_ram_canon_code_addr(uint32_t addr) {
|
||||
return psx_ram_canon_code_addr_inline(addr);
|
||||
}
|
||||
|
||||
void psx_ram_resync_high_after_restore(void) {
|
||||
uint32_t page;
|
||||
psx_ram_apply_registered_bitmap();
|
||||
if (g_psx_ram_size <= PSX_RAM_2MB)
|
||||
return;
|
||||
for (page = PSX_RAM_HIGH_PAGE0; page < (PSX_RAM_8MB >> 12); page++) {
|
||||
uint32_t dst = page << 12;
|
||||
uint32_t src = dst & (PSX_RAM_2MB - 1u);
|
||||
if (psx_ram_high_page_unique(page))
|
||||
continue;
|
||||
if (memcmp(ram + dst, ram + src, 4096u) != 0)
|
||||
psx_ram_high_page_mark(page);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t psx_mod_memory_snapshot_bytes(void) {
|
||||
return mod_memory_used || mod_gpu_dma_memory_used
|
||||
@@ -139,22 +200,63 @@ uint8_t *g_psx_ram = ram;
|
||||
/* PSX_LOAD_DELAY gate (default on). −1 = unread; 0/1 after first resolve. */
|
||||
int g_psx_load_delay = -1;
|
||||
|
||||
/* Physical address translation for guest accesses. The 2 MB main RAM is
|
||||
* mirrored 4x across the first 8 MB of each segment (mem-ctrl RAM_SIZE
|
||||
* register, default 0x0B88) and games rely on it — Kula World's crt0
|
||||
* parks $sp in the 4th mirror (0x807FFFF8). Fold the mirrors here so the
|
||||
* RAM bounds checks below see canonical offsets; without this, mirror
|
||||
* writes fell into the open-bus no-op and mirror reads returned 0 (the
|
||||
* guest's stack silently vanished and $ra came back as 0). */
|
||||
/* Physical address translation for guest accesses. Retail 2 MB DRAM is
|
||||
* mirrored across the first 8 MB of each segment; the opt-in 8 MB mode maps
|
||||
* registered high pages uniquely and keeps unregistered high pages aliased. */
|
||||
static inline uint32_t psx_phys_addr(uint32_t addr) {
|
||||
uint32_t phys = addr & 0x1FFFFFFFu;
|
||||
if (phys < 0x00800000u) phys &= (uint32_t)(RAM_SIZE - 1);
|
||||
if (phys < PSX_RAM_WINDOW) phys = psx_ram_map_read(phys);
|
||||
return phys;
|
||||
}
|
||||
|
||||
static inline uint32_t psx_phys_addr_store(uint32_t addr) {
|
||||
uint32_t phys = addr & 0x1FFFFFFFu;
|
||||
if (phys < PSX_RAM_WINDOW) phys = psx_ram_map_write(phys);
|
||||
return phys;
|
||||
}
|
||||
|
||||
/* Expose RAM pointer for oracle comparison (find_first_divergence). */
|
||||
uint8_t *memory_get_ram_ptr(void) { return ram; }
|
||||
uint8_t *memory_get_scratchpad_ptr(void) { return scratchpad; }
|
||||
uint32_t memory_get_ram_bytes(void) { return g_psx_ram_size; }
|
||||
int psx_ram_8mb_active(void) { return g_psx_ram_size > PSX_RAM_2MB; }
|
||||
|
||||
void psx_ram_reset_size_request(void) {
|
||||
s_ram_8mb_requested = 0;
|
||||
memset(s_ram_high_registered, 0, sizeof(s_ram_high_registered));
|
||||
memset(g_psx_ram_high_unique, 0, sizeof(g_psx_ram_high_unique));
|
||||
}
|
||||
|
||||
int psx_mod_set_main_ram_8mb(int enabled) {
|
||||
s_ram_8mb_requested = enabled ? 1 : 0;
|
||||
memset(s_ram_high_registered, 0, sizeof(s_ram_high_registered));
|
||||
memset(g_psx_ram_high_unique, 0, sizeof(g_psx_ram_high_unique));
|
||||
if (enabled)
|
||||
psx_ram_register_unique(PSX_RAM_2MB, PSX_RAM_8MB - PSX_RAM_2MB);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int psx_ram_any_high_registered(void) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < PSX_RAM_HIGH_BITWORDS; i++) {
|
||||
if (s_ram_high_registered[i] != 0u)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psx_ram_apply_size_request(void) {
|
||||
if (s_ram_8mb_requested) {
|
||||
g_psx_ram_size = PSX_RAM_8MB;
|
||||
g_psx_ram_mask = PSX_RAM_8MB - 1u;
|
||||
if (!psx_ram_any_high_registered())
|
||||
psx_ram_register_unique(PSX_RAM_2MB, PSX_RAM_8MB - PSX_RAM_2MB);
|
||||
} else {
|
||||
g_psx_ram_size = PSX_RAM_2MB;
|
||||
g_psx_ram_mask = PSX_RAM_2MB - 1u;
|
||||
memset(g_psx_ram_high_unique, 0, sizeof(g_psx_ram_high_unique));
|
||||
}
|
||||
}
|
||||
|
||||
void memory_clear_low_boot_scratch(void) {
|
||||
memset(ram, 0, 0x10u);
|
||||
@@ -771,6 +873,7 @@ uint32_t dirty_ram_get_bitmap_word_count(void) {
|
||||
}
|
||||
|
||||
void dirty_ram_set_bitmap_words(const uint32_t* words, uint32_t count) {
|
||||
memset(dirty_ram_bitmap, 0, sizeof(dirty_ram_bitmap));
|
||||
if (count > DIRTY_RAM_BITMAP_WORDS) count = DIRTY_RAM_BITMAP_WORDS;
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
dirty_ram_bitmap[i] = words[i];
|
||||
@@ -1103,6 +1206,7 @@ static uint32_t s_bios_checksum = 0;
|
||||
uint32_t memory_get_bios_checksum(void) { return s_bios_checksum; }
|
||||
|
||||
void memory_init(const char* bios_path) {
|
||||
psx_ram_apply_size_request();
|
||||
memset(ram, 0, sizeof(ram));
|
||||
memset(scratchpad, 0, sizeof(scratchpad));
|
||||
/* Rematch re-enters without process exit — wipe sticky I/O regs that
|
||||
@@ -1712,7 +1816,7 @@ static void psx_write_word_raw(uint32_t addr, uint32_t val) {
|
||||
* We have no cache model, so silently discard RAM/scratchpad writes. */
|
||||
if (sr_ptr && (*sr_ptr & 0x10000u)) return;
|
||||
|
||||
uint32_t phys = psx_phys_addr(addr);
|
||||
uint32_t phys = psx_phys_addr_store(addr);
|
||||
|
||||
/* The generated BIOS mirrors its exception trampoline to 0x80000000 during
|
||||
* boot. On hardware this mirror copy is not visible in RAM; only the real
|
||||
@@ -1906,7 +2010,7 @@ static void psx_write_half_raw(uint32_t addr, uint16_t val) {
|
||||
|
||||
/* KSEG2 guard — see psx_read_word_raw. */
|
||||
if (addr >= 0xC0000000u) { g_kseg2_ignored_writes++; return; }
|
||||
uint32_t phys = psx_phys_addr(addr);
|
||||
uint32_t phys = psx_phys_addr_store(addr);
|
||||
|
||||
if (phys < RAM_SIZE) {
|
||||
debug_server_trace_write_check(phys, (uint32_t)read_ram_half(phys), (uint32_t)val, 2);
|
||||
@@ -2166,10 +2270,10 @@ static inline int psx_cyc_main_ram_fast_addr(uint32_t addr, uint32_t width,
|
||||
return 0;
|
||||
uint32_t phys = addr & 0x1FFFFFFFu;
|
||||
if (phys >= 0x00800000u) return 0;
|
||||
phys &= (uint32_t)(RAM_SIZE - 1);
|
||||
phys = psx_ram_map_read(phys);
|
||||
/* Aligned guest loads cannot cross this boundary, but fail closed for a
|
||||
* malformed/unaligned caller instead of introducing a host OOB read. */
|
||||
if (phys > (uint32_t)RAM_SIZE - width) return 0;
|
||||
if (phys > g_psx_ram_size - width) return 0;
|
||||
*phys_out = phys;
|
||||
return 1;
|
||||
}
|
||||
@@ -2241,7 +2345,7 @@ static void psx_write_byte_raw(uint32_t addr, uint8_t val) {
|
||||
|
||||
/* KSEG2 guard — see psx_read_word_raw. */
|
||||
if (addr >= 0xC0000000u) { g_kseg2_ignored_writes++; return; }
|
||||
uint32_t phys = psx_phys_addr(addr);
|
||||
uint32_t phys = psx_phys_addr_store(addr);
|
||||
|
||||
if (phys < RAM_SIZE) {
|
||||
debug_server_trace_write_check(phys, (uint32_t)ram[phys], (uint32_t)val, 1);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Framework-owned opt-in 8 MB main RAM.
|
||||
*
|
||||
* Retail PS1 DRAM is 2 MiB mirrored four times across 0x00000000-0x007FFFFF.
|
||||
* Some enhancement patches use the upper part of that window as real RAM.
|
||||
*/
|
||||
#include "mod_plugins.h"
|
||||
|
||||
static void builtin_8mb_ram_activate(void) {
|
||||
(void)psx_mod_set_main_ram_8mb(1);
|
||||
}
|
||||
|
||||
PSX_MOD_CONSTRUCTOR(psx_register_builtin_ram_plugins) {
|
||||
(void)psx_mod_register_activation_plugin(
|
||||
"psx.8mb-ram", builtin_8mb_ram_activate);
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "mod_packages.h"
|
||||
#include "mod_plugins.h"
|
||||
#include "gpu.h"
|
||||
#include "psx_ram.h"
|
||||
#include "psx_sha256.h"
|
||||
|
||||
#if defined(RECOMP_LAUNCHER)
|
||||
@@ -1337,6 +1338,7 @@ extern "C" int psx_mod_read_disc_file(const char* path, void* buffer,
|
||||
extern "C" void mod_runtime_activate_plugins(void) {
|
||||
using namespace PSXRecompV4;
|
||||
RuntimeMods& s = state();
|
||||
psx_ram_reset_size_request();
|
||||
if (!s.initialized || !s.plan.ok) return;
|
||||
for (const ModResolution::Plugin& plugin : s.plan.plugins) {
|
||||
s.current_plugin = &plugin;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
|
||||
extern uint8_t* memory_get_ram_ptr(void);
|
||||
extern uint32_t memory_get_ram_bytes(void);
|
||||
extern uint32_t i_stat;
|
||||
extern uint32_t i_mask;
|
||||
extern void timers_get_snapshot(uint16_t counter[3], uint32_t mode[3],
|
||||
@@ -55,8 +56,6 @@ static uint32_t digest_module(uint32_t (*bytes_fn)(void), void (*write_fn)(uint8
|
||||
return crc32_compute(buf, n);
|
||||
}
|
||||
|
||||
#define NP_RAM_SIZE (2u * 1024u * 1024u)
|
||||
|
||||
uint32_t netplay_cdrom_digest(void)
|
||||
{
|
||||
static uint8_t *buf;
|
||||
@@ -159,7 +158,7 @@ void netplay_core_digest_parts(const CPUState* cpu, NetplayCoreParts* out)
|
||||
|
||||
ram = memory_get_ram_ptr();
|
||||
if (ram)
|
||||
crc_ram = crc32_update(crc_ram, ram, NP_RAM_SIZE);
|
||||
crc_ram = crc32_update(crc_ram, ram, memory_get_ram_bytes());
|
||||
|
||||
wc = dirty_ram_get_bitmap_word_count();
|
||||
for (i = 0; i < wc; i++) {
|
||||
|
||||
@@ -60,6 +60,7 @@ extern "C" uint32_t psx_mod_memory_alloc(uint32_t, uint32_t) { return 0; }
|
||||
extern "C" uint32_t psx_mod_gpu_dma_memory_alloc(uint32_t, uint32_t) {
|
||||
return 0;
|
||||
}
|
||||
extern "C" void psx_ram_reset_size_request(void) {}
|
||||
extern "C" int psx_ws_x_margin(void) { return 0; }
|
||||
|
||||
/* Stand-in for the GPU's display geometry. psx_mod_display_width/height must
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "psx_ram.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
uint32_t g_psx_ram_size = PSX_RAM_2MB;
|
||||
uint32_t g_psx_ram_mask = PSX_RAM_2MB - 1u;
|
||||
uint32_t g_psx_ram_high_unique[PSX_RAM_HIGH_BITWORDS];
|
||||
|
||||
static int check(int cond, const char *label) {
|
||||
if (!cond) {
|
||||
fprintf(stderr, "FAIL: %s\n", label);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
const uint32_t high = 0x00201000u;
|
||||
const uint32_t high_page = high >> 12;
|
||||
uint32_t i = high_page - PSX_RAM_HIGH_PAGE0;
|
||||
int ok = 1;
|
||||
|
||||
ok &= check(psx_ram_map_read(high) == 0x00001000u,
|
||||
"retail maps high mirror to low RAM");
|
||||
ok &= check(psx_ram_canon_code_addr_inline(0x80201000u) == 0x80001000u,
|
||||
"retail folds high code PC to low mirror");
|
||||
|
||||
g_psx_ram_size = PSX_RAM_8MB;
|
||||
g_psx_ram_mask = PSX_RAM_8MB - 1u;
|
||||
ok &= check(psx_ram_map_read(high) == 0x00001000u,
|
||||
"unregistered 8 MB high page still mirrors low RAM");
|
||||
|
||||
g_psx_ram_high_unique[i >> 5] |= 1u << (i & 31u);
|
||||
ok &= check(psx_ram_map_read(high) == high,
|
||||
"registered 8 MB high page maps uniquely");
|
||||
ok &= check(psx_ram_canon_code_addr_inline(0x80201000u) == 0x80201000u,
|
||||
"registered high code PC remains unique");
|
||||
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user