docs: document the BSDL workflow + add a batch/TUI tutorial

DESIGN.md: libbsdl dependency and --batch headless mode; bsdl_model/bsdl_check
in the layout; the attach-bsdl command and the `B` persist tag; PinSpec is now
BSDL-populated; verify's five passes incl. the model-driven and JTAG checks
and the new AnomalyKinds. README: libbsdl dependency, --batch usage, tutorial
link. New doc/user/tutorial.md: end-to-end batch and TUI walkthroughs (load →
tag → connect → attach-bsdl → verify, with the pin/JTAG findings explained).
Regenerated commands.md (adds attach-bsdl); index.md links the tutorial.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 15:46:56 +02:00
parent 581028a83d
commit a4f8254cb3
5 changed files with 274 additions and 10 deletions

View File

@@ -12,8 +12,10 @@ cmake --build build -j
- CMake **3.14+** required (uses `FetchContent_MakeAvailable`). - CMake **3.14+** required (uses `FetchContent_MakeAvailable`).
- FTXUI is fetched at configure time from GitHub (`v6.1.9`, shallow clone). First configure pays ~20 s for the clone; subsequent ones are cached in `build/_deps/`. - FTXUI is fetched at configure time from GitHub (`v6.1.9`, shallow clone). First configure pays ~20 s for the clone; subsequent ones are cached in `build/_deps/`.
- **System dependencies** (resolved via `find_package`): `libzip` (target `libzip::zip`) and `pugixml` (target `pugixml::pugixml`). Used by the ODS importer. Available on Arch via `pacman -S libzip pugixml`. - **System dependencies** (resolved via `find_package`): `libzip` (target `libzip::zip`) and `pugixml` (target `pugixml::pugixml`). Used by the ODS importer. Arch: `pacman -S libzip pugixml`; Debian/Ubuntu: `libzip-dev libpugixml-dev`.
- **`libbsdl`** (standalone BSDL parser, LGPL-2.1) is the sibling repo at `../libbsdl`, pulled in via `add_subdirectory` (path overridable with `-DBSDL_DIR=...`) and linked dynamically (`bsdl::bsdl`; an LGPL `.so` is fine from EUPL essim). Powers the BSDL ingest behind `attach-bsdl`.
- Sources are collected with `file(GLOB_RECURSE ALL_SOURCES "src/*.cpp")`. **After adding a new `.cpp`, re-run `cmake -S . -B build`** — CMake does not re-glob automatically and link will fail with "undefined reference". - Sources are collected with `file(GLOB_RECURSE ALL_SOURCES "src/*.cpp")`. **After adding a new `.cpp`, re-run `cmake -S . -B build`** — CMake does not re-glob automatically and link will fail with "undefined reference".
- **Headless / batch**: `essim --batch --source FILE` runs a script and prints its console output to stdout, then exits without the TUI (good for CI / capturing `verify`). Also `--restore FILE` and `--commands-md [FILE]`. `BootDispatch` runs `--restore`/`--source` synchronously before the event loop (`Source` takes its headless drain branch when no screen is attached), so the console buffer is complete by the time `--batch` dumps it (`Tui::DumpOutput`).
## Layout ## Layout
@@ -35,6 +37,8 @@ src/
CheckIdentityCompatible + FillIdentityNCs CheckIdentityCompatible + FillIdentityNCs
pin_role.{hpp,cpp} pin_role(kind, name) → PinSpec, pin_layout(kind), pin_role.{hpp,cpp} pin_role(kind, name) → PinSpec, pin_layout(kind),
FillPartFromLayout(part, kind) FillPartFromLayout(part, kind)
bsdl_model.{hpp,cpp} BsdlModel (libbsdl C-ABI wrapper) + apply_bsdl(Part*, model)
bsdl_check.{hpp,cpp} check_pin_specs / check_jtag_chain → vector<Anomaly>
nets.{hpp,cpp} find_net / compute_all_nets / net_type_consistent nets.{hpp,cpp} find_net / compute_all_nets / net_type_consistent
analysis.{hpp,cpp} analyze_system → AnalysisReport (diff pairs, buses, anomalies) analysis.{hpp,cpp} analyze_system → AnalysisReport (diff pairs, buses, anomalies)
persist.{hpp,cpp} save / restore (tab-delimited) persist.{hpp,cpp} save / restore (tab-delimited)
@@ -91,7 +95,7 @@ doc/classes.puml -- PlantUML class diagram
- Multi-step prompts work via a `std::deque<Prompt>` queue. `Submit()` pops them one by one before falling back to dispatch. Adding a new command = one entry in `RegisterCommands()`; the prompt-flow and inline-flow are both handled automatically. - Multi-step prompts work via a `std::deque<Prompt>` queue. `Submit()` pops them one by one before falling back to dispatch. Adding a new command = one entry in `RegisterCommands()`; the prompt-flow and inline-flow are both handled automatically.
- Tab completion: at the top-level prompt (no `pending`), completes built-in command names. Inside a prompt with `path_completion = true` (e.g. the `filename` step of `load`), completes file paths via `std::filesystem::directory_iterator` (handles `~/`, dirs get a trailing `/`). Logic: 1 match → replace; multiple with progress on the longest common prefix → extend; multiple stuck at LCP → list candidates in the visualisation area. - Tab completion: at the top-level prompt (no `pending`), completes built-in command names. Inside a prompt with `path_completion = true` (e.g. the `filename` step of `load`), completes file paths via `std::filesystem::directory_iterator` (handles `~/`, dirs get a trailing `/`). Logic: 1 match → replace; multiple with progress on the longest common prefix → extend; multiple stuck at LCP → list candidates in the visualisation area.
Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source`, `script-save`, `connect` (alias `plug`), `set-connector-type`, `set-signal-type`, `explore`, `verify`, `analyze`, `dashboard`, `clear`, `help`, `quit`/`exit`. `Esc` cancels an in-progress multi-step prompt. Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source`, `script-save`, `connect` (alias `plug`), `set-connector-type`, `attach-bsdl`, `set-signal-type`, `explore`, `verify`, `analyze`, `dashboard`, `clear`, `help`, `quit`/`exit`. `Esc` cancels an in-progress multi-step prompt.
`set <name> <value>` declares a session-scoped variable. Subsequent commands expand `$name` and `${name}` in their args (substitution happens in `Finalize` between canonical-form recording and `spec.action(args)` — so `history` and `script-save` keep the **unexpanded** form, while the action sees resolved values). Unknown variables are left literal. `vars` is reset by `new`. Validation: `[A-Za-z_][A-Za-z0-9_]*`. `set <name> <value>` declares a session-scoped variable. Subsequent commands expand `$name` and `${name}` in their args (substitution happens in `Finalize` between canonical-form recording and `spec.action(args)` — so `history` and `script-save` keep the **unexpanded** form, while the action sees resolved values). Unknown variables are left literal. `vars` is reset by `new`. Validation: `[A-Za-z_][A-Za-z0-9_]*`.
@@ -105,7 +109,7 @@ Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source
Pending prompts (from incomplete inline commands) are NOT considered interactive and are filled by subsequent script lines, the way you'd expect. Lines starting with `#` and blank lines are skipped; leading/trailing whitespace is trimmed; `~/` is expanded. Pending prompts (from incomplete inline commands) are NOT considered interactive and are filled by subsequent script lines, the way you'd expect. Lines starting with `#` and blank lines are skipped; leading/trailing whitespace is trimmed; `~/` is expanded.
`save` / `restore` (`src/system/persist.{hpp,cpp}`): tab-delimited line format, no extra deps. Tags: `M` (module), `P` (part with `connector_type`), `N` (pin → signal name; empty = NC; optional 4th field carries `nc_origin_tag()`: `U` = ImportedUnconnected, `D` = DroppedSingleton — omitted when the pin has a signal or when origin is `None`), `S` (signal → type override; only emitted for non-default), `C` (connection header with endpoints + `transform_name`), `W` (wire pair within the current connection). The 4th N field is backward-compatible: pre-existing snapshots without it restore with `nc_origin = None`. `save` / `restore` (`src/system/persist.{hpp,cpp}`): tab-delimited line format, no extra deps. Tags: `M` (module), `P` (part with `connector_type`), `B` (part's attached BSDL `.bsd` path — re-parsed and re-applied on restore; the path is persisted, **not** the derived pin specs), `N` (pin → signal name; empty = NC; optional 4th field carries `nc_origin_tag()`: `U` = ImportedUnconnected, `D` = DroppedSingleton — omitted when the pin has a signal or when origin is `None`), `S` (signal → type override; only emitted for non-default), `C` (connection header with endpoints + `transform_name`), `W` (wire pair within the current connection). The 4th N field is backward-compatible: pre-existing snapshots without it restore with `nc_origin = None`.
**Signals** carry a `type` (`SignalType::Power | GndShield | Other`). The `Signal` constructor **defaults to `Other`** — auto-inference no longer happens at construction. Types are set in three ways, in priority order: **Signals** carry a `type` (`SignalType::Power | GndShield | Other`). The `Signal` constructor **defaults to `Other`** — auto-inference no longer happens at construction. Types are set in three ways, in priority order:
@@ -118,11 +122,13 @@ Pending prompts (from incomplete inline commands) are NOT considered interactive
The explore screen shows the type in the signal detail header. The explore screen shows the type in the signal detail header.
**Pin spec (expected attributes)**: every Pin carries a `PinSpec spec` (`src/system/pin_spec.hpp`) — the *expected* half of verification, set from a model: `function` (Power/Ground/Signal/Clock/NoConnect/Jtag*), `direction` (In/Out/Bidir/Passive/Power), `pad` (physical package terminal, e.g. a BSDL ball), and `source` (which model wrote it). `set-connector-type` populates it via `pin_role(connector_type, pin_name) → PinSpec`. `Pin::expected_signal_type()` is now a **derived accessor**`to_signal_type(spec.function)` (Power→Power, Ground→GndShield, else Other) — not a stored field; the *observed* half stays `Pin::signal()` + the net + inference, and `verify` diffs the two. The framework is wired end-to-end; the VPX 3U lookup (`vpx_3u_role`) is still a stub returning Other for every position, so today every pin's `function` resolves to Unknown → `expected_signal_type()` Other (behaviour unchanged from the old field) — fill in the real VITA 46 layout when needed. `direction`/`function`/`pad` are present but not yet model-populated: they are what the BSDL ingest (`libbsdl`) and the planned contention / undriven-net / NC-wired / JTAG-chain checks will consume. **Pin spec (expected attributes)**: every Pin carries a `PinSpec spec` (`src/system/pin_spec.hpp`) — the *expected* half of verification, set from a model: `function` (Power/Ground/Signal/Clock/NoConnect/Jtag*), `direction` (In/Out/Bidir/Passive/Power), `pad` (physical package terminal, e.g. a BSDL ball), and `source` (which model wrote it). `set-connector-type` populates it via `pin_role(connector_type, pin_name) → PinSpec`. `Pin::expected_signal_type()` is now a **derived accessor**`to_signal_type(spec.function)` (Power→Power, Ground→GndShield, else Other) — not a stored field; the *observed* half stays `Pin::signal()` + the net + inference, and `verify` diffs the two. The VPX 3U connector lookup (`vpx_3u_role`) is still a stub returning Other, so connector-typed pins resolve to function Unknown until that table is filled. **`direction`/`function`/`pad` are populated from BSDL** via `attach-bsdl` (see below) and consumed by the model-driven checks (`check_pin_specs`: contention / undriven / NC-wired) and the JTAG chain check (`check_jtag_chain`), both run by `verify`.
**Connector pin layout (preparation)**: `pin_layout(connector_type)` returns the canonical full pin-name list for a known connector kind, and `FillPartFromLayout(part, kind)` materialises NC pins for any layout position absent from the imported netlist. `set-connector-type` calls it after setting `connector_type` (no-op today since `pin_layout` is a stub returning `{}` for everything — populate alongside `vpx_3u_role`). End-to-end chain in place: `set-connector-type → FillPartFromLayout → pin_role`. **Connector pin layout (preparation)**: `pin_layout(connector_type)` returns the canonical full pin-name list for a known connector kind, and `FillPartFromLayout(part, kind)` materialises NC pins for any layout position absent from the imported netlist. `set-connector-type` calls it after setting `connector_type` (no-op today since `pin_layout` is a stub returning `{}` for everything — populate alongside `vpx_3u_role`). End-to-end chain in place: `set-connector-type → FillPartFromLayout → pin_role`.
**`verify` (three passes)**: (1) walks all typed pins and reports local mismatches between each pin's `expected_signal_type()` (derived from its `PinSpec`) and the actual signal type; (2) walks all bridged nets reporting Power↔GndShield inconsistencies; (3) prints a single-line orphan summary `N orphan pin(s) at import (X imported NC, Y dropped singleton)`. The orphan pass filters out pins that appear in any `Connection::pin_map` — those are bridged to a real signal on the peer module (typically `FillIdentityNCs`-materialised) and not real NCs at system level. The BFS-reached `(module, signal)` set for any signal is shown live in `explore`'s detail pane when a signal entry is selected. **BSDL models (`attach-bsdl`)**: `attach-bsdl <module> <part> <file.bsd>` parses a BSDL device through `libbsdl` (wrapped by `BsdlModel`, `src/system/bsdl_model.{hpp,cpp}`), then `apply_bsdl(part, model)` binds each port to a Pin **by port name first, then by physical pad** — so a netlist that names IC pins either by signal or by package ball both bind. Each bound pin gets its `spec` set: `direction` (BSDL in/out/inout/linkage), `function` (TAP role → Jtag\*, `linkage` → Power/Ground/NoConnect by name, else Signal), `pad` (PIN_MAP ball), `source = Bsdl`. The `.bsd` path is stored on `Part::bsdl_path`, persisted via the `B` tag and re-applied on `restore`. Real-world check: an `xcku15p` FPGA in a VPX system binds 1517/1517 ports.
**`verify` (five passes)**: (1) typed pins — local mismatch between each pin's `expected_signal_type()` (derived from its `PinSpec`) and the actual signal type; (2) bridged nets — Power↔GndShield inconsistencies; (3) orphan summary `N orphan pin(s) at import (X imported NC, Y dropped singleton)` (filters out pins bridged via any `Connection::pin_map` — typically `FillIdentityNCs`-materialised); (4) **model-driven pin checks** (`check_pin_specs`): `DriveContention` (≥2 push-pull `Out` on a net), `UndrivenNet` (a **fully-modelled** net with input(s) but no driver — nets with any Unknown-direction pin are skipped, so un-modelled drivers don't cause false positives), `NcWired` (a no-connect pin on a multi-pin net); (5) **JTAG chain** (`check_jtag_chain`): collects TAP pins by `spec.function`, maps each to its net, emits `JtagTapIncomplete` / `JtagBusUnbridged` (TMS or TCK not common to all TAP devices) / `JtagChainBreak` (dangling TDO/TDI, chain fan-out, or not a single head→tail daisy chain). The BFS-reached `(module, signal)` set for any signal is shown live in `explore`'s detail pane when a signal entry is selected.
**`analyze` (post-processing pass)**: `analyze_system(System*) → AnalysisReport` (`src/system/analysis.{hpp,cpp}`) is a stateless read-only pass that detects structural signal groups and anomalies. Per-module (signals are module-scoped): **`analyze` (post-processing pass)**: `analyze_system(System*) → AnalysisReport` (`src/system/analysis.{hpp,cpp}`) is a stateless read-only pass that detects structural signal groups and anomalies. Per-module (signals are module-scoped):
@@ -290,6 +296,8 @@ The analyze screen additionally surfaces two "verify-class" issues, computed the
- **pin-role mismatch** — a pin whose `expected_signal_type()` (derived from its `PinSpec`, set by `set-connector-type` via `pin_role(connector_type, pin_name)`) disagrees with the actual signal type. - **pin-role mismatch** — a pin whose `expected_signal_type()` (derived from its `PinSpec`, set by `set-connector-type` via `pin_role(connector_type, pin_name)`) disagrees with the actual signal type.
- **net-mix** — a bridged net (BFS over `Connection::pin_map`, ≥ 2 members) where `net_type_consistent(net, &dominant)` returns false. Specifically, the net contains both `Power` and `GndShield` signals. - **net-mix** — a bridged net (BFS over `Connection::pin_map`, ≥ 2 members) where `net_type_consistent(net, &dominant)` returns false. Specifically, the net contains both `Power` and `GndShield` signals.
The `verify` command (not the analyze screen, yet) also emits the **model-driven `AnomalyKind`s** from `bsdl_check.{hpp,cpp}`: `DriveContention` / `UndrivenNet` / `NcWired` (`check_pin_specs`) and `JtagTapIncomplete` / `JtagChainBreak` / `JtagBusUnbridged` (`check_jtag_chain`). They consume the BSDL-populated `PinSpec` plus `compute_all_nets`. Surfacing them in the analyze/dashboard Issues pane is a TODO.
### Component kind ### Component kind
`Part::kind` is inferred at construction (`src/system/component_kind.cpp`) from the leading reference-designator letter(s) of the part name. **Longest-match wins**: `Part::kind` is inferred at construction (`src/system/component_kind.cpp`) from the leading reference-designator letter(s) of the part name. **Longest-match wins**:

