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

Debug: Cleaning Logs and Confirming Nested Loops

Date:2025-12-20 StepID:0158 State: 🔍 DRAFT

Summary

Analysis of the trace from Step 0157 confirmed that the fix of the Z flag (Step 0152) was a success: the loopDEC B -> JR NZended correctly when B reached 0x00 and the Z flag was set. However, the execution was silently stopped inPC: 0x0297, indicating that the CPU immediately entered a second cleanup loop (DEC C -> JR NZ) that was not instrumented. Detailed debug logs removed fromDEC BandJR NZto clean up the output and allow the triggered trace to capture the code that runs after all the loops.

Hardware Concept

Game Boy ROM boot routines typically run multiple memory cleanup loops in sequence. Each loop uses a different register (B, C, D, E, etc.) to count iterations and clear different memory regions. The typical structure is:

loop1:
    DEC B
    JR NZ, loop1 ; Loop 1: Clean region 1
    
loop2:
    DEC C
    JR NZ, loop2 ; Loop 2: Clean region 2
    
; ...more loops...
    
; Main code after initialization

When a loop ends (the register reaches 0x00 and the Z flag is set), the CPU continues with the next instruction. If that instruction is the start of another similar loop, the CPU immediately enters that second loop without pausing.

Key observation:If we only instrument the first loop with detailed logs, the second loop will run silently, creating the impression that execution has "stopped" when it is actually running at full speed within the second loop.

Fountain:Game Boy ROM Execution Trace Analysis - Common Initialization Patterns

Implementation

Removed all detailed debug logs that were added in previous steps to diagnose the behavior of the Z flag in initialization loops. These logs have already fulfilled their mission: they confirmed that the Z flag is activated correctly and that the loopDEC Bends as expected.

Deleted logs

  • DEC B (0x05):Theprintfwhich showed the value of B and Z before and after the operation.
  • JR NZ (0x20):Theprintfwhich showed the state of the Z flag, the offset and the jump decision.

Preserved logic

The triggered trace logic implemented in Step 0157 was kept intact. The "triggered" trace system is still active and will automatically activate when the PC exceeds0x0300, capturing the 100 critical instructions that are executed after all the initialization loops.

Changes made

CPU.cpp - case 0x05 (DEC B):

case 0x05://DEC B
{
    regs_->b = alu_dec(regs_->b);
    cycles_ += 1;
    return 1;
}

CPU.cpp - case 0x20 (JR NZ, e):

case 0x20://JR NZ, e (Jump Relative if Not Zero)
{
    uint8_t offset_raw = fetch_byte();
    
    if (!regs_->get_flag_z()) {
        // True condition: jump
        int8_t offset = static_cast(offset_raw);
        uint16_t new_pc = (regs_->pc + offset) & 0xFFFF;
        regs_->pc = new_pc;
        cycles_ += 3;
        return 3;
    } else {
        //False condition: do not jump, continue normal execution
        cycles_ += 2;
        return 2;
    }
}

Affected Files

  • src/core/cpp/CPU.cpp- Elimination of debugging logs inDEC BandJR NZ

Tests and Verification

Build validation:

  • Successful rebuild of C++ module with.\rebuild_cpp.ps1
  • No compilation errors
  • Moduleviboy_core.cp313-win_amd64.pydgenerated correctly

Running the emulator:

  • The emulator runs without errors:python main.py roms/tetris.gb
  • The console remains silent during loop execution (expected behavior)
  • The triggered trace is ready to activate when the PC exceeds0x0300

Analysis of expected behavior:

When running the emulator, the console should remain completely silent for a brief moment while the CPU runs through the cleanup loops at full speed.DEC BandDEC Cwithout printing anything. After all the loops finish and the PC finally overcomes0x0300, the triggered trace system should activate and display:

--- [CPU TRACE TRIGGERED at PC: 0x0300] ---
[CPU TRACE 0] PC: 0x0300 | Opcode: 0xXX
[CPU TRACE 1] PC: 0x0301 | Opcode: 0xXX
...
[CPU TRACE 99] PC: 0xXXXX | Opcode: 0xXX

Sources consulted

  • Game Boy ROM Execution Trace Analysis - Common Initialization Patterns
  • Step 0157: Implementing Triggered CPU Trace
  • Step 0152: Fix the Z flag in DEC instructions

Educational Integrity

What I Understand Now

  • Loops nested in sequence:The initialization routines execute multiple cleanup loops in sequence, each using a different register. When one loop ends, the CPU immediately continues with the next one.
  • Importance of log cleaning:Detailed debug logs are useful for diagnosing specific problems, but once behavior is confirmed, they should be removed to allow other tracing systems (such as triggered tracing) to function correctly.
  • Silence as a positive sign:In a properly functioning emulator, silence during the execution of optimized loops is a positive sign: it means that the CPU is running at full speed without I/O overhead.

What remains to be confirmed

  • Post-loop trace:We need to capture the trace that is generated when the PC finally exceeds0x0300to confirm that all loops finished successfully and see what code is executed next.
  • Exact number of loops:Although we know that there are at least two loops (DEC B and DEC C), we don't know the total number of cleanup loops that the ROM executes before reaching the main code.

Hypotheses and Assumptions

Main hypothesis:The CPU is successfully executing all the cleanup loops and will eventually reachPC: 0x0300, at which point the triggered trace will activate and capture the critical instructions that configure the graphics and initial state of the game.

Assumption:The second loop (DEC C) works the same way as the first (DEC B), using the Z flag correctly to terminate when C reaches 0x00.

Next Steps

  • [ ] Run the emulator and capture the trace triggered when the PC exceeds0x0300
  • [ ] Analyze the 100 captured instructions to identify missing opcodes
  • [ ] Implement missing opcodes that prevent execution from progressing
  • [ ] Continue the debug cycle until the ROM executes meaningful code