Network Model¶
The physical shift-topology graph and its node types; see also Nested SIB networks and Multi-arm ScanMux for how these compose.
warptap.icl_model ¶
Pure ICL (Instrument Connectivity Language) data model (implementation_plan.md §7 Stage 4, §3.2). Two genuinely separate structures, confirmed independently by real ICL sources and by Honza255/icl_parser's own design:
- :class:
PhysicalGraph: the physical shift-topology graph. What actually sits on the scan path, in TDI-to-TDO order, and which SIB gates which nested segment. - :class:
ModuleInstance: the module-instantiation tree. Pure lexical containment, used only for dotted-address resolution (top.wrapper.instrument), never for shift-order math. A SIB's own instance name normally does NOT appear in the dotted address of the instrument it gates -- confirmed against real ICL examples that SIB and instrument are siblings under the same enclosing module, not parent/child.
No networkx dependency: real ICL's ScanMux ... SelectedBy <expr> grammar permits
arbitrary multi-arm, multi-bit combinational selects (a real fixture examined this session had
an 11-arm, 4-bit-select mux), which is why icl_parser reaches for a graph library -- but every
arm of a :class:ScanMuxNode (this project's own N-arm generalization of the binary
self-select :class:SibNode) still nests its own independent, non-shared sub-chain, so the
whole physical graph stays a pure tree (no cross-branch sharing, no cycles) regardless of how
many arms a mux has. A plain NamedTuple tree remains sufficient, matching this codebase's
existing no-dataclasses convention (bsr_plan.BsrCell/BsrPlan).
PhysicalGraph ¶
Bases: NamedTuple
SibNode ¶
Bases: NamedTuple
One SIB plus everything it gates (§3.2 structure 1). Exactly one of instrument/
nested is ever populated: a leaf SIB gates one instrument directly; a hierarchy SIB
(instrument=None) gates a nested sub-network instead, recursively -- real IEEE 1687
(a SIB's fromSO binds to either an instrument's SO or another SIB's SO, never
both). :func:validate_physical_graph enforces this invariant, plus global sib_name
uniqueness across the whole tree, on every tree this codebase constructs.
nested widened to tuple["ChainSlot", ...] for the multi-arm ScanMux feature --
annotation-only, no runtime behavior change (no mypy in this repo, and NamedTuple
fields aren't runtime-type-checked): every tree built before ScanMuxNode existed still
only ever puts SibNodes here.
ScanMuxNode ¶
Bases: NamedTuple
An N-arm generalization of :class:SibNode's binary self-select splice -- real IEEE
1687 ScanMux ... SelectedBy <expr> { <value> : <arm>; ... }. Exactly one arm is ever
physically live at a time, chosen by comparing the mux's own select_width-bit self-
select register against each arm's claimed value(s); a value matching no declared arm is
implicit bypass, directly generalizing a closed :class:SibNode's own never-modeled
"closed" state.
select_width is always caller-specified, independent of len(arms) -- a real select
register is often an existing architectural register reused as a selector, not necessarily
sized to exactly fit the arm count (the vendored mux_3 fixture itself demonstrates this
pattern: an 11-arm mux selected by a 4-bit field, wider than len(arms) strictly needs).
arms must have at least 2 entries (validated) -- a 1-arm mux isn't a real mux.
ScanArm ¶
Bases: NamedTuple
One arm of a :class:ScanMuxNode -- the value(s) of the mux's own select field that
route to it, plus exactly one of instrument/nested, the same leaf-xor-hierarchy
invariant :class:SibNode enforces (and for the same reason: real IEEE 1687 has a
ScanMux arm bind to either one instrument or one further SIB/mux, never both).
values is a tuple, not a single int, to stay forward-compatible with real ICL's
multi-value catch-all-arm form (e.g. a real vendored fixture's own mux_3 mapping 6
distinct values to one destination arm) without a future breaking change to this field's
shape -- but v1 requires len(values) == 1 everywhere an arm is actually consumed (this
module's own :func:validate_physical_graph, plus RTL parameter derivation, insertion,
retargeting, and ICL emit/import), so the behavior stays single-value-only until a later
feature deliberately relaxes that one check.
InstrumentNode ¶
Bases: NamedTuple
InstrumentDirection ¶
Bases: Enum
Which way an instrument's bits move real design data (implementation_plan.md §7 Stage 9). One direction per instrument, not per-bit and not real ICL's bidirectional DataInPort+DataOutPort-on-one-TDR shape -- every real signal this project binds so far is cleanly either read-only status or write-only control, never both.
SignalBinding ¶
Bases: NamedTuple
One instrument bit's real host-net binding: bit bit of top-level port
port_name on the module being inserted into. An InstrumentNode with no
signal_bits has no real binding -- v1's original stub behavior, unchanged.
Alias ¶
Bases: NamedTuple
A named, contiguous sub-range within an instrument's own width -- real ICL's
Alias <name>[hi:lo] = <reg>[hi:lo]; construct (confirmed real, e.g. a real fixture's
own Alias okay = DO[0];/Alias mode[3:0] = DI[6:5],DI[3:2];). v1 scopes this to a
single contiguous range referencing one instrument's own register -- real ICL's
concat-of-multiple-sources Alias form (multiple comma-joined ranges in one alias) is
not modeled here; no real caller needs it yet.
ModuleInstance ¶
Bases: NamedTuple
One node in the module-instantiation tree (§3.2 structure 2) -- pure lexical containment for dotted addressing only. v1's tree is flat by construction (every instrument a direct sibling child of the root), matching the confirmed sibling-addressing convention, not a simplification of some deeper structure.
ICLAddressError ¶
Bases: WarptapError
Raised by :func:resolve_dotted_address when a path segment doesn't resolve --
matches BsrInsertError's convention of naming the exact bad input rather than
returning None.
resolve_dotted_address ¶
resolve_dotted_address(root: ModuleInstance, dotted: str) -> ModuleInstance
Walk root's children by each dot-separated segment of dotted in turn.
dotted does not include root.name itself -- it names the path below root,
matching how a real ICL dotted address is relative to the enclosing top module.