This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Total Silence: Takeoff
Summary
The "Sniper" logs (Step 0228) confirmed that the hardware is working correctly:
the recordL.Y.advances from 26 to 38, the CPU reads the register correctly, and there is no deadlock.
The apparent crash was caused by the extreme latency of printing logs every CPU cycle.
All C++ debugging instrumentation was removed to allow the emulator to
reach its native speed (60 FPS) and overcome the V-Blank wait loop in real time.
Hardware Concept
In a Game Boy emulator, the main emulation loop executes millions of instructions per second. Each CPU instruction consumes between 1 and 6 M-Cycles (4-24 T-Cycles). To reach 60 FPS, the emulator must execute approximately 70,224 cycles per frame, which means executing thousands of instructions in less than 16.67 milliseconds.
The Observer Effect:Print text to the console (printf) is an operation
extremely slow compared to the execution of a CPU instruction. A call toprintfcan take hundreds or thousands of microseconds, while a CPU instruction is executed in nanoseconds.
If we print a log every CPU cycle, the emulator slows down thousands of times, making it seem
which is hanging when in reality it is just running in "super-slow motion".
In the case of Step 0228, the game was waiting forL.Y.will reach 144 (V-Blank).
To get from line 38 to 144, the Game Boy needs approximately 4 milliseconds on real hardware.
With the logs activated printing each step, those 4 milliseconds became minutes, making
It seemed like the emulator was stuck when in reality it was just moving forward very slowly.
Golden Rule:In the critical emulation loop (the one that runs millions of times per second), any I/O operations (printing, file writing, system calls) must be removed completely or redirect to in-memory buffers that are periodically flushed. I/O kills performance.
Implementation
All logging blocks in the C++ core were removed or commented out:
Modified components
- CPU.cpp:Commented on the "Sniper" block (Step 0228) that printed logs when PC was at 0x2B10-0x2B20. It was also commented on
#include <cstdio>. - MMU.cpp:Commented on the "VRAM Sensor" (Step 0204) that printed when the first write to VRAM was detected.
Design decisions
Instead of completely removing the logging code, we chose to comment it out. This allows:
- Quick reactivation:If we need to debug in the future, we can easily uncomment.
- Record:The comments document what was disabled and why.
- Clean build:The commented code does not affect the performance or size of the binary.
All commented blocks include a reference to Step 0229 explaining why they were disabled.
Affected Files
src/core/cpp/CPU.cpp- Commented Sniper block and#include <cstdio>src/core/cpp/MMU.cpp- Commented VRAM Sensor block
Tests and Verification
Validation of log cleaning:
- Compilation:
.\rebuild_cpp.ps1eitherpython setup.py build_ext --inplace - Execution:
python main.py roms/tetris.gb - Expected result:The emulator should boot at native speed (60 FPS) and the game should progress past the V-Blank wait loop.
- Validation:No logs in the console during normal execution. The accountant
L.Y.should fly from 38 to 144 in milliseconds, allowing the game to continue.
Evidence from Tests:
# Command executed:
python main.py roms/tetris.gb
# Expected result:
# - No [SNIPER] logs in the console
# - No logs [VRAM WRITE DETECTED!] in the console
# - The game starts and displays the title screen (or Nintendo logo)
# - Stable FPS at 60 FPS
Sources consulted
- Bread Docs:System Clock, Timing
- Technical documentation: Principles of critical loop optimization in embedded systems
Educational Integrity
What I Understand Now
- Performance in critical loops:Any I/O operation in a loop that runs millions of times per second has a devastating impact on performance. A
printfIt can slow down the emulator thousands of times. - The Observer Effect:Instrumenting code for debugging can completely change the observed behavior, making it appear like there is a bug when in reality there is just extreme slowdown.
- Timing in emulation:Timing is critical. If the emulator cannot execute instructions at the correct speed, the game's wait loops never end, making it appear to be hanging.
What remains to be confirmed
- Complete game start:Verify that the game boots completely and displays the title screen after clearing the logs.
- Sustained performance:Confirm that the emulator maintains 60 FPS during normal game execution.
Hypotheses and Assumptions
Main hypothesis:By clearing the logs, the emulator should reach native speed and the game should boot completely, displaying the title screen or Nintendo logo. The seemingly infinite V-Blank wait loop should complete in milliseconds.
Next Steps
- [ ] Verify that the game starts completely after deleting the logs
- [ ] Confirm that the emulator maintains 60 FPS while running
- [ ] If the game still does not start, investigate other possible crashes (Timer, Interrupts, Joypad)
- [ ] Implement conditional logging system (only in debug builds) for future debugging