View File

@@ -20,6 +20,15 @@ auto-generated reference at [`doc/user/commands.md`](doc/user/commands.md).
A worked bring-up script is at [`test/system.essim`](test/system.essim); A worked bring-up script is at [`test/system.essim`](test/system.essim);
load it with `source test/system.essim`. load it with `source test/system.essim`.
To run a script without the TUI and print its output to stdout (CI-friendly):
```sh
./build/essim --batch --source bring-up.essim
```
Step-by-step walkthroughs for both the batch and TUI workflows are in
[`doc/user/tutorial.md`](doc/user/tutorial.md).
## Dependencies ## Dependencies
- **C++17 compiler** and **CMake 3.14+**. - **C++17 compiler** and **CMake 3.14+**.
@@ -28,6 +37,10 @@ load it with `source test/system.essim`.
- Debian/Ubuntu — `sudo apt install libzip-dev libpugixml-dev` - Debian/Ubuntu — `sudo apt install libzip-dev libpugixml-dev`
- Arch — `sudo pacman -S libzip pugixml` - Arch — `sudo pacman -S libzip pugixml`
- Fedora — `sudo dnf install libzip-devel pugixml-devel` - Fedora — `sudo dnf install libzip-devel pugixml-devel`
- **libbsdl** — the standalone BSDL parser, a sibling repo expected at
`../libbsdl`, pulled in via `add_subdirectory` and linked dynamically.
Override its location with `-DBSDL_DIR=/path/to/libbsdl`. Powers the
`attach-bsdl` command and the pin/JTAG checks.
- Fetched automatically at configure time via `FetchContent` (nothing to - Fetched automatically at configure time via `FetchContent` (nothing to
install): **FTXUI** v6.1.9 and **doctest** v2.4.11. install): **FTXUI** v6.1.9 and **doctest** v2.4.11.
- Optional, only for the `doc` target: **doxygen** and **python3**. - Optional, only for the `doc` target: **doxygen** and **python3**.

