IL

ila-hw-debug

Hardware-level debugging methodology for FPGA designs using Integrated Logic Analyzers.

Install

mkdir -p .claude/skills/ila-hw-debug && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11355" && unzip -o skill.zip -d .claude/skills/ila-hw-debug && rm skill.zip

Installs to .claude/skills/ila-hw-debug

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Insert/connect an ILA (Integrated Logic Analyzer), program the board, arm a trigger, and read back captured waveforms on real FPGA hardware. Use when the user says "debug on hardware", "insert ILA", "capture waveform on the board", "the design works in sim but fails on the board", "trigger when X happens on hardware", "probe a signal live", "read the ILA", or wants to observe live silicon behavior via JTAG. Covers the full loop: mark/insert debug cores -> re-implement -> bitstream -> connect hardware server -> program with .ltx probes -> set trigger -> arm -> capture -> read CSV. Requires the SynthPilot MCP server with Vivado open and tcl_server.tcl running, plus a physical JTAG-connected board and a running hw_server (hardware server).
746 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Insert ILA cores
  • Arm hardware triggers
  • Capture waveforms
  • Read waveform data

How it works

It inserts ILA cores into the netlist, programs the FPGA, and captures live signals via JTAG.

Inputs & outputs

You give it
Hardware debug requirement
You get back
Captured waveform CSV

When to use ila-hw-debug

  • Debugging FPGA hardware
  • Capturing live silicon signals
  • Analyzing timing/IO issues
  • Hardware trigger setup

About this skill

ILA Hardware Debug

On-silicon debug methodology. Insert an Integrated Logic Analyzer (ILA), re-run implementation so the debug core is real in the routed netlist, program the board with the matching probes file, arm a trigger, capture, and read back the waveform. This is for behavior you cannot see in simulation: real I/O timing, real PLL lock, real DDR/transceiver/external-device interaction, metastability, and "works in sim, fails on the board" bugs.

The discipline here is the same as timing closure: observe before you change, insert the smallest probe that answers the question, capture FRESH hardware evidence before claiming anything, and never invent a "trigger hit" you did not read back from the device.

When to use

  • "Debug on hardware", "insert an ILA", "capture a waveform on the board".
  • A design passes simulation but misbehaves on real silicon (I/O, clocking, external memory/peripheral, link training, reset sequencing).
  • You need to trigger on a specific live condition (state == ERROR, fifo_full && wr_en, an address range) and see the surrounding cycles.
  • You need to read a current live value or drive a control bit at runtime (VIO).
  • You need to verify a fix actually took effect in hardware, not just in a report.

When NOT to use

  • The bug is reproducible in simulation -> use the simulation skill (sim_compile / sim_run / sim_probe). Sim is faster, fully observable, and free; exhaust it first. ILA only sees what you wired up and only after a full build.
  • A timing problem (WNS/TNS negative) -> close timing first. Probing a design that does not meet timing gives you garbage captures; the timing-closure skill comes first.
  • You only need static facts about the routed design (utilization, DRC, timing, power) -> those are report tools, no hardware needed.
  • You want to change RTL behavior. ILA observes; it does not fix. Use it to localize, then hand the root cause to the RTL/timing/CDC skill.

Prerequisites (verify first)

Do not skip. Most "ILA doesn't work" reports are a broken prerequisite, not a bug.

  1. MCP + Vivado link alive: test_connection. If it fails, the Tcl server inside Vivado is not running — stop and tell the user to start it.
  2. A project is open with a known top: get_project_info. ILA insertion edits this design.
  3. Decide the insertion path (see Decision Table). Confirm which one the design uses before touching anything:
    • Netlist (HDL) flow: mark signals in RTL -> setup_debug on the synthesized netlist. Use list_source_files to confirm the RTL exists.
    • Block Design flow: list_block_designs; instantiate bd_create_ila / bd_create_system_ila and wire probes in the BD.
  4. Physical board reachable (for the program/capture half):
    • open_hardware_manager
    • connect_hardware_server (default localhost:3121 — a hw_server process must be running and the board powered + JTAG-connected). If this fails, it is an environment problem: no board, no driver, or hw_server down. Say so — do not fake a capture.
    • list_hardware_targets then open_hardware_target — confirm a target exists.
    • list_hardware_devices — confirm the FPGA is detected on the JTAG chain.
  5. A debug-enabled bitstream + its .ltx must exist before you can capture. If the current bitstream has no debug core, you are in Phase A (insert), not Phase C (capture).

