mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Merge bug/memory-card-ape-escape-tomba-2: memcard write-handshake + RAM-0 store visibility (Tomba 2 saves; cross-title gate Ape/Tomba/MMX6 passed)
This commit is contained in:
@@ -113,7 +113,9 @@ void fntrace_record(CPUState* cpu, uint32_t target) {
|
||||
* later overlay overwrites, so the dispatch runs clean text compiled and
|
||||
* interprets only true overlays (Tomba 2 boot-text loader overlay). */
|
||||
extern void dirty_ram_clear_image_baseline(void);
|
||||
extern void memory_clear_low_boot_scratch(void);
|
||||
dirty_ram_clear_image_baseline();
|
||||
memory_clear_low_boot_scratch();
|
||||
cdrom_notify_game_started();
|
||||
boot_state_trigger_capture(cpu);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "cdrom.h"
|
||||
#include "crash_trace.h"
|
||||
#include "dma.h"
|
||||
#include "fntrace.h"
|
||||
#include "gpu.h"
|
||||
#include "mdec.h"
|
||||
#include "sio.h"
|
||||
@@ -49,6 +50,10 @@ static inline uint32_t psx_phys_addr(uint32_t addr) {
|
||||
uint8_t *memory_get_ram_ptr(void) { return ram; }
|
||||
uint8_t *memory_get_scratchpad_ptr(void) { return scratchpad; }
|
||||
|
||||
void memory_clear_low_boot_scratch(void) {
|
||||
memset(ram, 0, 0x10u);
|
||||
}
|
||||
|
||||
/* ---- Dirty-page tracking for install-at-runtime code (CLAUDE.md Rule 18) ----
|
||||
*
|
||||
* The PS1 BIOS writes 4-instruction dispatch stubs into kernel RAM at runtime
|
||||
@@ -1096,7 +1101,59 @@ static void psx_write_word_raw(uint32_t addr, uint32_t val) {
|
||||
|
||||
uint32_t phys = psx_phys_addr(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
|
||||
* exception vector at 0x80000080 is. Tomba 2 later passes buffer=0 to the
|
||||
* BIOS card write routine, so stale mirror bytes at 0 corrupt the sector 63
|
||||
* management write and leave the load menu stuck checking the card. */
|
||||
if (fntrace_is_game_started() &&
|
||||
phys < 0x10u && g_debug_last_store_pc == 0xBFC10A00u) return;
|
||||
|
||||
/* BIOS helpers use RAM address zero as a tiny delay-loop scratch between
|
||||
* device-register polls. Treat these two dummy stores as non-visible; real
|
||||
* hardware / Beetle preserve Tomba 2's sector-63 card-management payload
|
||||
* when it passes buffer=0 to _card_write. */
|
||||
if (fntrace_is_game_started() && phys == 0u) {
|
||||
switch (g_debug_last_store_pc) {
|
||||
case 0xBFC04E90u:
|
||||
case 0xBFC04EF0u:
|
||||
case 0xBFC05164u:
|
||||
case 0xBFC0D634u:
|
||||
case 0xBFC3EEB4u:
|
||||
case 0xBFC405E4u:
|
||||
case 0xBFC40788u:
|
||||
case 0xBFC41C50u:
|
||||
case 0x80012434u:
|
||||
case 0x800125ACu:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (phys < RAM_SIZE) {
|
||||
/* Tomba 2 load-game card check: the BIOS card-manager cleanup helper
|
||||
* at kernel RAM 0x1C5C scans MARK events and re-arms any READY event
|
||||
* matching F0000011/{4,8000,100,200,2000}. In the recomp timing path it
|
||||
* can run after the card completion DeliverEvent but before the game's
|
||||
* TestEvent poll, consuming the public card event and leaving the UI
|
||||
* stuck at "Checking MEMORY CARD...". Let the real TestEvent consume
|
||||
* public MARK card events instead; keep this narrowly keyed to the
|
||||
* helper's status store and the EvCB layout. */
|
||||
if (fntrace_is_game_started() &&
|
||||
g_debug_last_store_pc == 0xBFC117E4u &&
|
||||
val == 0x2000u &&
|
||||
phys >= 4u && (phys + 8u) < RAM_SIZE &&
|
||||
read_ram_word(phys) == 0x4000u &&
|
||||
read_ram_word(phys - 4u) == 0xF0000011u &&
|
||||
read_ram_word(phys + 8u) == 0x2000u) {
|
||||
uint32_t spec = read_ram_word(phys + 4u);
|
||||
if (spec == 0x00000004u || spec == 0x00008000u ||
|
||||
spec == 0x00000100u || spec == 0x00000200u ||
|
||||
spec == 0x00002000u) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (phys == D44_PHYS) d44_note(phys, read_ram_word(phys), val);
|
||||
debug_server_trace_write_check(phys, read_ram_word(phys), val, 4);
|
||||
parity_trace_note_write(phys, 4, effective_store_pc());
|
||||
|
||||
+18
-3
@@ -127,6 +127,7 @@ typedef enum {
|
||||
MC_READ_CHK,
|
||||
MC_READ_END,
|
||||
/* Write states */
|
||||
MC_WRITE_LSB_ECHO, /* rx = sector_lsb while accepting first data byte */
|
||||
MC_WRITE_DATA,
|
||||
MC_WRITE_CHK,
|
||||
MC_WRITE_ACK1,
|
||||
@@ -1066,11 +1067,17 @@ static void mc_process_byte(uint8_t tx_byte) {
|
||||
for (int i = 0; i < 128; i++)
|
||||
mc_checksum ^= mc_data[i];
|
||||
mc_state = MC_READ_ACK1;
|
||||
sio_rx_data = 0x00;
|
||||
} else {
|
||||
mc_data_idx = 0;
|
||||
mc_state = MC_WRITE_DATA;
|
||||
mc_state = MC_WRITE_LSB_ECHO;
|
||||
/* Hardware/Beetle echo the high address byte on the address-LSB
|
||||
* transfer (zero for all 1Mbit card sectors), then echo the low
|
||||
* address byte while receiving the first payload byte. Some BIOS
|
||||
* card-write paths validate this handshake before they schedule the
|
||||
* follow-up directory reads. */
|
||||
sio_rx_data = mc_sector_msb;
|
||||
}
|
||||
sio_rx_data = 0x00;
|
||||
sio_stat |= SIO_STAT_ACK;
|
||||
break;
|
||||
|
||||
@@ -1135,6 +1142,13 @@ static void mc_process_byte(uint8_t tx_byte) {
|
||||
}
|
||||
|
||||
/* ---- WRITE states ---- */
|
||||
case MC_WRITE_LSB_ECHO:
|
||||
mc_data[mc_data_idx++] = tx_byte;
|
||||
mc_state = MC_WRITE_DATA;
|
||||
sio_rx_data = mc_sector_lsb;
|
||||
sio_stat |= SIO_STAT_ACK;
|
||||
break;
|
||||
|
||||
case MC_WRITE_DATA:
|
||||
mc_data[mc_data_idx++] = tx_byte;
|
||||
sio_rx_data = 0x00;
|
||||
@@ -1313,7 +1327,8 @@ static void sio_process_byte(uint8_t tx_byte) {
|
||||
/* ---- Card transaction tracking: record + maybe-close ---- */
|
||||
if (txn_was_card_byte && sio_txn_open) {
|
||||
int got_ack = (sio_mc_ack_count > trace_ack_before) ? 1 : 0;
|
||||
uint16_t sector_now = (mc_state >= MC_READ_ACK1 || mc_state == MC_WRITE_DATA
|
||||
uint16_t sector_now = (mc_state >= MC_READ_ACK1 || mc_state == MC_WRITE_LSB_ECHO
|
||||
|| mc_state == MC_WRITE_DATA
|
||||
|| mc_state >= MC_WRITE_ACK1)
|
||||
? mc_sector : 0xFFFF;
|
||||
txn_record_byte(tx_byte, sio_rx_data, mc_cmd, sector_now,
|
||||
|
||||
Reference in New Issue
Block a user