# debug-tb > Debug SystemVerilog testbench failures in the SVC project. Use when a - Author: Patrick Bozeman - Repository: pbozeman/svc - Version: 20260118183646 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/pbozeman/svc - Web: https://mule.run/skillshub/@@pbozeman/svc~debug-tb:20260118183646 --- --- name: debug-tb description: Debug SystemVerilog testbench failures in the SVC project. Use when a testbench fails (make _tb), to analyze CHECK_* assertion failures, watchdog timeouts, or unexpected signal values. Provides systematic debugging workflow using VCD waveforms and failure output analysis. --- # Debugging Testbenches ## Workflow 1. **Capture failure output** - Run `make _tb` and note the error 2. **Parse failure message** - Extract file, line, assertion type, and values 3. **Read failing test** - Find the test task and understand expected behavior 4. **Read module under test** - Understand the RTL logic being tested 5. **Analyze root cause** - Compare expected vs actual behavior 6. **Fix and verify** - Apply fix, run test again ## Failure Message Format Test failures display: ``` FAIL : CHECK_(=0x, =0x) make _tb RUN= gtkwave .build/.vcd & ``` Key information: - **File:line** - Location of failed assertion - **CHECK type** - EQ, TRUE, FALSE, WAIT_FOR, etc. - **Signal values** - Actual vs expected (hex format) - **Re-run command** - Isolate the failing test - **VCD path** - Waveform file for visual debugging ## Assertion Types | Macro | Fails When | | ------------------------------- | ---------------------------------------- | | `CHECK_TRUE(a)` | `a !== 1` | | `CHECK_FALSE(a)` | `a !== 0` | | `CHECK_EQ(a, b)` | `a !== b` | | `CHECK_NEQ(a, b)` | `a === b` | | `CHECK_LT(a, b)` | `a >= b` or X/Z values | | `CHECK_WAIT_FOR(clk, sig, max)` | Signal never becomes 1 within max cycles | Note: `CHECK_EQ` uses `!==` (4-state), so X/Z mismatches fail. ## Common Failure Patterns ### Signal Never Asserts (CHECK_WAIT_FOR timeout) Causes: - Missing handshake (valid without ready, or vice versa) - Reset not properly released - Clock domain issue - Logic stuck waiting for upstream event Debug steps: 1. Check reset sequence in test 2. Verify all required inputs are driven 3. Look for combinatorial loops or missing clock edges ### Wrong Value (CHECK_EQ failure) Causes: - Off-by-one in counters or indices - Incorrect bit slicing or width mismatch - Endianness confusion - Combinatorial vs registered output timing Debug steps: 1. Check data width consistency 2. Verify timing (are you checking one cycle too early/late?) 3. Trace data path through module ### X or Z Values Causes: - Uninitialized signal - Missing reset initialization - Unconnected port - Multiple drivers Debug steps: 1. Check all signals initialized in reset block 2. Verify port connections in UUT instantiation 3. Look for undriven module outputs ### Watchdog Timeout Causes: - Deadlock in handshake protocol - Infinite loop in test logic - Test expects condition that never occurs Debug steps: 1. Find where simulation is stuck (last passing assertion) 2. Check for circular dependencies in ready/valid 3. Verify test doesn't wait for impossible state ## Debugging Commands ```bash # Run specific test make _tb RUN= # View waveforms gtkwave .build/.vcd & # Debug RISC-V core (prints instruction trace) make _tb SVC_RV_DBG_CPU=1 # Run all tests make tb ``` ## Adding Debug Output When existing debug capabilities aren't sufficient, add `$display` statements directly in the testbench being debugged. Don't try to brute-force reason through signal values - actually look at what's happening. ```systemverilog // Add ungated - just do it, remove later $display("state=%0d valid=%b ready=%b data=%h", uut.state, out_valid, out_ready, out_data); ``` Add an `always` block in the testbench to monitor UUT internals: ```systemverilog always @(posedge clk) begin if (uut.some_valid && uut.some_ready) $display("handshake: data=%h", uut.some_data); end ``` Good things to display: - UUT internal state machines (`uut.state`) - Handshake completions (valid && ready) - Counter values - Data at pipeline stage boundaries Remove debug statements after fixing the issue. ## Reading Waveforms Focus signals: 1. `clk` and `rst_n` - Verify timing and reset 2. `*_valid` / `*_ready` - Handshake signals 3. Signals mentioned in failure message 4. Internal state machines (if exposed) Look for: - Signals stuck at X/Z - Handshakes that never complete - Unexpected transitions - Missing clock edges ## AXI Debugging For AXI/AXI-Lite protocol issues, see [references/axi_debug.md](references/axi_debug.md). ## Reference - Test framework: `rtl/common/svc_unit.sv` - Full testbench guide: `docs/tb.md` - Example testbench: `tb/common/svc_arbiter_tb.sv`