If any prerequisite fails, report exactly which one and stop. Do not proceed with a half-connected toolchain.


METHODOLOGY

The flow has three phases. Phase A (insert + rebuild) only runs if the design does not already contain the ILA you need. Phase B (program). Phase C (arm, capture, read). If a debug bitstream + .ltx already exist for the exact signals you need, skip straight to Phase B.

Phase A — Insert / connect the ILA (only if not already present)

A1. Pick the smallest probe set that answers the question. State, before inserting, what condition you are hunting and which signals prove or disprove it. ILA costs BRAM and routing; do not blanket-probe a bus you do not need. Width × depth is the budget — capture the suspect control/handshake signals and the few data bits that matter.

A2a. Netlist (HDL) insertion — preferred when probing internal RTL signals:

  1. mark_debug_signal for each signal of interest. (Equivalently, the user can add (* MARK_DEBUG = "true" *) in RTL; list_debug_signals confirms what is marked.) These signals must survive synthesis — a signal optimized away cannot be probed; if it is missing after synth, it was merged/trimmed.
  2. run_synthesis_async -> poll get_run_status until done -> get_synthesis_report. Use open_synthesized_design so the netlist is in memory.
  3. setup_debug — auto-builds the ILA core and connects all MARK_DEBUG signals (one clock domain per ILA core; mixed-domain signals need separate cores or you get an invalid setup).
  4. list_debug_cores + list_debug_signalsverify the core exists and the intended signals are actually attached before spending a build.
  5. implement_debug_core then write_debug_probes (produces the .ltx that the hardware side needs to name probes). Keep the .ltx next to the bitstream so program_device auto-associates it.

A2b. Block-Design insertion — preferred for AXI / interface / system-level debug:

  1. bd_create_system_ila (interface-aware, for AXI/AXIS/handshake interfaces) or bd_create_ila (pin-level) and configure depth with bd_ila_set_probe_width / bd_system_ila_set_slot as needed.
  2. bd_connect_system_ila_interface (interface) or bd_connect_ila_probe + bd_connect_ila_clock (pins). The ILA clock MUST be the clock of the domain you are sampling.
  3. bd_validate_designmust pass clean before generating. Unconnected probe/clock = invalid capture.
  4. bd_generate_output_and_wrapper, then bd_wait_on_output_generation / bd_check_output_status.

A3. Size the ILA deliberately (create_ila if instantiating directly, else the BD config tools). sample_depth ∈ {1024 … 131072}: deeper = more BRAM, more build time. num_probes up to 64. Start modest; widen only if the first capture proves you need more window or more signals.

A4. Re-implement and re-bitstream — the debug core must be real in routed silicon.

  • run_implementation_async -> poll get_run_status until complete.
  • report_drcmust be clean (debug-core insertion can introduce real DRC issues; do not ignore them).
  • Check timing did not regress from the inserted core: report_timing_summary -> extract_timing_metrics. If WNS went negative because of the ILA, that is a real regression — hand to the timing skill; do not paper over it.
  • generate_bitstream. Confirm the returned .bit path. write_debug_probes must have produced the matching .ltx.

One change-class per build. Do not simultaneously add probes, retime RTL, and tweak strategy — if the next capture looks wrong you will not know which change caused it.

Phase B — Program the board

  1. Re-confirm the live connection: open_hardware_manager, connect_hardware_server, open_hardware_target, list_hardware_devices.
  2. program_device with the debug .bit. Leave probes_file empty to auto-detect the .ltx beside the bitstream, or pass it explicitly. The .ltx MUST match this exact bitstream — a stale .ltx gives wrong/garbage probe names and silently meaningless captures.
  3. refresh_hardware_device then hw_ila_listverify the ILA core(s) appear with the expected probe count. No ILA listed = wrong bitstream, missing .ltx, or insertion failed. Stop and fix; do not pretend to capture.

