Dashboard + palette + analyze screen; consolidated categorization rules.
UI restructuring:
- Dashboard (`screen_dashboard.cpp`, `screen_idx = 6`) is the new home
screen at boot. Reads Overview / Health / Analysis / Modules from
the current System every frame; per-module rows list parts grouped
by `connector_type` and a Power/Gnd inference summary (yellow when
any name-Power signal is refuted). Scrollable via PgUp/PgDn/Home/End.
Letter shortcuts: `c`=console, `s`=search, `p`=plug (alias of
connect), `t`=set-type, `e`=explore, `n`=net, `a`=analyze, `q`=quit.
- Global Ctrl-P palette (`screen_palette.cpp`) — fuzzy-finds over
registered commands + module / signal names. Activation runs the
bare command or jumps to the matching screen with state seeded.
- Unified analyze screen (`screen_analyze.cpp`, `screen_idx = 7`):
tabbed layout (`Issues / Groups / Types`), Tab or ←→ to switch
tabs, ↑/↓ to navigate the focused list. Replaces the previous
shell-bouncing `[v]erify` shortcut — `verify` content is now in
the Issues tab. Types tab attaches the decision rationale to each
signal row (fan-out / voltage / hard floor).
- Context help panel: `RenderHelpPanel(title, entries)` in
`tui_helpers.{hpp,cpp}` rendered on the right of every screen.
- Console (former "log") rename: screen 0 is `[c]onsole` in the UI
and "console" in its help-panel title. The underlying screen and
the shell prompt are unchanged.
- Esc from any non-home screen returns to the dashboard. The
dashboard itself swallows Esc; quit via `q` / the `quit` command.
`quit` now calls `screen_ptr->Exit()` directly so it works from
any screen including via the palette.
Signal type inference:
- `Signal::type` defaults to `Other` — auto-inference no longer
happens at construction.
- `infer_signal_types(System*)` is called at the end of every load.
Three rules: GndShield from name alone; Power requires name match
+ a hard fan-out floor (< 3 pins = always Other, regardless of
name or voltage) + at least one positive structural signal
(fan-out ≥ 4 OR voltage pattern in the name like `3V3`, `5V`).
- Thresholds exposed in `analysis.hpp` (`POWER_FANOUT_HARD_FLOOR`,
`POWER_FANOUT_CONFIRM_MIN`, `has_voltage_pattern`) so the analyze
screen can render the same rationale without duplicating logic.
- `set-signal-type` still wins; save/restore round-trips the type.
Analysis groups & anomalies:
- New `GroupKind::DiffBus` — ≥ 2 diff pairs sharing the same
outer-stem with consecutive integer indices are aggregated into a
single bus (`MDI[0..3]_P/N`). `MDI0` and `PCIE_TX_0` index forms
both accepted. Solo pairs under a bus-able stem fall back to
`DiffPair`.
- New `AnomalyKind::DiffBusGap` for missing lanes.
Documentation:
- `DESIGN.md`: dedicated "Categorization rules (normative)" section
consolidating signal type, NC origin, signal groups, anomalies,
component kind, and connector wiring rules with exact thresholds
and decision order.
- `doc/user/analysis.md` (new): user-facing version of the same
rules in plain language. Linked from `doc/user/index.md`.
Tests: +6 new cases (62 total). Adjusted `test_persist.cpp` to set
the signal type explicitly in the fixture (no more auto-inference).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
136
doc/user/analysis.md
Normal file
136
doc/user/analysis.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# essim — how the analysis classifies things
|
||||
|
||||
essim looks at signal names and the way pins are wired to decide
|
||||
whether a net is a **power rail**, a **ground**, a **diff pair**, a
|
||||
**bus**, etc. This page summarises those rules in plain language so you
|
||||
know what to expect when you run `analyze` (the `[a]` shortcut on the
|
||||
dashboard) or when you read the numbers on the home screen.
|
||||
|
||||
Nothing here mutates anything you cannot fix manually: every
|
||||
inference can be overridden with `set-signal-type`, and the rules are
|
||||
re-run on every `load` so the picture stays consistent with the
|
||||
netlists currently in memory.
|
||||
|
||||
## Signal type — Power / Gnd / Other
|
||||
|
||||
Every signal is classified into one of three buckets.
|
||||
|
||||
**Gnd** if the name matches one of:
|
||||
`GND`, `GROUND`, `EARTH`, `SHIELD`, `CHASSIS` (or starts with any of
|
||||
those followed by `_`). The name alone is enough — false positives
|
||||
here are essentially nil.
|
||||
|
||||
**Power** is a two-stage decision:
|
||||
|
||||
1. The name has to suggest power — it contains `PWR`, `POWER`,
|
||||
`VCC`, `VDD`, `VEE`, `VSS`, `VBAT`, or starts with `VS_`, `VS3_`,
|
||||
`+5V`-style or `-12V`-style prefixes.
|
||||
2. The wiring has to corroborate it. essim requires at least one of:
|
||||
- the signal lands on **4 or more pins** (a real rail goes to
|
||||
decouplers + ICs + connectors, so it almost always has many
|
||||
pads), or
|
||||
- the name contains a **voltage value** — `3V3`, `5V`, `12V`,
|
||||
`0V9`, `5V0`, etc. (any `V` next to a digit).
|
||||
|
||||
*Hard floor*: a signal touching **fewer than 3 pins** is
|
||||
**never** Power, even if both 1 and the voltage motif are
|
||||
present. Physically you cannot have a rail on 1 or 2 pads.
|
||||
|
||||
**Other** in every other case.
|
||||
|
||||
This rule deliberately rejects things that look like power but
|
||||
aren't: `PWR_OK` (status), `VSEL_0` (voltage select), `VDD_SENSE`
|
||||
(sense feedback) — they all match step 1 but fail steps 2/3. The
|
||||
analyze screen lists them under **Suspect Power** with the reason
|
||||
attached (`fan-out 1, no voltage` etc.). Inspect, then either accept
|
||||
the suspect status or force it back with `set-signal-type`.
|
||||
|
||||
## NC (no-connect) pins
|
||||
|
||||
A pin is shown as `(NC)` in the explore detail when it has no signal
|
||||
attached. essim distinguishes three reasons:
|
||||
|
||||
- **Imported NC** — the netlist explicitly says the pin is
|
||||
unconnected (Mentor format: signal name `unconnected` or
|
||||
`unconnected (by TERM)`; Altium format: the pin is simply omitted
|
||||
from every signal block).
|
||||
- **Dropped singleton** — after import, essim removes every signal
|
||||
that touches exactly one pin. A net with a single endpoint cannot
|
||||
carry signal anywhere, so the pin is detached and tagged. This
|
||||
catches both intentional sentinels and the per-IC `NC_*` labels
|
||||
that customers often put on dead pads.
|
||||
- **Filled at connect** — when you `connect` two parts that don't
|
||||
agree on which pins exist (a Mentor part may have all pads, an
|
||||
Altium part only the wired ones), essim materialises the missing
|
||||
pads on the smaller side. They are unconnected *locally* on that
|
||||
module but are bridged to a real signal on the other module via
|
||||
the connection — so they do not count as orphans.
|
||||
|
||||
The dashboard's "NC" row summarises orphan counts (imported and
|
||||
dropped only; filled-at-connect pins are excluded). The analyze
|
||||
screen's "Types" tab adds a trailing line with the totals.
|
||||
|
||||
## Signal groups
|
||||
|
||||
essim groups signals that share an obvious structural pattern. They
|
||||
are detected per module — a multi-card bus on the system is the BFS
|
||||
union of the per-module groups it touches.
|
||||
|
||||
**Diff pair** — two signals named `STEM_P` and `STEM_N`
|
||||
(case-insensitive, `_` required before the polarity letter). Both
|
||||
halves must be present. Lone `_P` halves are flagged as orphans;
|
||||
lone `_N` halves are *not* flagged (the `_N` suffix is overloaded
|
||||
with active-low semantics — `RESET_N`, `BOOTMODE_N` — and flagging
|
||||
them would flood the report).
|
||||
|
||||
**Diff bus** — at least two diff pairs whose stems share a common
|
||||
prefix and only differ by a trailing index: `MDI0_P`/`MDI0_N`,
|
||||
`MDI1_P`/`MDI1_N`, … → `MDI[0..3]_P/N`. Both `STEMN` and `STEM_N`
|
||||
forms work (`MDI0`, `PCIE_TX_0`).
|
||||
|
||||
**Bus** — at least two signals with a common stem and a trailing
|
||||
integer index. Two notations: `DATA[0]`, `DATA[1]`, … (bracketed)
|
||||
or `ADDR_0`, `ADDR_1`, … (underscore — *strict*: an underscore is
|
||||
required between the stem and the digits, so a name like
|
||||
`GETH_01_VDD12` is *not* a bus).
|
||||
|
||||
**Anomalies** are emitted alongside groups:
|
||||
|
||||
- *Diff pair orphan*: a `_P` with no matching `_N`.
|
||||
- *Diff bus gap*: e.g. `MDI[0..3]` has `MDI0`, `MDI1`, `MDI3` (`MDI2`
|
||||
missing).
|
||||
- *Bus gap*: same idea on plain buses.
|
||||
|
||||
Internal Mentor net names that start with `$` (like `$N12345`) are
|
||||
skipped from every group/bus detection.
|
||||
|
||||
## Issues reported by `analyze`
|
||||
|
||||
The Issues tab of the analyze screen aggregates everything that
|
||||
deserves attention:
|
||||
|
||||
| Tag | What it means |
|
||||
|---|---|
|
||||
| `[pin-role]` | A connector pin is typed (via `set-type`) as Power or Gnd but the actual signal landing on it disagrees. |
|
||||
| `[net-mix]` | A net bridged across modules carries both Power and Gnd signals — almost always a topology mistake. |
|
||||
| `[diff-pair-orphan]` | `STEM_P` with no `STEM_N` in the same module. |
|
||||
| `[bus-gap]` | A bus is missing one or more index values inside its range. |
|
||||
| `[diff-bus-gap]` | A diff bus is missing one or more lane indices. |
|
||||
|
||||
Zero issues = the module passes every structural check essim knows
|
||||
how to run today.
|
||||
|
||||
## Overrides
|
||||
|
||||
Every classification is advisory. To force a different type:
|
||||
|
||||
- **Signal type**: from the `net` or `explore` screen, press Enter
|
||||
on a signal entry → a popup lets you pick `power` / `gnd` /
|
||||
`other`. Or type `set-signal-type <module> <signal> <type>` in the
|
||||
console (or from the palette).
|
||||
- **Connector type**: `set-type <module> <part> <connector-kind>`
|
||||
(also via the dashboard `[t]` shortcut). This drives the pin role
|
||||
expectations, which feed the `pin-role` check.
|
||||
|
||||
Overrides survive `save`/`restore` but are recomputed at every
|
||||
`load` (i.e. the inference re-runs).
|
||||
@@ -93,6 +93,9 @@ fresh.
|
||||
|
||||
- [`commands.md`](commands.md) — exhaustive command reference,
|
||||
regenerated from the binary on every `cmake --build build --target doc`.
|
||||
- [`analysis.md`](analysis.md) — how essim classifies signals
|
||||
(Power / Gnd / Other), how it detects buses and diff pairs, what
|
||||
the `analyze` screen actually reports and why.
|
||||
- [`scripting.md`](scripting.md) — `set` / `$var` / `${var}`, `source`
|
||||
semantics, the script-save denylist.
|
||||
- [`DESIGN.md`](../../DESIGN.md) — implementation notes, useful if
|
||||
|
||||
Reference in New Issue
Block a user