View File

@@ -37,7 +37,7 @@ browse modules → parts/signals/connections → details (interactive)
--- ---
### `export` *(interactive)* ### `export` *(interactive)*
export structured data to CSV (kinds: connections; bare form opens the file-picker dialog) export structured data to CSV / ODS (kinds: connections; bare form opens the file-picker dialog)
**Arguments** **Arguments**
@@ -88,6 +88,21 @@ tag a part's connector type for transform lookup
detect signal groups (diff pairs, buses) and structural anomalies detect signal groups (diff pairs, buses) and structural anomalies
**No arguments.** **No arguments.**
---
### `attach-bsdl`
attach a BSDL (.bsd) model to a part and populate pin specs
**Arguments**
1. `module`
2. `part (name or pattern)`
3. `bsdl file (.bsd path)`
**Notes**
- no per-arg prompt: pass all args inline (or run bare for an empty-args path)
--- ---
### `clear` ### `clear`
@@ -238,7 +253,7 @@ execute a file of commands line by line (interactive cmds rejected)
--- ---
### `verify` ### `verify`
check pin roles locally and signal-type consistency across bridged nets check pin roles, bridged-net consistency, and model-driven pin specs (contention/undriven/NC)
**No arguments.** **No arguments.**
--- ---

View File

@@ -1,8 +1,9 @@
# essim — user guide # essim — user guide
A short, task-oriented introduction to using essim. For an exhaustive A short, task-oriented introduction to using essim. For step-by-step
reference of every command, see [`commands.md`](commands.md) (auto- **batch** and **TUI** walkthroughs, see [`tutorial.md`](tutorial.md). For an
generated from the binary). For scripting and `$variable` expansion, exhaustive reference of every command, see [`commands.md`](commands.md)
(auto-generated from the binary). For scripting and `$variable` expansion,
see [`scripting.md`](scripting.md). see [`scripting.md`](scripting.md).
## What essim is ## What essim is
@@ -91,6 +92,8 @@ fresh.
## Where to look next ## Where to look next
- [`tutorial.md`](tutorial.md) — end-to-end batch and TUI walkthroughs,
including BSDL attach + the pin/JTAG checks.
- [`commands.md`](commands.md) — exhaustive command reference, - [`commands.md`](commands.md) — exhaustive command reference,
regenerated from the binary on every `cmake --build build --target doc`. regenerated from the binary on every `cmake --build build --target doc`.
- [`analysis.md`](analysis.md) — how essim classifies signals - [`analysis.md`](analysis.md) — how essim classifies signals

