This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
The VRAM Sensor: Real-Time Write Monitoring
Summary
Step 0192's "Checkerboard Test" validated that our rendering pipeline is working perfectly. The diagnosis is definitive: the blank screen is due to theVRAM is empty, not a rendering problem.
The current hypothesis is that the CPU never executes the code that copies the Nintendo logo data from ROM to VRAM. She's stuck in a logic loopbeforeto get to that point.
This Step implements a "motion sensor" in the MMU that will detect and report the first time any instruction attempts to write a byte to VRAM (0x8000-0x9FFF). This will give us a definitive, binary answer: is the CPU trying to write to VRAM, yes or no?
Engineering Concept: The Single Point of Truth
In our architecture, every memory write, no matter which CPU instruction originates it (RHP (HL), A, LDD (HL), A, or a future transferDMA), must be passed through a single method:MMU::write(). This method is our "single point of truth" for all write operations.
By placing a diagnostic sensor at this point, we can be 100% sure that we will capture any attempt to modify the VRAM, giving us a definitive answer: is the CPU trying to write, yes or no?
Binary Sensor Principle:This sensor acts as a "lie detector" that will tell us once and for all if the CPU is holding up its end of the bargain. We don't need to capture all the writes (that would be too much noise), just the first one. That is enough to answer our fundamental question.
VRAM Range:The VRAM memory range on Game Boy is0x8000to0x9FFF(8KB). This range contains both tile data and tilemaps. Any writing in this range is significant for our diagnosis.
Implementation
We have added a simple check inside the methodMMU::write()which detects the first write in the VRAM range and immediately reports it to the console.
Modified components
src/core/cpp/MMU.cpp: Added include<cstdio>and VRAM sensor in the methodwrite()
Sensor Code
The sensor uses a static variable to ensure that the message is printed only once:
void MMU::write(uint16_t addr, uint8_t value) {
// Ensure the address is in the valid range
addr &= 0xFFFF;
// Mask the value to 8 bits
value &= 0xFF;
// --- VRAM SENSOR (Step 0194) ---
// Static variable to ensure that the message is printed only once.
static bool vram_write_detected = false;
if (!vram_write_detected && addr >= 0x8000 && addr<= 0x9FFF) {
printf("\n--- [VRAM WRITE DETECTED!] ---\n");
printf("Primera escritura en VRAM en Addr: 0x%04X | Valor: 0x%02X\n", addr, value);
printf("--------------------------------\n\n");
vram_write_detected = true;
}
// --- Fin del Sensor ---
// ... resto de la lógica de write()
}
Design decisions
- Static variable:We use a local static variable so that the message is printed only once during the entire emulator execution. This avoids flooding the console with repetitive messages.
- First write detection:We just need to know if the CPU is trying to writeeverin VRAM. The first scripture is enough to answer our question.
- Sensor location:The sensor is placed just after the initial address and value validation, but before any other special logic (hardware registers, etc.). This ensures that we capture all writes to VRAM, without exception.
- Reported information:We report both the address and the written value, to be able to analyze what the CPU is doing if the sensor is activated.
Affected Files
src/core/cpp/MMU.cpp- Added include<cstdio>and VRAM sensor in methodwrite()docs/bitacora/entries/2025-12-20__0194__sensor-vram-monitoreo-escrituras-tiempo-real.html- New log entrydocs/bitacora/index.html- Updated with new entryREPORT_PHASE_2.md- Updated with Step 0194
Tests and Verification
The verification of this Step is mainly about compiling and running the emulator. The expected result is that the sensor is activated (or not) during execution, giving us definitive information about the behavior of the CPU.
Verification Process
- Recompile the C++ module:
.\rebuild_cpp.ps1Result: ✅ Successful compilation (with expected minor warnings from unused variables in other files)
- Run the emulator:
python main.py roms/tetris.gbThe emulator should run normally. The user must press a key to loop the Joypad.
- Observe the console:
The sensor will search for the message
[VRAM WRITE DETECTED!]in the console output.
C++ Compiled Module Validation
The emulator uses the compiled C++ module (viboy_core), which contains the VRAM sensor implemented inMMU::write(). Any writes to VRAM will go through this method and trigger the sensor if applicable.
Possible Results
There are two possible outcomes when running the emulator:
- The message does NOT appear
[VRAM WRITE DETECTED!]:- Meaning:Our hypothesis is correct. The CPUNEVERtries to write to VRAM. She's stuck in a logic loopbeforeof the graphics copy routine.
- Diagnosis:We have eliminated all hardware causes. The problem must be a software loop in the ROM itself that we have not anticipated, perhaps waiting for another I/O register that we have not initialized correctly.
- Next Step:We would turn on the CPU trace again, but this time with the confidence that we are looking for a pure software loop, not a hardware deadlock.
- YES the message appears
[VRAM WRITE DETECTED!]:- Meaning:Our main hypothesis was wrong! The CPUYEAHis writing to VRAM.
- Diagnosis:If the CPU is writing to VRAM, but the screen is still blank, it can only mean one thing: it is writing the wrong data (e.g. zeros) or to the wrong place.
- Next Step:We would analyze the value and address of the first write to understand what the CPU is doing. Are you clearing VRAM before copying? Are you pointing in the wrong direction?
Sources consulted
- Bread Docs:Memory Map
- Bread Docs:VRAM (Video RAM)
- Systems Engineering Principles: Single Point of Truth and Diagnostic Instrumentation
Educational Integrity
What I Understand Now
- The power of the single point of truth:In well-designed architectures, all operations of a specific type (in this case, memory writes) pass through a single point. This makes instrumentation trivial and 100% reliable.
- Binary diagnosis:Sometimes the best diagnostic tool is the simplest: a binary (yes/no) question that can be answered with a single observation. We don't need to capture the entire flow, we just need to know if something is happening or not.
- Motion sensor:This sensor acts as a "microphone" that shouts at us the moment something happens. It is simple, direct and definitive.
What remains to be confirmed
- Is the CPU trying to write to VRAM?This is the fundamental question that the sensor will answer. Depending on the answer, we will know exactly where to direct our diagnostic efforts.
- If the CPU does write, what is it writing?If the sensor activates, we will need to analyze the value and address to understand what the CPU is doing.
Hypotheses and Assumptions
Main hypothesis:The CPU never attempts to write to VRAM because it is stuck in a logic loop before reaching the graphics copy routine. This hypothesis will be based on the previous observation that VRAM is empty and the logic of the Game Boy boot code.
Assumption:If the sensor does not activate, then the problem must be a software loop in the ROM itself, possibly waiting for a hardware register that we have not initialized correctly or an opcode that we have not implemented.
Next Steps
- [ ] Run the emulator and see if the sensor activates
- [ ] If the sensor does NOT activate: Analyze the CPU execution flow during the boot code to identify the software loop preventing progress
- [ ] If the sensor DOES activate: Analyze the value and address of the first write to understand what the CPU is doing
- [ ] Identify the root cause of the problem (software loop, improperly initialized registry, missing opcode, etc.)