Agent skill
debug-tb
Debug SystemVerilog testbench failures in the SVC project. Use when a testbench fails (make <module>_tb), to analyze CHECK_* assertion failures, watchdog timeouts, or unexpected signal values. Provides systematic debugging workflow using VCD waveforms and failure output analysis.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/debug-tb
SKILL.md
Debugging Testbenches
Workflow
- Capture failure output - Run
make <module>_tband note the error - Parse failure message - Extract file, line, assertion type, and values
- Read failing test - Find the test task and understand expected behavior
- Read module under test - Understand the RTL logic being tested
- Analyze root cause - Compare expected vs actual behavior
- Fix and verify - Apply fix, run test again
Failure Message Format
Test failures display:
FAIL
<file>:<line> CHECK_<type>(<signal>=0x<actual>, <expected>=0x<expected>)
make <module>_tb RUN=<test_name>
gtkwave .build/<module>.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:
- Check reset sequence in test
- Verify all required inputs are driven
- 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:
- Check data width consistency
- Verify timing (are you checking one cycle too early/late?)
- Trace data path through module
X or Z Values
Causes:
- Uninitialized signal
- Missing reset initialization
- Unconnected port
- Multiple drivers
Debug steps:
- Check all signals initialized in reset block
- Verify port connections in UUT instantiation
- 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:
- Find where simulation is stuck (last passing assertion)
- Check for circular dependencies in ready/valid
- Verify test doesn't wait for impossible state
Debugging Commands
# Run specific test
make <module>_tb RUN=<test_name>
# View waveforms
gtkwave .build/<module>.vcd &
# Debug RISC-V core (prints instruction trace)
make <module>_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.
// 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:
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:
clkandrst_n- Verify timing and reset*_valid/*_ready- Handshake signals- Signals mentioned in failure message
- 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.
Reference
- Test framework:
rtl/common/svc_unit.sv - Full testbench guide:
docs/tb.md - Example testbench:
tb/common/svc_arbiter_tb.sv
Didn't find tool you were looking for?