225
doc/user/tutorial.md Normal file
View File

@@ -0,0 +1,225 @@
# essim — tutorial
Two end-to-end walkthroughs of the same work. The **batch** one runs everything
from a script with no terminal UI (ideal for CI or quick reproducible checks);
the **TUI** one drives the same operations interactively.
Both assume essim is built (`cmake -S . -B build && cmake --build build -j` — see
the [README](../../README.md)). For the exhaustive command list see
[`commands.md`](commands.md); for `$variable` expansion see
[`scripting.md`](scripting.md).
---
## 1. Batch mode
`essim --batch --source FILE` runs an essim script and prints the console output
to stdout, then exits — no TUI. The script is the same language you'd type at the
prompt: one command per line, `#` comments, blank lines ignored, `$variables`
expanded, `~/` paths supported.
### 1.1 A first script
Create `bring-up.essim`:
```text
# Load two cards, tag + wire their VPX connectors, then verify.
new
set nl /path/to/netlists
load backplane $nl/backplane.NET altium
load payload1 $nl/payload.qcv mentor
set-connector-type backplane J20 vpx-3u-bkp-p0
set-connector-type payload1 P0 vpx-3u-payload-p0
connect backplane J20 payload1 P0
verify
save system.essim
```
Run it:
```sh
./build/essim --batch --source bring-up.essim
```
Each command is echoed with its result, e.g.:
```text
> load backplane /path/to/netlists/backplane.NET altium
loaded 'backplane' from /path/to/netlists/backplane.NET
> connect backplane J20 payload1 P0
connected: backplane/J20 <-> payload1/P0 via vpx-3u-p0 (59 wires)
> verify
verify: 0 local mismatch(es) over 0 typed pin(s).
verify: 0 inconsistent net(s) over 1 bridged net(s) (... total).
...
```
### 1.2 Attaching a BSDL model and checking the JTAG chain
For complex ICs (FPGAs, big SoCs) you can attach a **BSDL** (`.bsd`) device model
to a part. essim binds each BSDL port to a pin — **by port name first, then by
package ball** — and fills the pin's direction / function / pad. `verify` then
runs model-driven checks on top of the basic ones.
Add this before `verify`:
```text
attach-bsdl payload1 U14 /path/to/bsdl/xcku15p_ffve1517.bsd
```
`attach-bsdl` reports the binding:
```text
payload1/U14: attached BSDL 'XCKU15P_FFVE1517' — 1517/1517 ports bound
```
and `verify` now also prints the model-driven and JTAG passes, e.g.:
```text
verify: 0 model-driven pin anomaly(ies).
[jtag-bus-unbridged] TMS is not common to all TAP devices (off-bus: ...)
[jtag-chain-break] JTAG chain is not a single daisy chain: 3 head(s), 3 tail(s) over 3 TAP device(s)
verify: 3 JTAG chain anomaly(ies).
```
What the new findings mean:
| Finding | Meaning |
|---|---|
| `drive-contention` | ≥2 push-pull outputs share a net |
| `undriven-net` | a **fully-modelled** net has input(s) but no driver |
| `nc-wired` | a no-connect pin is wired onto a multi-pin net |
| `jtag-tap-incomplete` | a TAP device is missing TDI/TDO/TMS/TCK |
| `jtag-bus-unbridged` | TMS or TCK isn't common to every TAP device |
| `jtag-chain-break` | the TDO→TDI daisy chain dangles, forks, or isn't a single path |
`undriven-net` only fires when *every* pin on the net is modelled — otherwise the
driver might sit on a part with no model, so essim stays quiet rather than guess.
The attached `.bsd` path is stored in the `save` snapshot and re-applied on
`restore` (the path is persisted, not the derived pin data), so the model survives
round-trips.
### 1.3 Capturing and chaining
`--batch` exits 0 after the script, so pipe/grep the output like any tool:
```sh
./build/essim --batch --source bring-up.essim | grep -E '\[jtag-|verify:'
```
Layer a script on top of a saved snapshot with `--restore`:
```sh
./build/essim --batch --restore system.essim --source extra.essim
```
---
## 2. TUI mode
Launch with no script:
```sh
./build/essim
```
You land on the **dashboard** — a read-only overview (module / part / signal /
connection counts, health rows, a per-module table). It's the home screen.
### 2.1 Getting around
Dashboard single-key shortcuts:
| Key | Goes to |
|---|---|
| `c` | console (type commands, read output) |
| `p` | plug / connect screen |
| `t` | set-connector-type screen |
| `e` | explore screen |
| `a` | analyze screen |
| `q` | quit |
From anywhere, `Ctrl-P` opens the **command palette** (fuzzy-find a command, or
jump to a module / signal). `Esc` backs out of a screen or cancels a prompt.
### 2.2 The console
Press `c`. This is the textual shell — the same commands as the batch script,
typed one at a time:
```text
> new
> load backplane ~/netlists/backplane.NET altium
> set-connector-type backplane J20 vpx-3u-bkp-p0
> verify
```
Helpers:
| Action | How |
|---|---|
| List commands / help on one | `help`, `help <name>` |
| Tab-complete a command or path | `Tab` |
| Recall previous commands | ↑ / ↓ |
| Scroll output | `PageUp`/`PageDown`, `Home`/`End` |
| Cancel a multi-step prompt | `Esc` |
Any command works inline (`set-connector-type backplane J20 vpx-3u-bkp-p0`) or
**bare** to open its interactive screen (`set-connector-type` then Enter).
### 2.3 Interactive screens
Bare `connect`, `set-connector-type`, `explore`, `analyze` open a full-screen
layout. Conventions: a title bar at the top, `Tab` cycles fields (the active one
flips to reverse video), `Esc` returns to the prompt.
- **connect** (`p`) — pick module A, filter + pick its part, module B, its part,
then Apply. The transform is chosen from the two `connector_type`s.
- **set-connector-type** (`t`) — pick a module, filter + pick a part, type the
kind, Apply. Materialises any missing layout pins and fills each pin's expected
spec.
- **explore** (`e`) — browse modules → parts / signals → pins. Selecting a signal
shows its net (the members reached across connections); Enter on a signal opens
the power / gnd / other popup.
- **analyze** (`a`) — Issues / Groups / Types panes: pin-role mismatches,
bridged-net inconsistencies, diff pairs, buses, structural anomalies.
### 2.4 Attaching BSDL in the TUI
`attach-bsdl` has no dedicated screen — run it inline from the console:
```text
> attach-bsdl payload1 U14 ~/bsdl/xcku15p_ffve1517.bsd
payload1/U14: attached BSDL 'XCKU15P_FFVE1517' — 1517/1517 ports bound
> verify
```
The model-driven and JTAG findings appear in the console output (see §1.2).
(Surfacing them on the analyze screen is planned.)
### 2.5 Saving your work
| Command | Writes |
|---|---|
| `save <file>` | full snapshot (including attached BSDL paths) |
| `script-save <file>` | replay-ready script of this session |
| `source <file>` | run a script line by line |
A common loop: experiment in the console, `script-save` what works, hand-edit it
into a parametrised `$variable` script, then `--batch --source` it for repeatable
runs.
---
## Where to look next
- [`index.md`](index.md) — the user-guide overview.
- [`commands.md`](commands.md) — every command, regenerated from the binary.
- [`analysis.md`](analysis.md) — signal classification, buses, diff pairs.
- [`scripting.md`](scripting.md) — `set` / `$var`, `source` semantics.
- [`../../DESIGN.md`](../../DESIGN.md) — implementation notes (BSDL ingest, checks).