Phase C — Arm, trigger, capture, read

  1. hw_ila_get_status — read current core status, depth, and probe names. Use the exact probe names it returns for all trigger calls.
  2. Set the trigger (the heart of useful capture):
    • hw_ila_set_trigger(probe, value, operator, radix) per probe. Use radix="bin" with X don't-care bits for bit-field conditions (e.g. "XXXX1XXX"), radix="dec"/"hex" for values, and operator ∈ eq/neq/gt/lt for ranges.
    • Multiple probes: hw_ila_set_trigger_condition("AND" | "OR") to combine.
    • hw_ila_clear_trigger to reset a probe (or all) if you mis-set it.
    • For a free-running snapshot with no condition, skip the trigger and use trigger_now=True in the next step.
  3. Confirm the trigger before arming: hw_ila_get_status again and read back the per-probe compare values and AND/OR mode. The condition you intended must be the condition shown. Set trigger_position so you capture enough pre-trigger context (e.g. center the window).
  4. Arm: hw_ila_run (or hw_ila_run(trigger_now=True) for immediate). Status should report ARMED (or TRIGGERED if it fired instantly).
  5. Provoke the condition. If a runtime stimulus is needed and a VIO exists, hw_vio_list -> hw_vio_get_probes -> hw_vio_write to drive control bits, hw_vio_read to observe live values. Otherwise the DUT/external event drives it.
  6. Wait for capture: hw_ila_wait(timeout=N). Final status IDLE = capture complete (trigger hit + buffer full). Still ARMED after timeout = trigger never fired — that is a real result, not an error to hide (see loop).
  7. Read back: hw_ila_read_data(file_path="...csv") to upload the samples and save the waveform CSV. Report the sample count and CSV path. This CSV — not any inference — is the evidence.
  8. Cleanly disconnect_hardware when the session is done (leaving the target open can block other tools / other users of the board).


Content truncated.

When not to use it

  • Simulation-reproducible bugs
  • Timing closure issues

Prerequisites

VivadoJTAG connectionhw_server

Limitations

  • Requires physical hardware
  • Limited by BRAM/routing budget

How it compares

It provides a methodology for on-silicon debugging that simulation cannot replicate.

Compared to similar skills

ila-hw-debug side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
ila-hw-debug (this skill)02moNo flagsAdvanced
python-testing-patterns772moReviewIntermediate
chrome-devtools417moReviewIntermediate
bats97moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

python-testing-patterns

wshobson

Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development. Use when writing Python tests, setting up test suites, or implementing testing best practices.

77204

chrome-devtools

mrgoonie

Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.

41157

bats

OleksandrKucherenko

Bash Automated Testing System (BATS) for TDD-style testing of shell scripts. Use when: (1) Writing unit or integration tests for Bash scripts, (2) Testing CLI tools or shell functions, (3) Setting up test infrastructure with setup/teardown hooks, (4) Mocking external commands (curl, git, docker), (5) Generating JUnit reports for CI/CD, (6) Debugging test failures or flaky tests, (7) Implementing test-driven development for shell scripts.

991

browser-daemon

noiv

Persistent browser automation via Playwright daemon. Keep a browser window open and send it commands (navigate, execute JS, inspect console). Perfect for interactive debugging, development, and testing web applications. Use when you need to interact with a browser repeatedly without opening/closing it.

587

performance-profiling

davila7

Performance profiling principles. Measurement, analysis, and optimization techniques.

633

obsidian-local-dev-loop

jeremylongshore

Configure Obsidian plugin development with hot-reload and fast iteration. Use when setting up development workflow, configuring test vaults, or establishing a rapid development cycle. Trigger with phrases like "obsidian dev loop", "obsidian hot reload", "obsidian development workflow", "develop obsidian plugin".

328

Search skills

Search the agent skills registry