When debugging FPGA designs, simple triggers often don’t cut it. Complex designs frequently require capturing data only after a specific sequence of events or when multiple signals meet intricate conditions. This is where advanced triggering with trigger state machines (TSMs) comes into play, giving engineers powerful control over when and how data capture starts within Integrated Logic Analyzers (ILAs).
Why Basic Triggering Isn’t Enough
Basic triggering responds to a single condition, such as a flag going high or a particular signal matching a value. But real-world problems often need more. For instance, you might want to wait a certain number of clock cycles after a trigger event, watch for multiple events in order, or combine conditions across different signals.
Imagine trying to debug a bus transaction that requires monitoring a sequence like “status changes from A to D, then back to A,” and only after that sequence should you start capturing data. Basic triggers lack the flexibility to handle these nuanced requirements.
States and Transitions
Each state is defined by a name and a body of logic that can include:
- Conditional branching (two-way, or three-way)
- Setting or clearing internal flags
- Incrementing or resetting built-in counters
- Commands to jump (“goto”) to other states
The state machine always starts in the first declared state and moves from state to state based on your programmed logic and signal conditions.
Counters and Flags
The TSM provides four built-in counters that can track how many times an event has occurred, letting you delay triggering until a counter reaches a certain value. Similarly, flags provide internal markers you can set and clear to monitor the state machine’s progress or paths taken, which is invaluable for debugging complex trigger logic.
Crafting Complex Trigger Conditions
In TSM programming, you compare input probe signals against defined values or edges, combining multiple conditions with logical ANDs, ORs, and parentheses to create precise triggering windows.
Each condition uses a comparator resource, so complex expressions require careful allocation of these resources during ILA setup. You can check for things like rising edges, falling edges, or specific binary, hexadecimal, or decimal values on signals or buses.
One powerful feature is that you can change or swap your entire trigger state machine file without recompiling your FPGA bitstream, as long as the ILA was initially configured in advanced mode. This flexibility can save HOURS of time by letting you iterate rapidly during debugging.
Real-World Example for Trigger State Machines: Sequence Detection
Suppose you want to capture data only after detecting a specific sequence on a data bus, such as a series of decreasing values from 7 down to 3. The Trigger State Machine might start in an initial state, waiting for the first value (7). Once detected, it increments a counter and transitions to the next state, where it waits for 6, and so on.
Only after confirming the entire sequence will the TSM trigger the ILA capture, ensuring you record exactly the right data related to that event pattern.
Debugging the Trigger State Machine
The flags and counters inside your TSM also help you monitor its behavior during debugging. If your trigger doesn’t fire when expected, examining these internal states can reveal where the state machine got stuck or if a particular condition failed.
Multiple trigger windows and branches are possible within one ILA instance, allowing parallel monitoring of different event sequences, which is a significant step up from the limited windows in basic triggering.
Setting Up Your ILA for Advanced Triggering with Trigger States Machines
To harness the power of trigger state machines, you must:
- Enable advanced trigger mode when creating your ILA core
- Assign enough comparators to cover all your trigger conditions
- Attach probes to all signals involved in your trigger logic
- Use the language templates available in Vivado to help build your TSM code
With these in place, you can swap trigger state machine files dynamically and adapt your trigger logic on the fly without regenerating your FPGA bitstream.
For a solid foundation on state machines in general, which is highly relevant when working with TSMs, check out our detailed guide: Finite State Machines Guide.
Writing Trigger State Machine Logic
When crafting your trigger state machine code, keep in mind that you’re working with hardware-level logic, not software, so timing and resource usage matter.
Start simple and build complexity gradually. Begin with a straightforward state sequence to verify basic transitions work as expected. Then layer in counters, flags, and conditional branches. This iterative approach helps catch errors early.
Use meaningful state names. Since states are referenced explicitly in transitions (goto commands), clear names make your code easier to read and debug.
Leverage built-in counters and flags wisely. Counters help you implement delays or count occurrences without extra logic. Flags provide internal checkpoints, set and clear them to track which branches the state machine has taken. They’re especially handy when troubleshooting why a trigger didn’t fire.
Mind your comparators and resources. Each conditional probe uses a comparator, so complex conditions consume more hardware resources. Pay special attention to wide comparisons at high clock rates as they’re likely to use several layers of logic and may impact timing closure. In short, plan accordingly during ILA configuration.
Take advantage of AMD Vivado’s language templates. These templates provide a solid starting point, with example states and conditionals, which you can customize for your application.
Sample Trigger State Machine Code
Here’s a simple example illustrating a TSM that triggers after detecting the fourth rising edge on a signal ABC:
state WAIT_FOR_FOURTH_EDGE:
if (ABC == 1’bR && counter0 == 3) then reset_counter $counter0; trigger; elseif(ABC == 1’bR) then increment_counter $counter0 else goto WAIT_FOR_FOURTH_EDGE; endif
Explanation:
- The TSM starts in state WAIT_FOR_FOURTH_EDGE.
- Each clock cycle, it checks if signal ABC has a rising edge.
- If it detects a rising edge (R) and the counter is not equal to 3, it increments counter0.
- If it detects a rising edge (R) and the counter is equal to 3, meaning we have seen 3 previous edges and this current one is the fourth, it resets the counter and triggers an ILA capture.
- If neither of these cases are true, it stays in WAIT_FOR_EDGE, waiting for more edges.
- This example shows how counters and conditionals work together to create delayed or sequenced triggers.
Expanding the Logic
You can easily extend this example with multiple states and flags using the goto command. For instance, a TSM could:
- Wait for a specific sequence of bus values, moving through states like WAIT_FOR_A, WAIT_FOR_B, WAIT_FOR_C.
- Use flags to mark which parts of the sequence have been confirmed.
- Include nested conditional branches with two-way or three-way decisions to handle alternative scenarios.
Best Practices for Trigger State Machines
While in-circuit debugging fills key gaps in the verification process, it is not a replacement for simulation. Before debugging on the bench, comprehensive simulation should be performed. If a design is working in simulation but not on the bench, an ILA might detect a situation that was not simulated. If so, step back and create a matching test bench to observe circuit behavior and the controlled environment of simulation before rebuilding and going back to the bench.
A use case for ILAs is observing behaviors and interactions that are simply too complex or that would take too long to effectively simulate. These include interactions between processors and hardware as well as those involving unrelated time domains. In short, use the right tool at the right time.
Note, one set of issues that hardware debugging won’t (directly) help solve are those involving timing issues; however, ILAs can expose the “collateral damage” caused by them. Beware, the insertion of an ILA into the logic already pushing timing boundaries can cause the design to fail timing. For example, a probe in the middle of logic can cause the probe to suddenly be routed across the FPGA due to its position in relation the ILA. This will increase the time between synchronous elements, potentially violating timing.
Conclusion
Advanced triggering through trigger state machines provides FPGA engineers with precise, flexible control over data capture conditions. This approach simplifies debugging complex behaviors by allowing triggers based on sequences, delays, and sophisticated logic, all without the need for time-consuming recompilation. Mastering TSMs can dramatically reduce development cycles and improve design reliability.
