This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Debug: Re-activation of the Trace to Analyze Logical Loop
Summary
The Step 0168 diagnostic confirmed that the CPU is not encountering unknown opcodes. The deadlock ofLY=0persists because the CPU is trapped in an infinite loop composed of instructionsvalid. The "fail-fast" strategy was reverted and the triggered tracing system was re-activated with a trigger in0x02A0and a limit of 200 instructions to capture and analyze the logic loop the CPU is trapped in.
Hardware Concept: Logic Debugging vs. Opcodes
There are two main types of errors that causedeadlocksin an emulator under development:
- Missing Opcode Error:The CPU finds an instruction that it doesn't know about. Our "fail-fast" strategy from Step 0168 is perfect for this, as it terminates execution immediately and reports the unknown opcode.
-
Loop Logic Error:The CPU executes a loop (ex:
DEC B -> JR NZ) but the exit condition is never met (e.g. the flagZnever activates). This requires observing the state of the registers and flagsinsideof the loop to understand why the condition is never met.
Diagnostics in Step 0168 ruled out the first type of error: the fact that the main Python loop is still running (displaying the messages💓Heartbeat) and may we never see the fatal message of thedefaultcase confirms thatall opcodes that the CPU is running are already implemented.
Therefore, the problem is of the second type: an infinite logical loop. The Tetris ROM runs several memory cleaning routines in sequence. We have fixed the loopDEC Bfrom Step 0165, but the ROM has almost certainly immediately entered another similar loop, for example one that usesDEC CeitherDEC DE.
To analyze this type of error, we need an observation tool (a trace) instead of a mine detector (fail-fast). Triggered tracing allows us to capture the pattern of opcodes being executed repeatedly, allowing us to identify the loop and deduce which exit condition is not being met.
Implementation
It was modifiedsrc/core/cpp/CPU.cppto reverse the "fail-fast" behavior of Step 0168 and re-activate the triggered tracing system with a configuration optimized to capture logical loops.
Modified components
src/core/cpp/CPU.cpp: Case reverseddefaultof the switch to return 0 cycles silently, and set the trace system triggered.
Changes made
1. Trigger and Trace Limit Setting:
// Static variables for diagnostic logging with system "triggered"
// The trigger is activated after the memory cleaning routines (0x02A0)
// to capture critical hardware configuration code and logic loops
static const uint16_t DEBUG_TRIGGER_PC = 0x02A0; // Plot activation address (after cleanup)
static bool debug_trace_activated = false; // Activation flag
static int debug_instruction_counter = 0; // Post-activation counter
static const int DEBUG_INSTRUCTION_LIMIT = 200; // Post-activation limit (Step 0169: increased to capture loops)
The trigger was changed from0x0300to0x02A0to capture the code that runs just after the first known cleanup loop. The limit was increased from 100 to 200 instructions to capture full loops.
2. Default Case Reversal:
default:
// --- Step 0169: Reverted to silent behavior ---
// Step 0168 diagnostic confirmed that there are no unknown opcodes.
// The deadlock is caused by a logic loop with valid instructions.
// We return 0 cycles again to allow the trace to capture the loop.
cycles_ += 0;
return 0;
Theexit(1)and it returned 0 cycles silently. This allows the emulator to continue running and the trace to capture the logic loop.
3. Removal of Unnecessary Include:
The#include <cstdlib>since it is no longer usedexit().
Affected Files
src/core/cpp/CPU.cpp- Modified the triggered tracing system (trigger set to 0x02A0, limit increased to 200) and reverted the default case to silent behavior.
Tests and Verification
The verification will be carried out by running the emulator and observing the output of the plot:
- Command executed:
python main.py roms/tetris.gb - Expected result:The emulator should run silently until the PC reaches
0x02A0, at which point the message should appear--- [CPU TRACE TRIGGERED at PC: 0x02A0] ---followed by 200 trace lines showing the opcode pattern of the logic loop. - Native Validation:Compiled C++ module validation with tracing enabled.
Note:This Step does not include unit tests because it is a temporary debugging modification. Validation is carried out by direct observation of the execution trace.
Sources consulted
- Implementation based on general knowledge of emulator debugging techniques and infinite loop analysis.
- Bread Docs:CPU Instruction Set- For reference of valid instructions.
Educational Integrity
What I Understand Now
- Difference between Opcode Error and Logic Error:An opcode error is detected immediately when the CPU attempts to execute an unknown instruction. A logic error requires looking at the repetitive behavior of valid instructions to identify why a condition is never met.
- Complementary Debugging Strategies:"Fail-fast" is great for detecting missing opcodes, but useless for analyzing logic loops. Triggered tracing is the right tool to observe repetitive running patterns.
- The Diagnosis of Step 0168 was Successful:Although it didn't resolve the deadlock, it confirmed that there are no unknown opcodes, which is valuable information that allows us to focus debugging on the loop logic.
What remains to be confirmed
- Loop Pattern:We need to run the emulator and analyze the trace to identify the exact pattern of opcodes that are repeating, which will allow us to deduce which instruction or condition is causing the infinite loop.
- Output Condition:Once the loop is identified, we need to analyze why the exit condition (e.g. flag
ZinJR NZ) is never fulfilled.
Hypotheses and Assumptions
Main Hypothesis:The logic loop is similar to Step 0165 (a never-ending decrement loop), but probably uses a different register (e.g.DEC CratherDEC B) or a 16-bit instruction (e.g.DEC DE). The trace will confirm or refute this hypothesis.
Next Steps
- [ ] Run the emulator and capture the logic loop trace
- [ ] Analyze the pattern of repetitive opcodes in the trace
- [ ] Identify the statement or condition that causes the infinite loop
- [ ] Implement the necessary fix (probably similar to Step 0165)