This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Sniper: Reload
Summary
After implementing Echo RAM (Step 0239) and GPS monitor (Step 0240), GPS analysis reveals that the CPU is still stuck in the zone0x2B24. Even though the Echo RAM logic is implemented, the game still fails memory validation. "Sniper" (detailed trace) is reactivated in range0x2B20-0x2B30to observe the dynamic behavior of the loop and determine if HL is advancing (scanning memory) or constantly restarting.
Hardware Concept
Dynamic Analysis of Verification Loops: When a game checks memory integrity, it typically runs a loop that:
- Initializes a register (ex: HL) with a starting address.
- Reads a byte of memory at that address.
- Compares the read value with an expected value (ex:
CP 0xFD). - If the comparison fails, restart the loop or abort.
- If the comparison passes, increase HL and repeat until the entire range is covered.
If the loop ismoving forward(HL increments), means the check is progressing but is slow (it may be scanning all of the RAM). If the loop isstatic(HL constantly resets), means it fails on the first byte and never moves forward.
"Sniper" is a debugging technique that involves activating detailed traces only in a specific range of memory addresses. This allows you to observe the behavior of a loop without cluttering the console with massive logs of the entire execution.
Implementation
The Sniper debug block is reactivated inCPU.cpp, just before the opcode fetch, to capture each instruction executed in the critical range.
Modified components
src/core/cpp/CPU.cpp: Added Sniper debug block in the methodstep().
Design decisions
The debug block is placedbeforeof thefetch_byte()to capture the PC before it increases. This allows you to see the exact address where each instruction is executed. The log format includes:
- PC: Program Counter (address of the current instruction).
- OP: Opcode of the instruction.
- TO: Accumulator value (to see what value is being compared).
- H.L.: Value of the HL register pair (to see if it advances or restarts).
Important note: This debug is temporary and should be disabled once we identify the problem, since theprintfsignificantly slow down execution.
Code added
// --- Step 0241: RELOADED SNIPER ---
// We reactivate the Sniper debug to analyze the behavior
//dynamic loop at 0x2B20-0x2B30. We need to see if HL advances
// (scanning memory) or restarts constantly.
if (regs_->pc >= 0x2B20 && regs_->pc<= 0x2B30) {
uint8_t opcode = mmu_->read(regs_->pc);
printf("[SNIPER] PC:%04X | OP:%02X | A:%02X | HL:%04X\n",
regs_->pc, opcode, regs_->a, regs_->get_hl());
}
// ------------------------------------------
Affected Files
src/core/cpp/CPU.cpp- Reactivation of the Sniper debug block in the methodstep()docs/bitacora/entries/2025-12-22__0241__sniper-reload.html- Log entry
Tests and Verification
To validate this implementation, you must:
- Recompile the C++ extension:
python setup.py build_ext --inplace - Run the emulator with Tetris:
python main.py roms/tetris.gb - Analyze Sniper logs:
- YeahHL advances(ex:
HL:E645,HL:E646,HL:E647...): The loop is scanning all the RAM and it's just slow. Let the logs run or optimize them. - YeahHL is static(ex:
HL:E645repeated): The loop fails at the first byte and restarts. There is a data problem in RAM. - YeahTo change: See what value is being compared and if it matches what is expected.
- YeahHL advances(ex:
Current status: Pending execution and log analysis.
Sources consulted
- Bread Docs:Game Boy Pan Docs- General architecture reference LR35902
Note: This implementation is a standard debugging technique for dynamic loop analysis.
Educational Integrity
What I Understand Now
- Dynamic Analysis: Observing the behavior of a loop at runtime is crucial to understanding why it fails. Static logs (memory dumps) do not show the execution flow.
- Selective Debugging: Enabling traces only on a specific range of addresses allows you to obtain detailed information without cluttering the console with massive logs.
- Verification Patterns: Games typically check memory integrity by scanning byte by byte. If the loop advances, the verification is progressing; if it restarts, there is an early failure.
What remains to be confirmed
- HL behavior: Does HL advance or restart? This will determine if the problem is an early failure or a slow loop.
- Value of A: What value is being compared? Is it the expected (
0xFD) or is there a discrepancy? - Memory status: Does the WRAM memory contain the correct values? Is Echo RAM working properly?
Hypotheses and Assumptions
Main hypothesis: Although we implement Echo RAM, it is possible that:
- The WRAM memory was not initialized correctly before verification.
- The game wrote values to WRAM that were not correctly reflected in Echo RAM.
- There is another initialization problem that causes the check to fail on a different byte.
The Sniper logs will tell us which of these hypotheses is correct.
Next Steps
- [ ] Recompile the C++ extension with the Sniper debug enabled.
- [ ] Run Tetris and capture the Sniper logs.
- [ ] Analyze the logs to determine if HL advances or restarts.
- [ ] If HL advances: Let the loop run or optimize the logs so that it ends faster.
- [ ] If HL is static: Investigate why the memory does not contain the expected values.
- [ ] Once the problem has been identified, disable the Sniper debug so as not to slow down execution.