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
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:
- LDIR (0xED 0xB0): Most common pattern. Copy (HL++) to (DE++), decrement BC, repeat until BC=0.
- Manual Loops:
LD A,(HL) ; LD (DE),A ; INC HL ; INC DE ; DEC BC ; JR NZ - 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 capturing
original_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 monitorssrc/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: Module
viboy_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
- Bread Docs:Video RAM (VRAM)
- Bread Docs:CPU Instruction Set - LDIR
- Bread Docs:Tile Data
- Bread Docs:LCD Modes
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