⚠️ Clean-Room / Educational

This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.

DMA/HRAM Transfer Interceptor

Date:2025-12-22 StepID:0245 State: draft

Summary

The Sentinel (Step 0244) confirmed that the game writes the score0xFDinHRAM (0xFF8D), but then he desperately searches for it inWRAM, causing an infinite loop. Missing link: Who moves data from HRAM to WRAM? A transfer interceptor is implemented that monitors writes to the DMA register (0xFF46) and reads in HRAM (0xFF8D) to determine if the game attempts to use DMA or a manual copy routine.

Hardware Concept

DMA (Direct Memory Access): The Game Boy has a DMA register (0xFF46) that allows you to copy 160 bytes of data from any memory address to the OAM (Object Attribute Memory,0xFE00-0xFE9F). When the game writes a byte to0xFF46, the hardware automatically initiates a transfer from the address(value × 0x100)to OAM. For example, write0xFEin0xFF46initiate a transfer from0xFE00to OAM.

Manual Memory Transfers: In addition to DMA, programs can use manual copy instructions such asLDI(Load Increment) orLDD(Load Decrement) to move data between memory areas. These instructions copy one byte from the address pointed to byH.L.to the address indicated byOF, incrementing or decrementing both pointers.

The Missing Link Problem: Step 0244 confirmed that:

  • The game writes0xFDin HRAM (0xFF8D).
  • The game searches0xFDin WRAM (0xCxxx).
  • The marker never appears in WRAM, causing an infinite loop.

This suggests that there is adata transferwhich should happen between writing to HRAM and searching to WRAM, but it is not working. The possibilities are:

  • Option A: The game tries to use DMA to copy data, but our DMA implementation is not working or is not copying to the correct address.
  • Option B: The game uses a manual copy routine (LDI/LDD) that reads from HRAM and writes to WRAM, but the read or write fails silently.
  • Option C: The game wrote to HRAM but never tried to copy the data (previous issue in initialization logic).

Hetransfer interceptorimplements two critical points:

  • DMA register (0xFF46): Detects if the game tries to trigger a DMA transfer.
  • HRAM (0xFF8D): Detects if someone tries to read the marker from HRAM (which would be necessary to copy it to WRAM).

Fountain: Pan Docs - "DMA Transfer", "OAM DMA", "High RAM (HRAM)", "Memory Map"

Implementation

Two instrumentation blocks are added to the MMU: one inMMU::readto detect reads in HRAM (0xFF8D) and another inMMU::writeto detect writes to the DMA register (0xFF46). Additionally, an automatic analysis script is created to process the logs and generate a structured summary.

Modified components

  • src/core/cpp/MMU.cpp: Added instrumentation blocks inMMU::read(HRAM) andMMU::write(DMA).
  • tools/analyze_dma_0245.py: Automatic analysis script to process logs and generate summary.

Code added in MMU::read

// --- Step 0245: HRAM READ WATCHDOG ---
// The Sentinel (Step 0244) confirmed that the game writes 0xFD to HRAM (0xFF8D),
// but then looks for it in WRAM. We need to know if someone is trying to read 0xFF8D
// to copy that data to WRAM. If no one reads 0xFF8D, no one can copy the marker.
// Source: Pan Docs - "High RAM (HRAM)", "Memory Map"
if (addr == 0xFF8D) {
    printf("[HRAM] Read detected on FF8D! PC could be copying data.\n");
}
// -----------------------------------------

Code added in MMU::write

// --- Step 0245: DMA INTERCEPTOR ---
// The Sentinel (Step 0244) confirmed that the game writes 0xFD to HRAM (0xFF8D),
// but then looks for it in WRAM. We need to know if the game tries to activate
// a DMA transfer to move data from HRAM to WRAM.
// DMA register (0xFF46) is written with the high byte of the source address
// (ex: writing 0xFE starts a transfer from 0xFE00).
// Source: Pan Docs - "DMA Transfer", "OAM DMA"
if (addr == 0xFF46) {
    printf("[DMA] Write to DMA Register (FF46)! Value: %02X (Source: %04X00)\n", value, value);
}
// -----------------------------------------

Automatic Analysis Script

The script is createdtools/analyze_dma_0245.pythat:

  • Analyze the emulator logs looking for DMA and HRAM events.
  • Generates event statistics (total, distribution, correlation).
  • Provides hypotheses and conclusions based on the findings.

Using the script:

#1. Run the emulator and redirect the output to a log
python main.py roms/tetris.gb > dma_check.log 2>&1

