Adds recomp::mirror_rom_to_kseg1(rdram) that copies the loaded ROM
into rdram + 0x30000000 with XOR-3-byte-swapped storage so direct
MIPS reads of cart vaddrs return the expected bytes.
Why:
The recompiler's MEM_W formula maps kseg1 vaddrs into the second
512 MiB of the rdram allocation:
MEM_W(addr) = *(int32_t*)(rdram + (addr - 0xFFFFFFFF80000000))
For addr=0xB0000000, that's rdram + 0x30000000. Previously, ROM
bytes were only available via osPiStartDma -> do_rom_read; direct
reads of cart vaddrs (e.g. `lw $t0, 0xE38($t9)` with $t9=0xB000_0000)
hit never-written rdram and returned garbage.
Visible symptom:
Pokemon Stadium's Game_DoCopyProtection at 0x80028FA0 reads
*(u32*)0xB0000E38 and compares the low 16 bits against 0x828A.
Without the mirror that read returned 0, the magic check tripped,
and the function returned -0x10 = 0xFFFFFFF0 — a sentinel state
that the main state-machine switch doesn't handle. Title screen
flashed for 1-2 frames then reverted to intro on every run.
After the fix: copyprot returns input state unchanged, title
screen stays up cleanly. Verified via Stadium harness:
gCurrentGameState transitions 0x01 -> 0x02 and stays there
through 25s of idle with zero copyprot trips logged.
Generality:
Any N64 game with a ROM-checksum / magic-word check (Stadium,
many original-IP games, anti-piracy code in others) needs this.
CIC-NUS-6103 / 6105 / 6106 boot also reads ROM via virtual
addresses. The mirror is install-once at game-start time, after
load_stored_rom populates the rom vector.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .github/workflows | ||
| librecomp | ||
| N64Recomp@81213c1831 | ||
| thirdparty | ||
| ultramodern | ||
| .gitignore | ||
| .gitmodules | ||
| CMakeLists.txt | ||
| COPYING | ||
| README.md | ||
N64 Modern Runtime
A modern runtime for traditional ports and recompilations of N64 games.
The runtime is consists of two libraries: ultramodern and librecomp.
ultramodern
ultramodern is a reimplementation of much of the core functionality of libultra. It can be used with either statically recompiled projects that use N64Recomp or direct source ports. It implements the following libultra functionality:
- Threads
- Controllers
- Audio
- Message Queues
- Timers
- RSP Task Handling
- VI timing
Platform-specific I/O is handled via callbacks that are provided by the project using ultramodern. This includes reading from controllers and playing back audio samples.
ultramodern expects the user to provide and register a graphics renderer. The recommended one is RT64.
librecomp
librecomp is a library meant to be used to bridge the gap between code generated by N64Recomp and ultramodern. It provides wrappers to allow recompiled code to call ultramodern. Librecomp also provides some of the remaining libultra functionality that ultramodern doesn't provide, which includes:
- Overlay handling
- PI DMA (ROM reads)
- EEPROM, SRAM and Flashram saving (these may be partially moved to ultramodern in the future)
Building
The recommended usage of these libraries is to include them in your project's CMakeLists.txt file via add_subdirectory. This project requires C++20 support and was developed using Clang 15, older versions of clang may not work. Recent enough versions of MSVC and GCC should work as well, but are not regularly tested.
These libraries can be built in a standalone environment (ie, developing new features for the libraries of this project) via the following:
cmake -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug
cmake --build build