bitstream-program
Generate a bitstream and program a Xilinx FPGA over JTAG, or build an MCS image and burn it into SPI/BPI configuration flash for power-on boot. Invoke when the user says "program the board", "generate
SKILL.mdskills/bitstream-program/SKILL.md
GitHubBitstream Generation & Device Programming
A methodology playbook for taking a routed implementation all the way to live silicon — either a volatile JTAG download (lost on power cycle) or a non-volatile flash burn (boots on power-up). Programming hardware is a one-way, physical action: this skill is deliberately conservative. It refuses to fabricate a "programmed OK" claim, refuses to skip sign-off gates, and hands control back to the human at every ambiguous fork (which device, which flash part, which boot mode).
This skill is a strategy layer over the SynthPilot MCP server. It does not write code; it decides which real tools to call, in what order, and when to STOP.
When to use
- User wants a
.bitproduced from the current implemented design. - User wants to download a design to a board over JTAG for a bench test (volatile — gone after power cycle).
- User wants to flash the design (
.mcs/.bin) into SPI/BPI configuration memory so the FPGA boots it automatically on power-up. - User reports a board that "doesn't come up after power cycle" (almost always a flash / boot-mode issue, not a JTAG issue).
- User wants an
.xsahand-off to Vitis (export hardware with bitstream).
When NOT to use
- Timing is not met / design is not routed. A
.bitfrom a design with setup/hold violations may program but will behave non-deterministically. Close timing first (use the timing-closure skill). Do not generate a sign-off bitstream over an open WNS violation without an explicit, stated user override. - Synthesis/implementation has not run or is stale relative to the RTL. Generating a bitstream does not re-run P&R; it ships whatever is in the run. Run/refresh implementation first.
- Debug-core insertion (ILA/VIO) — that belongs to the debug/instrumentation
skill. This skill only consumes an already-inserted
.ltxprobes file. - Pure simulation requests — use the simulation skill.
- Block-design / IP build — use the block-design skill; come back here once a routed implementation exists.
Prerequisites (verify first)
Do not assume state. Probe it with real tools before acting.
- MCP / Vivado / Tcl bridge alive —
test_connection. If this fails, nothing downstream can work; stop and tell the user to start Vivado and the Tcl server. - A project is open and is the right one —
get_project_info. Confirm the part/board matches what the user intends to program. The wrong part silently produces a bitstream the device will reject. - Implementation is complete and current —
get_run_status. The implementation run must beroute_design Complete(or equivalent "routed"). If it issynth-only, out of date, or failed, the design is not ready — go run/finish implementation (see Methodology step 1) before any bitstream. - For any JTAG/flash step: a board is physically present. This cannot be inferred from software state alone. The hardware-manager connect chain (Methodology step 5) is what discovers it; if no target appears, STOP and ask the user to plug in / power on the board and check the cable.
State everything you found before proceeding. If a prerequisite is missing, report it and stop — do not improvise around a missing board or an unrouted run.
Methodology (real tool calls, in order)
The flow has three phases: (A) sign-off gate → (B) bitstream → (C) deliver to device. Phase C splits into a volatile JTAG lane and a non-volatile flash lane. Pick the lane from the decision table below; do not run both blindly.
Phase A — Sign-off gate (MUST pass before any bitstream)
A bitstream is only as trustworthy as the implemented design behind it. These are fresh-evidence gates: read them now, do not trust a prior claim.
Ensure a complete implementation exists.
get_run_status→ if not routed, run it. For multi-minute P&R prefer the async pattern:run_implementation_async, then pollget_run_statusuntil complete. (run_implementationis the synchronous fallback for short runs.)- On completion,
open_implemented_designso the reports below read the routed netlist, not synthesis.
Route completeness —
report_route_status. Every net must be fully routed. Any unrouted / partially-routed / conflict nets ⇒ not signable — stop and route (or report the failure). A.bitover an incomplete route is invalid.DRC —
report_drc. Resolve (or consciously, with the user, accept) Critical Warnings/Errors before programming. Bitstream-relevant DRCs (e.g.DRC BIVRT, unconstrained I/O, config-bank/voltage, BUFGCE/clock placement) can produce a.bitthat damages or refuses to configure the part. Do not waive a config/IO DRC just to get a green light — see Safety rails.Timing sign-off —
report_timing_summary. Read WNS/TNS/WHS fresh.- WNS ≥ 0 and WHS ≥ 0 (no setup/hold failures) ⇒ pass the timing gate.
- WNS < 0 or WHS < 0 ⇒ the design is not signed off. Do not silently proceed. Report the violation and hand back to timing-closure. Only generate a bitstream over open violations if the user explicitly says "I know timing fails, build it anyway for a quick bench test" — and then label the artifact as not sign-off quality in the Output.
Gate rule: a "ready to program" claim REQUIRES fresh
report_route_status+report_drc+report_timing_summaryoutput in this session. Never infer it.
Phase B — Generate the bitstream
- Generate —
generate_bitstream(synchronous;jobsdefaults to 4).- This step embeds the routed configuration and (if debug cores were inserted)
emits a
.ltxprobes file next to the.bit. - On return, capture the reported
.bitpath. If generation fails, read the error summary it returns — common causes are config-bank voltage (CONFIG_VOLTAGE/CFGBVS) orBITSTREAM.*property DRCs surfaced only at write time. Fix the property/constraint (smallest safe change), re-run the Phase-A DRC, and regenerate. Do not retry blindly.
- This step embeds the routed configuration and (if debug cores were inserted)
emits a
Phase C — Deliver to the device
Choose the lane from the Decision table. Establish the hardware connection (common to both lanes) first.
Connect to hardware (JTAG/flash both need this):
open_hardware_managerconnect_hardware_server(defaults tolocalhost:3121; pass aurlfor a remotehw_server).open_hardware_target(empty arg auto-selects the first target).list_hardware_devices— confirm the discovered device matches the project part from step (Prereq 2). If the chain is empty, STOP: no board / bad cable / hw_server not running. If the part mismatches, STOP and ask — programming the wrong device is a hardware risk.
Shortcut:
quick_programauto-connects and downloads the current project bitstream in one call (and auto-skips Zynqarm_*debug devices). Prefer it only when the chain is unambiguous (single FPGA, default hw_server) and Phase A has already passed. For multi-device chains, remote servers, or any ambiguity, use the explicit connect chain above so you can verify the device before committing.
Lane 1 — Volatile JTAG download (bench test; lost on power cycle)
- Program over JTAG —
program_device.- Leave
bitstream_pathempty to use the project default, or pass the path captured in step 5. - It auto-associates a
.ltxprobes file found beside the bitstream and refreshes the device afterward. - If you need a fresh status snapshot,
refresh_hardware_device. - Verify, don't assume: report the tool's success/DONE status as the evidence. A volatile download is not persistent — say so explicitly so the user knows a power cycle wipes it.
- Leave
Lane 2 — Non-volatile flash (boots on power-up)
Pick the flash part — ask, don't guess. The configuration-memory part number and interface (SPI x1/x2/x4, QSPI, BPI) are board-specific. The wrong part/width burns a non-bootable image. If the user hasn't named the exact part, ask. Then
add_flash_configurationwith the correctflash_type(e.g. as25fl…,mt25q…, etc. part string).Build the flash image —
generate_mcs.- Inputs:
bitstream_path(from step 5), an outputmcs_path, andflash_size(MB) that matches the physical flash density (default 128). A size larger than the device, or a wrong start address, yields a non-bootable image. - For QSPI boot, confirm the design's
BITSTREAM.CONFIG.SPI_BUSWIDTH/CONFIG.CONFIGRATEmatch the flash wiring; a x4 image into x1 wiring won't boot. If these properties are unset, raise it before burning.
- Inputs:
Burn the flash —
program_flashwith themcs_filefrom step 8.- This writes (and the tool verifies) the configuration memory. Report the tool's verify result as evidence.
Prove it boots from flash — the only real test of a flash burn. A successful write+verify proves the bytes are in flash; it does not prove the FPGA will configure from them. Instruct the user to set the board to the correct boot mode (e.g. QSPI/Master-SPI strap or
MODE[2:0]pins), power-cycle, and confirm the DONE LED / design behavior. Thenrefresh_hardware_device/list_hardware_devicesto see the device now re-configured from flash. If it doesn't come up, this is the classic "won't come up after power cycle" failure — go to the troubleshooting table.
Optional — Hand off to embedded software
- If the user wants Vitis / bare-metal / Linux work,
export_hardware(include_bitstream=True) to emit the.xsa, then hand off to the embedded skill. Do not attempt the software build here.
Decision table — which lane and which fix
| Symptom / request | Likely cause | Smallest safe action (in order) |
|---|---|---|
| "Just test it on the bench now" | Volatile download is fine | Lane 1: program_device (or quick_program if chain is unambiguous) |
| "It must boot by itself on power-up" | Needs non-volatile config memory | Lane 2: add_flash_configuration → generate_mcs → program_flash → verify boot |
generate_bitstream fails with CFGBVS/CONFIG_VOLTAGE DRC |
Config bank voltage not declared | Add/correct CFGBVS/CONFIG_VOLTAGE in XDC (constraint, not RTL), re-run report_drc, regen |
generate_bitstream fails with unconstrained-I/O DRC |
Pins/IOSTANDARD missing | Add I/O constraints (create_io_constraint), re-run report_drc, regenerate |
list_hardware_devices returns empty |
No board / cable / hw_server down | STOP. Ask user to connect & power the board; check JTAG cable; confirm hw_server running |
| Discovered device ≠ project part | Wrong board, wrong target, or wrong project open | STOP. Do not program. Reconcile target vs part with the user |
Zynq: extra arm_* targets on chain |
PS debug devices appear alongside the PL | Program the PL FPGA device; quick_program auto-skips arm_* |
| JTAG download works, but dead after power cycle | Design was only in volatile SRAM config, not in flash | Lane 2: program flash + set correct boot-mode straps + power-cycle |
| Flash burned + verified, still won't boot from flash | Wrong boot mode, wrong flash part/size, or bus width | Re-check flash_type & flash_size vs board; check boot-mode pins & SPI_BUSWIDTH; re-burn |
| WNS < 0 but user wants a bitstream | Design not signed off | Report violation; default = refuse sign-off .bit; build only on explicit "bench test anyway" |
| Need Vitis / software image | Hardware hand-off | export_hardware(include_bitstream=True) → embedded skill |
Programming loop + STOP conditions
Programming is iterative only on failure-to-configure; a clean program is a single pass. The loop exists to converge a non-booting device, one change-class per iteration so cause→effect is attributable.
[Phase A gates] → generate_bitstream → connect HW → verify device==part
→ program (Lane 1 or Lane 2) → READ device status (fresh)
│
configured/DONE asserted? ──yes──► STOP (success, with evidence)
│ no
▼
Classify ONE failure class (boot mode | flash part/size | bus width |
config DRC | wrong device) → apply ONE fix
→ re-verify with a tool → loop
STOP immediately (do not iterate) when:
- No board / chain empty → hand back to user (physical action required).
- Discovered device ≠ project part → never program a mismatched device.
- A DRC/timing gate is failing and the user has not explicitly authorized a non-sign-off build → hand back to the relevant skill.
- Success: the device reports configured / DONE asserted (JTAG lane), or the
board re-configures from flash after a power cycle (flash lane), confirmed by a
fresh
refresh_hardware_device/list_hardware_devices.
STOP and present options (don't thrash) when:
- You've tried the obvious fix in a failure class (e.g. corrected
flash_typeonce) and it still won't boot. Surface the remaining hypotheses (boot-mode straps, flash density, bus width, board power) with their costs, and hand back to the human. Do not loop on flash parts blindly — each burn wears the device and may not be the real cause.
Safety rails (do not violate)
No fake-pass on the sign-off gate. Never waive a route/DRC/timing failure — or apply
set_false_path/waive_lint_violation/ disable a DRC — purely to makegenerate_bitstreamsucceed or to declare the design "ready". A config-bank, I/O, or clocking DRC can mean the bitstream will not configure or could electrically stress the part. If a violation might be real, fix it or ask the user; state any assumption explicitly.Evidence before claims — always. "Bitstream generated", "device programmed", "flash verified", "boots from flash" each REQUIRE the corresponding fresh tool output in this session (
generate_bitstreampath,program_device/program_flashstatus,refresh_hardware_device/list_hardware_devices). Never infer success from a prior step, and never report a flash burn as "boots" until a power-cycle re-config is observed.Confirm the target device before you commit. Always reconcile
list_hardware_devicesagainst the project part beforeprogram_device/program_flash. Programming the wrong device or wrong flash part is a physical hazard, not a software typo.Ask before destructive / board-specific choices. Flash part number, flash size, bus width, and boot mode are board facts you cannot derive from the project. If unknown, ask — do not pick a plausible default and burn it.
Smallest safe change first. Bitstream-write DRC failures are almost always constraint/property fixes (XDC:
CFGBVS,CONFIG_VOLTAGE, IOSTANDARD,BITSTREAM.*), not RTL. Fix constraints first. Recommend — never silently apply — any RTL change; that re-opens synth/impl and a new sign-off.Volatile vs non-volatile must be stated. Always tell the user whether what you just did survives a power cycle. A JTAG
program_devicedoes not; only a flash burn does.One change-class per iteration. When chasing a non-booting board, change exactly one thing (boot mode or flash part or bus width) and re-measure, so the fix that worked is unambiguous.
Output
Report concisely, with evidence quoted from tool output, not narration:
- Readiness gate — route status (fully routed?), DRC (Critical count and any un-waived items), and timing (WNS / WHS / TNS), each with the tool that produced it. State pass/fail explicitly. If any gate failed and you proceeded anyway, label the artifact NOT sign-off quality and name the override.
- Bitstream — the
.bitpath returned bygenerate_bitstream, and whether a.ltxprobes file accompanied it. - Target — the discovered device(s) from
list_hardware_devicesand explicit confirmation it matches the project part. - Programming result —
- Lane 1:
program_devicestatus (DONE asserted / configured), and a clear note that this is volatile (lost on power cycle). - Lane 2:
flash_type,flash_size, the.mcspath, theprogram_flashwrite+verify result, and the boot-mode + power-cycle instruction the user must perform — plus the post-power-cyclelist_hardware_devicesevidence if obtained.
- Lane 1:
- If stopped: the exact blocking condition (no board / device mismatch / failing gate / exhausted safe options) and the specific decision or physical action handed back to the user — with options + costs, not a guess.
Never end with an unverified "done." End with the evidence, or with the precise reason you stopped.