#2. Analyze the log and generate the summary
python tools/analyze_dma_0245.py dma_check.log > SUMMARY_DMA_0245.txt

Design decisions

  • Selective instrumentation: Only critical directions are instrumented (0xFF46and0xFF8D) to minimize overhead and maintain emulator speed.
  • Message format: Messages use prefixes[DMA]and[HRAM]to facilitate its search in the logs.
  • Automatic analysis: The analysis script processes the logs in a structured way, allowing patterns and correlations to be identified without manually reviewing thousands of lines.

Affected Files

  • src/core/cpp/MMU.cpp- Added instrumentation blocks inMMU::read(HRAM) andMMU::write(DMA).
  • tools/analyze_dma_0245.py- Automatic analysis script to process logs and generate summary.
  • docs/bitacora/entries/2025-12-22__0245__interceptor-dma-hram.html- Log entry.
  • docs/bitacora/index.html- Updated with new entry.
  • REPORT_PHASE_2.md- Updated with Step 0245.

Tests and Verification

Verification is carried out by running the emulator and analyzing logs:

  1. Recompilation: Recompile the C++ extension with the new instrumentation:
    python setup.py build_ext --inplace
  2. Execution with logging: Run the emulator for 10 seconds and redirect the output:
    python main.py roms/tetris.gb > dma_check.log 2>&1
  3. Automatic analysis: Process the log with the analysis script:
    python tools/analyze_dma_0245.py dma_check.log > SUMMARY_DMA_0245.txt
  4. Interpretation of results:
    • If DMA events are detected: The game DOES try to use DMA, but the transfer fails.
    • If HRAM reads are detected: The game DOES try to read the marker, but the copy fails.
    • If nothing is detected: The game wrote to HRAM but never attempted to transfer the data.

C++ Compiled Module Validation: The instrumentation is implemented directly in C++, so it requires recompilation of the extension. Log messages are generated at run time and captured to standard output.

Sources consulted

Educational Integrity

What I Understand Now

  • DMA on Game Boy: The DMA register (0xFF46) allows you to copy 160 bytes from any address to OAM. However, real hardware only copies to OAM, not other memory areas. If the game tries to use DMA to copy from HRAM to WRAM, this will not work on real hardware (unless there is a manual copy routine that reads from OAM after the DMA transfer).
  • Manual Transfers:The instructionsLDIandLDDThey allow data to be copied byte by byte between memory areas. These instructions are slower than DMA but more flexible.
  • The Missing Link: If the game writes to HRAM and searches to WRAM, there must be an intermediate transfer. If we don't detect DMA or HRAM reads, it's possible that the game is using a copy routine that we're not instrumenting, or there's an upstream issue preventing the game from reaching the copy routine.

What remains to be confirmed

  • Does the game use DMA?: We need to run the emulator and analyze the logs to confirm if the game tries to activate DMA.
  • Does the game read HRAM?: We need to confirm if anyone tries to read0xFF8Dto copy the bookmark.
  • Is there a manual copy routine?: If we do not detect DMA or HRAM reads, it is possible that the game uses a copy routine that we are not instrumenting (for example, a routine that reads from a different address or that uses a copy method that we do not detect).

Hypotheses and Assumptions

Main assumption: We assume that if the game attempts to transfer data from HRAM to WRAM, it will do so via DMA or via a manual copy routine that reads from HRAM. However, it is possible that the game uses a different method (for example, a routine that reads from a different address or uses a copy method that we did not detect).

Instrumentation limitation: We only instrument two critical points (DMA and HRAM). If the game uses a copy routine that does not go through these points, we will not detect it. In that case, we would need to instrument more areas or use a different approach (for example, a write tracker in WRAM that detects when writing0xFDin WRAM).

Next Steps

  • [ ] Recompile the C++ extension:python setup.py build_ext --inplace
  • [ ] Run the emulator for 10 seconds:python main.py roms/tetris.gb > dma_check.log 2>&1
  • [ ] Analyze the log:python tools/analyze_dma_0245.py dma_check.log > SUMMARY_DMA_0245.txt
  • [ ] If DMA events are detected: Investigate why the DMA transfer fails (check DMA implementation, destination address, etc.).
  • [ ] If HRAM readings are detected: Investigate why the manual copy fails (check LDI/LDD instructions, Echo RAM redirection, etc.).
  • [ ] If nothing is detected: Instrument more areas (e.g. write tracer in WRAM) or investigate the game's initialization logic to find where the transfer is supposed to happen.