Debugging Waveforms
In this guide, we will explore one of NEX's most powerful and standout features: the Waveforms Task Agent.
While static analysis and code reviews are great for catching syntax errors and basic logic flaws, many complex hardware bugs only reveal themselves during runtime. To find these elusive bugs, verification engineers rely on analyzing signal transitions over time. NEX introduces the Waveforms Task Agent, a specialized agent that empowers the AI to directly query, navigate, and analyze simulation waveform files (such as .vcd or .fst) just like a human engineer using a waveform viewer.
By the end of this tutorial, you will understand how to leverage this feature to seamlessly transition from encountering a simulation failure to identifying the root cause in the waveform, and finally, applying the fix to your own designs.
The Debugging Workflow: How the Waveforms Agent Adds Value
In a typical debugging workflow, an engineer runs a simulation, sees a test failure, opens a tool like GTKWave or Verdi, traces the failing signal back through the design hierarchy, and manually inspects timing windows to find the discrepancy.
The Waveform Agent automates this tedious process. When a simulation fails, NEX can:
- Load the generated waveform file.
- Query specific time markers and signal hierarchies.
- Correlate the physical signal transitions (from the waveform) with the logical intent (from the RTL source).
- Pinpoint the exact cycle and signal where the design deviated from the expected behavior.
For this tutorial, we will walk through debugging an AXI4 Read Slave design and its accompanying testbench. The testbench runs a series of read transactions, but it contains a functional bug that cannot be detected by static code analysis alone.
Prerequisites
Before starting, ensure you have your workspace set up:
- Your RTL design file (e.g., axi4_read_slave.sv).
- Your testbench file (e.g., tb_axi4_read_slave.sv).
- Ensure your testbench includes the necessary system tasks to dump waveforms (e.g., $dumpfile("axi4_read_slave.vcd"); and $dumpvars(0, tb_axi4_read_slave);).
Step 1: Launching NEX
NEX provides specialized manager agents tailored for different workflows (ASIC, FPGA, Verification, etc.). You can invoke the one that best matches your project's toolchain environment. In this example, we'll invoke the FPGA agent.
Open your terminal and run the following command:
Note: Depending on your specific setup, you could also use --agent=verification for a pure simulation focus.
You should see a confirmation message similar to the following, indicating the agent has successfully loaded its context and tools:
Step 2: Building Context (Reading the Design & Testbench)
Before NEX can effectively analyze a waveform, it needs to understand the architecture of your design. By reading the source files, NEX builds an internal map of your module hierarchies, state machines, signal names, and the verification intent written in your testbench.
Prompt the agent to read your project files.
Read './axi4_read_slave.sv' and './tb_axi4_read_slave.sv' to understand the design architecture and testbench logic.
Behind the Scenes:
NEX parses the provided SystemVerilog files. It learns the AXI4 interface signals (like ARVALID, ARREADY, RVALID, RDATA, etc.) and understands how the testbench stimulates the design. This context is crucial; when NEX later looks at the waveform, it will know which signals are important to query based on this source code.
I have read the contents of both ./axi4_read_slave.sv and ./tb_axi4_read_slave.sv.
Here is a brief summary of what they contain:
axi4_read_slave.sv
- Purpose: Implements a simple, read-only AXI4 slave with an internal word-addressed memory.
- Protocol: Only supports the AXI4 Read Address (AR) and Read Data (R) channels.
- Burst Types: Supports FIXED (00), INCR (01), and WRAP (10) bursts.
- Design Style: One outstanding transaction at a time with registered state and combinational data outputs. This allows data to immediately reflect the requested address on the current beat.
tb_axi4_read_slave.sv
- Purpose: A self-checking testbench to verify the functionality of axi4_read_slave.sv.
- Methodology:
- Pre-loads the memory with an address-derived data pattern (0xAAAA0000 | addr).
- Drives stimuli to test INCR (single beat and 4-beat bursts), WRAP (4-beat), and FIXED (4-beat) transaction types.
- Compares the sampled RDATA, RID, and RLAST against expected internal state calculations.
- Automatically reports test success/failure.
Let me know if you would like to run a simulation with these files (e.g., using Icarus Verilog), modify them, analyze them further, or proceed with integrating this IP into an FPGA project!
Step 3: Running the Simulation
Once NEX understands your codebase, the next step is to execute the simulation.
Behind the Scenes:
NEX will automatically determine the best available simulator in your environment (e.g., Vivado XSim, Questa, VCS, or Icarus Verilog). It compiles the design and testbench, runs the simulation, and captures the console output. Because your testbench includes waveform dumping tasks, a .vcd file is generated in your project directory.
The simulation was successfully launched using Icarus Verilog via the verification workflow, but the testbench reported failures and eventually timed out.
Simulation Results Summary
- Compilation: PASS
- Simulation: FAIL (Timed out at 10,000 ns)
Findings & Mismatches
1 Test 1 (Single beat, INCR, addr=0x00000010): Passed successfully.
2 Test 2 (4-beat INCR, addr=0x00000020): Failed immediately.
- RID Mismatch: Expected 2, got 1. (The ID from Test 1 seems to be lingering, or the new ID wasnt properly registered).
- RLAST Mismatch: Expected 0 in beat 0, got 1. Expected 1 in beat 3, got 0.
- RDATA Mismatch: Expected data for beat 0 was aaaa0008, got aaaa0004 (which corresponds to address 0x10 from Test 1!). The internal address pointer seems to be out of sync or did not accept the new command properly.
3 Timeout: The testbench safety timeout caught a hang at 10000 ns (likely because ARREADY or RVALID/RLAST became permanently stuck due to the state machine locking up, stalling Test 3).
Recommended Next Steps
We need to debug axi4_read_slave.sv. The fact that Test 2 is outputting the ID (1) and Data (0x10) from Test 1 indicates that the FSM either didnt transition back to S_IDLE properly, or didnt register the new AR channel inputs for Test 2.
If you d like, I can analyze the AXI RTL (axi4_read_slave.sv), propose a fix, and patch the code!
As you can see here, The simulation failed during Test Case 2 due to data mismatches while capturing a read transaction. As a result, the simulation eventually timed out and did not proceed to Test Cases 3 and 4.
Step 4: Inspecting Waveforms with the Waveforms Agent
Now that we have a failing testcase and a .vcd file, we reach the core capability of this tutorial. We will instruct NEX to use the Waveform Agent to investigate why the failure occurred.
Behind the Scenes:
Instead of trying to read a massive .vcd text file as plain text (which is impossible for large designs), NEX leverages the Waveforms MCP server.
- NEX issues structured queries to the Waveforms MCP, asking for the values of specific signals (like the AXI handshake signals) at the exact timestamp where the testbench reported the error.
- If the error isn't immediately obvious at that timestamp, NEX uses the built-in Waveforms Agent's capabilities to traverse backward in time, tracing the dependent signals cycle-by-cycle to find where the logic first broke down.
- It essentially acts as a virtual verification engineer, cross-referencing the waveform data with the RTL code it read in Step 2.
Waveform Analysis Discovery - The Fix:
After pinpointing the exact cycle and logic failure via waveform inspection, NEX will propose a code modification to fix the bug. Once you accept and apply NEX's proposed fix to the source file, NEX automatically re-runs the simulation to confirm whether the fix resolves the issue.
You will see something similar to this:
The Fix
I have already patched the tb_axi4_read_slave.sv testbench. I removed the hardcoded #15 delay in drive_ar and replaced it with a proper synchronous AXI loop that polls ARREADY at posedge ACLK:
task automatic drive_ar(
input [ID_WIDTH-1:0] id,
input [ADDR_WIDTH-1:0] addr,
input [7:0] len,
input [2:0] size,
input [1:0] burst
);
@(posedge ACLK);
ARID <= id;
ARADDR <= addr;
ARLEN <= len;
ARSIZE <= size;
ARBURST <= burst;
ARVALID <= 1'b1;
// FIX: Removed the #15 delay. Added a proper synchronous loop for the AXI Handshake.
do begin
@(posedge ACLK);
end while (!ARREADY);
ARVALID <= 1'b0;
endtask
In this case, NEX identified the root cause of the test failure in the testbench: a 15ns delay that was causing the transaction mismatch.
Simulation Results
After fixing the testbench, I re-ran the Icarus Verilog simulation. All tests now pass successfully with 0 errors!
--- Test 1: single beat, INCR, addr=0x00000010
[55000] OK : beat 0 addr=00000010 RDATA=aaaa0004 RLAST=1
--- Test 2: 4-beat INCR, addr=0x00000020 ---
[85000] OK : beat 0 addr=00000020 RDATA=aaaa0008 RLAST=0
[95000] OK : beat 1 addr=00000024 RDATA=aaaa0009 RLAST=0
[105000] OK : beat 2 addr=00000028 RDATA=aaaa000a RLAST=0
[115000] OK : beat 3 addr=0000002c RDATA=aaaa000b RLAST=1
.
.
.
TEST PASSED: 13 checks, 0 errors
Key Takeaways for your own projects
- Always provide context: Let NEX read both your RTL and Testbench before asking it to debug a waveform.
- Ensure waveforms are dumped: NEX cannot analyze what isn't recorded. Always include
$dumpvarsor vendor-equivalent commands in your testbenches. - Be specific: If you know roughly where or when an error occurs, mention it in your prompt to speed up NEX's waveform analysis.