⚠️ 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.

Global VRAM Access Monitor and Load Routine Search

Date:2025-12-25 StepID:0295 State: VERIFIED

Summary

Implemented five global monitors to track ALL VRAM accesses no matter where they occur in the execution flow. The analysis of Step 0294 partially rejected the hypothesis: the ISRs execute but do not access VRAM, and the post-BG code does not access either. We need to determine if the loading code exists and when it should be executed, or if it simply does not exist at this stage of the game.

The new monitors detect VRAM accesses at any time in the flow, correlate PCs with VRAM accesses, identify sequences consecutive loading times, detect copies from ROM using LDIR, and track the timing of VRAM accesses.

Hardware Concept

Video RAM (VRAM) and Tiles Loading

VRAM (0x8000-0x9FFF) contains two types of data:

  • Tile Data (0x8000-0x97FF): 384 tiles of 8x8 pixels, each tile occupies 16 bytes (2 bytes per row of 8 pixels).
  • Tile Maps (0x9800-0x9FFF): Two tile maps that indicate which tile is displayed at each position on the screen.

Tiles are typically loaded from cartridge ROM to VRAM using block instructions such asLDIR(Load, Increment, Repeat), which copies a sequence of bytes from a source address (ROM) to a destination address (VRAM).

Tile Loading Patterns

Games load tiles using several methods:

  1. LDIR (0xED 0xB0): Most common pattern. Copy (HL++) to (DE++), decrement BC, repeat until BC=0.
  2. Manual Loops: LD A,(HL) ; LD (DE),A ; INC HL ; INC DE ; DEC BC ; JR NZ
  3. Direct writing: RHP (HL+), AeitherLD (HL), nin consecutive sequences

A typical sequence loads 16 consecutive bytes (a full tile) from an address in ROM to an address in VRAM.

Load Timing

The tiles can be loaded at various times:

  • During initialization: Before the first frame, when the LCD is off
  • During V-Blank: When VRAM is accessible (although this is more common for upgrades)
  • During H-Blank: Limited, only in certain LCD-STAT modes
  • In the main flow: Any time when VRAM is accessible

Fountain: Pan Docs - "Video RAM (VRAM)", "CPU Instruction Set - LDIR", "Tile Data", "LCD Modes"

Implementation

Five global monitors were implemented inCPU::step()that detect VRAM accesses no matter where they occur in the execution flow. All monitors are run before any early return to ensure we capture all the executions.

Components created/modified

  • CPU.cpp: Added five global monitors after capturingoriginal_pc.
  • CPU.cpp: Added#include <map>for the PC-VRAM correlation monitor.

Implemented Monitors

[VRAM-ACCESS-GLOBAL] - VRAM Global Access Monitor

Detects ALL write accesses to VRAM (0x8000-0x9FFF) regardless of where they occur. Check if HL points to VRAM when writing opcodes are executed:

  • RHP (HL+), A(0x22)
  • RHP (HL-), A(0x32)
  • RHP (HL), A(0x77)
  • LD (HL), n(0x36)
  • RH (HL), r(0x70-0x75)

For each access, report PC, opcode, VRAM address, written value, whether it is Tile Data or Tile Map, approximate Tile ID, if it is real data or cleaning, and current ROM bank. Limit: 1000 accesses.

[PC-VRAM-CORRELATION] - PC-VRAM Correlation

Use astd::map<uint16_t, int>to track which PCs access VRAM and how many times. Print immediately when it detects a new PC or when it is data (not cleaning). This allows specific routines to be identified that load tools.

[LOAD-SEQUENCE] - Load Sequences

Detects consecutive sequences of writes to VRAM that could be loading tiles. Track consecutive addresses (increment or decrement) and reports when a 16-byte sequence is completed (a complete tile). Special alert when a complete sequence is detected.

[ROM-TO-VRAM] - Copies from ROM

Detects when it runsLDIR(0xED 0xB0) with DE pointing to VRAM. This indicates a block copy from ROM (HL) to VRAM (DE) of length BC. Reports PC, source and destination addresses, length and ROM bank.

[TIMING-VRAM] - VRAM Access Timing

Tracks the timing of VRAM accesses using an approximate instruction counter. Calculates the approximate frame based in instructions (assuming ~4 cycles per average instruction). Reports PC, approximate frame, LY (current scanline), LCD status (ON/OFF), BG Display status (ON/OFF), VRAM address and written value.

Design decisions

Monitors use variablesstaticto maintain status between calls. This is appropriate because the monitors they must track the global state of the system throughout the execution. The correlation monitor usesstd::mapto efficiently store the access count per PC.

The 1000 access limit for [VRAM-ACCESS-GLOBAL] prevents log saturation while allowing sufficient capture information for analysis. The approximate frame counter in [TIMING-VRAM] is sufficient to identify the relative timing of accesses without the need for direct access to the real PPU frame counter.

Affected Files

  • src/core/cpp/CPU.cpp- Added five global VRAM access monitors
  • src/core/cpp/CPU.cpp- Added#include <map>for correlation monitor

Tests and Verification

The code compiled successfully without errors. The monitors are ready for execution.

  • Compilation: python setup.py build_ext --inplace- Successful
  • Syntax validation: No linter errors
  • C++ Compiled Module Validation: Moduleviboy_corecompiled correctly

Note: The monitors will generate logs during the emulator execution. The analysis of these logs It will allow us to determine if there are VRAM accesses at any point in the flow and when they occur.

Sources consulted

Note: Implementation based on Pan Docs technical documentation and general knowledge of LR35902 architecture.

Educational Integrity

What I Understand Now

  • Global Monitoring: To find loading code that can run at any time, we need monitors that track ALL VRAM accesses, not just in specific contexts like ISRs or main stream after events.
  • PC-VRAM correlation: Identifying which specific routines (PCs) access VRAM allows you to find the loading code even if it is executed at unexpected times.
  • Loading Sequences: Tiles are typically loaded in consecutive 16-byte sequences, which is a detectable pattern.
  • LDIR: LDIR instruction is the most common method to copy data blocks from ROM to VRAM.

What remains to be confirmed

  • Existence of the loading code: Is there code that loads tiles at this stage of the game, or does the game load tiles later?
  • Load timing: If the code exists, when is it executed? During initialization, V-Blank, or at another time?
  • Execution conditions: If the code exists but is not executed, what conditions are missing?

Hypotheses and Assumptions

The analysis of Step 0294 partially rejected the hypothesis that the loading code is in an ISR. The new ones Monitors will allow testing new hypotheses:

  • Hypothesis A: Loading code exists but is executed BEFORE enabling BG Display
  • Hypothesis B: Loading code exists but runs LONG AFTER enabling BG Display
  • Hypothesis C: Load code exists but uses undetected methods (ex: non-standard DMA, indirect access)
  • Hypothesis D: The loading code does NOT exist in this phase of the game - the game loads tiles later or on another screen

Next Steps

  • [ ] Run the emulator with the new monitors active
  • [ ] Analyze logs to determine if there are VRAM accesses at any time
  • [ ] Identify specific routines that access VRAM (if they exist)
  • [ ] Detect loading sequences (if they exist)
  • [ ] Determine the timing of VRAM accesses
  • [ ] Conclude whether or not the loading code exists at this stage of the game