The hdl command line
Analyse, simulate, read waveforms, run the Vivado flow and drive the debug session from a terminal, with --json everywhere.
hdl analyses, simulates and debugs VHDL on the same GHDL machinery as F5, without the editor.
- In VS Code terminals
hdlis already on thePATH(settinghdl.cli.addToTerminalPath). It runs with the Node inside VS Code, so nothing has to be installed. HDL Studio: Show CLI Path copies the script’s path for use elsewhere. - Every command takes
--json. Success prints one object{ "ok": true, ... }on stdout; a failure prints{ "ok": false, "error": "..." }and the message also goes to stderr. - Exit codes:
0done;1the work failed (analysis errors, a failing testbench, a refused request);2wrong usage, or the command needs an editor window or debug session and there is none. - Times are written
50nsor1.5 us. Values print as VHDL literals ('1',x"05");--radix hex|bin|unsigned|signedchanges that. - GHDL, GDB and the C compiler come from
HDL_GHDL,HDL_GDBandHDL_CC(set in VS Code terminals from the settings), elseghdl,gdbandgccon thePATH.
hdl --help, hdl run counter_tb --json, hdl signals --at 90ns --file .hdl-studio/counter_tb.ghw, hdl skill --install.Headless or through the bridge#
| Mode | When | Commands |
|---|---|---|
| Headless | always available | workspace, analyse, elaborate, run, flow, program, reports, bd, skill, where; signals and waves from a recording |
| Bridge | a VS Code window has the working folder (or a folder above it) open | status, step, continue, pause, run-for, run-back-to, break, watch, force, stack, open, viewer; signals and waves read the live session |
Each window listens on a private socket (mode 0600) in $XDG_RUNTIME_DIR/hdl-studio. A command picks the window whose folders contain the current directory, where the deepest folder wins. hdl where shows which workspace file, window and session the other commands would use. --no-bridge (or HDL_NO_BRIDGE=1) never talks to an editor, and the setting hdl.cli.bridge turns the socket off.
hdl run is always a separate headless simulation: it does not disturb the debug session of the window.
Project and simulation#
| Command | Does |
|---|---|
hdl workspace [show | create | add-testbench <entity> | set-top <entity>] |
reads or writes the workspace file of this folder or the nearest one above |
hdl analyse |
ghdl -a over the sources, in order; exit 1 on errors, with parsed diagnostics |
hdl elaborate [<top>] |
analyse, then elaborate the top (default: the default testbench) |
hdl run [<testbench>] [--stop-time 2us] [--vcd out.vcd] [--ghw out.ghw] [--timeout 120] |
builds and simulates headless, records <workDir>/<testbench>.ghw; exit 1 when an error or failure assertion fired |
hdl signals [--at 50ns] [--filter <glob>] [--radix hex] [--file x.ghw] |
the values of the signals at a time |
hdl waves [<file>] --signal <path> [--from 10ns] [--to 100ns] |
every change of one signal |
hdl where |
which workspace file, window and session the commands would talk to |
// hdl run --json
{ "ok": true, "testbench": "counter_tb", "endTime": "216 ns", "end": 216000000, "precision": -15, "exitCode": 0,
"assertions": [{ "kind": "report", "severity": "note", "time": "216ns", "file": "/p/counter_tb.vhdl", "line": 59,
"column": 5, "message": "counter_tb: all checks passed" }],
"ghw": "/p/.hdl-studio/counter_tb.ghw", "vcd": null, "signals": 9, "changes": 153, "durationMs": 315 }end is in units of 10^precision seconds. A signal path may be shortened to its last elements when that is unique: hdl waves --signal count.
Driving the debug session#
These need a window with a debug session. Each answers with the state after the command: { ok, state, time, timeText, end, ... }, where state is idle, running, paused or ended. The resuming commands wait up to 30 s for the next stop.
| Command | Does |
|---|---|
hdl status |
state and time of the session |
hdl step [--time 10ns] [--line] |
next time step with activity; by a duration; or the next source line |
hdl continue |
run to the next breakpoint, watch, failing assertion or the end |
hdl pause |
pause a running simulation |
hdl run-for <duration> |
run for a duration |
hdl run-back-to <time> |
go back in time; see Time travel |
hdl break <file>:<line> [--condition <expr>] [--remove] |
a breakpoint of the editor (no session needed) |
hdl watch <signal> [--value <v>] [--remove] |
break when a signal changes, or reaches a value |
hdl force <signal> <value> |
deposit a value ('1', "0101", x"5", 5) |
hdl stack |
the call stack |
hdl open <file.ghw|vcd>, hdl viewer |
open a recording, or the signal viewer |
Vivado#
| Command | Does |
|---|---|
hdl flow <analyse|elaborate|simulate|synth|impl|bitstream|xsim> [--testbench <entity>] [--stop-time 2us] |
one stage of the Vivado flow; the log streams to the terminal |
hdl program [--bit file.bit] [--host host:port] [--verify] |
programs the device through hw_server |
hdl reports |
timing, utilisation and DRC of the last reports |
// hdl flow synth --json
{ "ok": true, "stage": "synth", "exitCode": 0, "durationMs": 29201, "errors": 0, "warnings": 0,
"log": "/p/.hdl-studio/vivado/synth.log", "output": "/p/.hdl-studio/vivado/synth.dcp",
"reports": { "timing": { "wns": 6.97, "met": true }, "drc": { "errors": 0 } } }Block designs#
hdl bd <create|add|set|port|connect|remove|layout|validate|show|wrapper|export-vivado> <file.vbd> ... edits a block design without an editor. Every command appends an event to the .vbd file, authored cli. A refused edit (width mismatch, an output used as a load, a second driver, an unknown entity) exits 1, says why, and leaves the file untouched.
Claude skill#
hdl skill --install writes the Claude skill to .claude/skills/hdl/SKILL.md, and hdl skill --print prints it. See AI agents.