Change ESI wrapper ports#129
Conversation
Bundle ports for external functions and export-class callbacks are now
declared as kanagawa.port.output instead of kanagawa.port.input. The
underlying scalar data direction is unchanged: channel directions inside
the bundle flip ('from' <-> 'to') so that the wrapper still produces
arguments and consumes any results.
EmitEsiWrapper takes the new direction via PushPopEsiBundle's
isOutputBundle flag and switches between the input-bundle pattern
(InputPort + Read + Unpack) and the output-bundle pattern (Pack +
OutputPort + Write).
Export function bundles continue to be emitted as input bundles.
[[async]] export functions and [[async]] callbacks (with backpressure) each produce exactly one ESI channel — there is no return-value channel because [[async]] functions and callbacks are always void. Wrapping such a single channel in a one-element bundle is unnecessary noise for PyCDE consumers, so EmitEsiWrapper now exposes them directly as ports of !esi.channel<...> type: - async export functions become input channel ports - async callbacks become output channel ports Multi-channel bundles (regular functions, regular callbacks) still go through the bundle/pack/unpack path.
[[no_backpressure]] functions and callbacks were previously kept out of
the ESI bundle/channel path entirely and exposed as raw scalar valid +
payload ports. Now that CIRCT supports ChannelSignaling::ValidOnly along
with esi.wrap.vo / esi.unwrap.vo, those ports go through the same
EmitEsiWrapper path as backpressured ones and are emitted as
!esi.channel<..., ValidOnly>.
Specifically:
- Free [[no_backpressure]] [[async]] callbacks: bare ValidOnly output
channel.
- Export functions that are no_backpressure but not fixed-latency: input
bundle whose arg and result channels are both ValidOnly.
- Fixed-latency export results have no Valid signal at all and remain
raw scalars (no ESI wrapping possible).
The signaling decision in EmitEsiWrapper now infers the protocol from
which control signals are present per direction:
* Ready -> ValidReady
* ReadEnable / Empty -> FIFO
* Valid only -> ValidOnly
Adds an interface.circt.esi_wrapper_ports test under test/interface/circt/
that compiles a small program exercising every combination of {export,
callback} x {regular, async, no_backpressure}, then runs a python script
that asserts each port lowers to the expected EsiWrapper shape and
forbids the pre-refactor shapes (input callback bundles, single-channel
async bundles).
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Reworks ESI wrapper port shapes so that callbacks become outputs, [[async]] functions become bare ESI channels (instead of single-element bundles), and [[no_backpressure]] functions/callbacks use the new ESI ValidOnly signaling protocol. A new test harness compiles a representative source file with --skip-circt-lowering and greps the emitted CIRCT MLIR to validate every port shape combination.
Changes:
- Extend
EmitEsiWrapperwith output-bundle, bare-channel, andValidOnly(wrap/unwrap) lowering paths, and letBeginEsiBundle/PushPopEsiBundlecarry an output-bundle flag. - In
verilog.cpp, callbacks are always emitted into a bundle and registered as output bundles, and exports get a bundle whenever ESI can describe the signaling (hasBackpressure || !fixedLatency). - Add a CMake-driven CIRCT MLIR check that compiles
esi_wrapper_ports.kand validates each port declaration viacheck_esi_wrapper_ports.py.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| compiler/cpp/circt_util.h | Adds isOutputBundle parameter and EsiBundleInfo struct to track per-bundle direction. |
| compiler/cpp/circt_util.cpp | Implements ValidOnly wrap/unwrap, output-bundle pack path, and bare-channel ports. |
| compiler/cpp/verilog.cpp | Updates export/callback bundle decisions and tags callback bundles as output. |
| test/interface/circt/esi_wrapper_ports.k | New Kanagawa source covering all 6 export/callback × signaling combinations. |
| test/interface/circt/check_esi_wrapper_ports.py | Regex-based MLIR checker for the expected and forbidden port shapes. |
| test/interface/circt/CMakeLists.txt | New add_circt_mlir_test helper wiring prepare/mkdir/compile/test fixtures. |
| test/interface/CMakeLists.txt | Hooks the new circt subdirectory into the interface test suite. |
Comments suppressed due to low confidence (1)
test/interface/circt/check_esi_wrapper_ports.py:1
- Only the first
.mlirfile (alphabetically) is inspected. If the compiler emits more than one.mlirfile into the output directory, port-shape regressions in the other files will be silently ignored. Consider concatenating the contents of all matched files (or iterating over them) before running the substring/forbidden checks, or asserting that exactly one file is expected.
#!/usr/bin/env python3
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- circt_util.cpp: replace literal 0/1 indices in the bare-channel branch with named constants (kFromGeneratedHwIdx / kToGeneratedHwIdx) and assert(valid) immediately before WrapValidOnlyOp::create to enforce the invariant at the point of use (Copilot review comments on #129). - verilog.cpp: minor formatting tweak for GetBasicBlockInstanceName. - test/interface/circt: trim duplicated comments and add a TODO noting that the python checker should ideally use the CIRCT Python API.
79f1c78 to
86a3952
Compare
blakepelton
left a comment
There was a problem hiding this comment.
LGTM. At some point, consider adding documentation in the doc directory for what the ESI interface looks like for an exported class.
After some experience importing and using ESI ports, I've changed my mind about a few things: callbacks should be outputs rather than inputs and
[[async]]functions should be channels rather than bundles since bundles are kind of a pain.Also, ESI recently added a "ValidOnly" signaling standard so we can use that for
[[no_backpressure]]functions and callbacks.Assisted-by: vscode:Claude Opus 4.7