Probe Dialect
The Probe dialect provides SSA handles for observation of hardware values. A probe handle can be passed through module outputs and used where access to the observed value is needed, without representing that relationship as ordinary hardware dataflow or committing to a particular hierarchical path representation.
Rationale ¶
Hardware IR often needs to preserve an observation relationship across module
boundaries. Routing the observed value through ordinary ports changes the
module interface and may introduce unnecessary data dependencies. The Probe
dialect represents this relationship explicitly: !probe.ref<T> is a
read-only handle to a value of type T, created by probe.send and observed
by probe.read. A read does not require the compiler to materialize ordinary
hardware dataflow from the probe origin to the read site.
A probe reference provides read-only access to an observed hardware value.
Its payload type must be accepted by the HW probe type classification. The
current implementation supports integer and non-inout HW value types,
!seq.clock, and HW aggregates recursively containing supported types.
Dialects may extend the set of supported payload types through
hw::ProbeTypeDialectInterface. Writable or bidirectional hardware references
are not supported.
Probe references may be exposed through HW module output ports. They must not appear, directly or nested in an aggregate, on input or inout ports. Frontends must legalize such cases to ordinary ports, XMRs, or another suitable representation before creating Probe dialect IR. This keeps the producer of an observation explicit in the module hierarchy. This restriction simplifies compilation for a wide range of backends.
Supported Placement and Propagation ¶
The initial Probe dialect supports the following narrow path: probe.send and
probe.read appear directly in an hw.module body, a probe reference is
returned through an output port, and the corresponding hw.instance result is
consumed by probe.read in the enclosing module body. This is the only
cross-module propagation path for which the dialect currently defines
semantics.
The Probe operations themselves cannot be placed in procedural regions such as
hw.triggered, or in other nested regions. Probe handles must not be created or
read inside those regions. Procedural logic should consume an ordinary hardware
value obtained by reading a probe in the enclosing module body. The dialect
does not define semantics for passing a probe reference across a region
boundary; such uses should be legalized before creating Probe dialect IR.
Probe references propagated through instance-choice operations are currently unsupported. The dialect does not define how a probe reference is associated with the selected module, so FIRRTL lowering must diagnose or reject such uses until the required semantics are specified.
Probe references are not supported as HW inner-symbol targets. This applies
both to a !probe.ref<T> value and to any field containing one. Other
propagation paths through generic operations are similarly outside the current
Probe dialect contract, even if those operations accept the type through a
generic type constraint such as AnyType.
Example ¶
The producer creates a probe handle for %in and returns it through an output
port. The consumer receives the handle from an instance and reads the observed
value through it.
hw.module @Producer(in %in: i8, out p: !probe.ref<i8>) {
%p = probe.send %in : i8
hw.output %p : !probe.ref<i8>
}
hw.module @Consumer(in %in: i8, out out: i8) {
%p = hw.instance "producer" @Producer(in: %in: i8) -> (p: !probe.ref<i8>)
%value = probe.read %p : <i8>
hw.output %value : i8
}
probe.send accepts any SSA value whose type is valid as the payload of a probe
reference, including the result of an expression. It produces only the probe
reference; ordinary dataflow consumers continue to use the original SSA value:
%value = comb.xor %a, %b : i8
%ref = probe.send %value : i8
%next = comb.xor %value, %c : i8
A probe observes the value passed to probe.send, not a particular SSA
definition or expression representation. Optimizations may rewrite the
producer, retarget the probe, or remove an unused probe handle as long as
probe.read observes the same value. The observed value does not need to have
an explicit name in the IR. A backend may generate a name when required, but
automatically generated names are implementation details and are not
guaranteed to remain stable across compiler runs or IR transformations.
External-module probe ABIs are presently outside the scope of this dialect definition.
Types ¶
RefType ¶
Read-only hardware probe handle
Syntax:
!probe.ref<
::mlir::Type # elementType
>
A probe.ref type is an SSA handle for read-only observation of a hardware
value. The handle does not encode or require a particular hierarchical path.
Its payload type must support probe observation.
Parameters: ¶
| Parameter | C++ type | Description |
|---|---|---|
| elementType | ::mlir::Type | type supported for probe observation |
Operations ¶
probe.read (circt::probe::ReadOp) ¶
Read the value observed by a probe handle
Syntax:
operation ::= `probe.read` $input attr-dict `:` type($input)
probe.read returns the value observed through its input probe handle. It
does not require the compiler to materialize ordinary hardware dataflow
between the origin of the probe and the read site.
The result is the hardware value observed through the read-only probe handle.
Traits: AlwaysSpeculatableImplTrait, HasParent<hw::HWModuleOp>
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
input | probe ref type |
Results: ¶
| Result | Description |
|---|---|
result | type supported for probe observation |
probe.send (circt::probe::SendOp) ¶
Create a read-only probe handle for a hardware value
Syntax:
operation ::= `probe.send` $input attr-dict `:` type($input)
probe.send creates a read-only probe handle for an arbitrary SSA hardware
value. The ref result represents an observation of that value and does not
represent ordinary hardware dataflow. Users that also consume the input
value should use the original SSA value directly.
The observed value does not need to have an explicit name in the IR. A backend may generate a name when required. Automatically generated names are implementation details and are not guaranteed to remain stable across compiler runs or IR transformations.
Traits: AlwaysSpeculatableImplTrait, HasParent<hw::HWModuleOp>
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands: ¶
| Operand | Description |
|---|---|
input | type supported for probe observation |
Results: ¶
| Result | Description |
|---|---|
ref | probe ref type |