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 hdl is already on the PATH (setting hdl.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: 0 done; 1 the work failed (analysis errors, a failing testbench, a refused request); 2 wrong usage, or the command needs an editor window or debug session and there is none.
  • Times are written 50ns or 1.5 us. Values print as VHDL literals ('1', x"05"); --radix hex|bin|unsigned|signed changes that.
  • GHDL, GDB and the C compiler come from HDL_GHDL, HDL_GDB and HDL_CC (set in VS Code terminals from the settings), else ghdl, gdb and gcc on the PATH.
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
jsonc
// 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
jsonc
// 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.

Documentation for HDL Studio 1.0.4.