This commit introduces a standardized synthesis pipeline and restructures the codebase:
* Creates a new SynthesisPipeline class to define the default synthesis pipeline. This pipeline serves both circt-synth and is exposed through the C API for Python bindings.
* Added a dedicated Synthesis directory under `lib/` to house synthesis-related code. This architectural change is aimed to promote synthesis capabilities to a first-class component within CIRCT rather than limiting it to the circt-synth tool.
This commit adds comprehensive Python bindings for the AIG (And-Inverter Graph) dialect.
The implementation includes an AIG C API header with dialect registration and an AIG C API implementation with pass registration.
It adds an AIG Python dialect TableGen file and Python dialect module. The AIG Python module C++ bindings are implemented using nanobind.
The implementation follows the pattern used by other CIRCT dialects
and enables Python users to work with AIG operations like and_inv through the
circt.dialects.aig module.
- Register the kanagawa dialect in Python bindings
- Register kanagawa dialect passes
- Add C API header and implementation for kanagawa dialect
- Add integration test for kanagawa dialect and passes
Follows the same pattern as pipeline dialect registration in commit 5c4d8ae.
This is a first implementation for if-statements and for/foreach-loops. We probably want to iterate on that because the stack frame manipulations and accessing is not great.
This follows the general nanobind porting guide and the upstream MLIR
changes in the same vein. For the most part, this is a very direct
migration accomplished with sed.
There were a couple minor differences.
Nanobind is more strict about implicit casting, which popped up in a
couple places:
* In MSFTModule, getNearestFreeInColumn was expecting a
CIRCTMSFTPrimitiveType (int), but was actually being passed
PrimitiveType enums at the call sites. Nanobind refused to
automatically cast enum to int, so it was done manually.
* In SVModule, SVAttributeAttr.get was expecting a bool for
emitAsComment, even though it was declared as having a default of
None. Nanobind refused to automatically cast None to bool, so it was
done manually, with a default of false.
Nanobind also prints enums slightly differently, so one FileCheck test
had to be updated for ESI.
Otherwise, the changes were purely mechanical.
This adds `walk_with_filter` python method to invoke callbacks
only for subset of operations. We require GIL to call python function
so this could improve performance of the tools based on Python API.
```
Starting walk_with_filter
walk_with_filter elapsed time: 0.005462 seconds cnt=1
Starting operation.walk
operation.walk elapsed time: 1.061360 seconds cnt=2
```
Add the emit dialect to the C-API and to Python. This is both missing and
is necessary for downstream Python tooling to not break.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This adds the usual Python API structure and dialect registration
boilerplate, as well as Python APIs around the Evaluator library.
The C++ implementations with pybind are intended to be as minimal and
straightforward as possible, simply wrapping the CAPI.
In order to provide a handy user-facing API, a couple of the C++
implementations are wrapped in pure Python to provide a nicer
interface:
The Evaluator constructor is wrapped in Python to also set up a logger
and diagnostic handler that uses the logger. This allows the CAPI and
C++ implementation to avoid dealing with Diagnostics. The CAPI simply
returns null on failure, and the C++ implementation simply throws a
Python error in this case. The pure Python diagnostic handler ensure
the error and any notes are logged before the error is thrown.
The Evaluator instantiate method is also wrapped in Python to handle
a few things required to provide a handy, type-safe API. It takes care
of accepting Python objects for actual parameters, and converting
these to Attributes using an existing helper function. It does a
similar conversion back to Python objects for primitive fields. It
also handles some minor metaprogramming to inspect an incoming
dataclass to determine its fields, extract them from the instantiated
Object, and return an instance of the dataclass.
Note that this initial implementation only supports Attributes in
Object fields in the pure Python wrapper around instantiation. Support
for Objects in Object fields will be added shortly in a subsequent
patch.
In llvm submodule: set branch to main, so can just update with:
$ git submodule update --remote --merge
See PR for summary of significant upstream changes and details of how they were handled:
https://github.com/llvm/circt/pull/3502
This is an initial commit for adding a CAPI for FSM as well as PyCDE support for constructing these.
See `test_fsm.py` for usage.
FSMs are constructed in a similar manner to PyCDE modules through a decorator on a class describing the FSM.
The FSM class may contain inputs (no outputs for now) and must provide
- A dictionary containing the states and their transitions
- A default state
State transitions may be either always taken, or taken based on some guard. This guard is defined by a function provided to the transition, which (like `@generator` functions) acts on the ports of the FSM.
The FSM will then be constructed with an output for each state, asserted when that state is active.
One important implementation note is the fact that the `fsm.machine` operation is treated as a PyCDE Module - there was surprisingly little friction slotting it into the current code and everything works as expected wrt. referencing `fsm.machine` in/out arguments through the transition guard functions.
However, modules instantiating the FSM expect a hardware-like interface, this being the ports of the `fsm.machine` operation + clock and reset signals. An `fsm.machine` op does not have these signals at the top level, since these are added during hardware lowering. To me, this is a sensible design choice, seeing that the FSM dialect should be applicable to both software and hardware representations (...eventually).
To get around this, the user will specify the intended name of the `clock` and optional `reset` signal of an FSM. A wrapper module is then created that provides the correct interface to the instantiating module, as well as instantiating the FSM through a `fsm.hw_instance` operation, doing the proper hoop-jumping to attach the clock signal (see `fsm_wrapper_class`).
There's still some work to do on the CIRCT side of the FSM dialect to clean it up a bit + make it a viable target for a front-end, but this commit represents the brunt of work on the PyCDE side.
Lots of boilerplate which should _really_ be autogenerated. Added support for SystemVerilog attributes to the python bindings for the SV and Seq dialects.
Previously, `circt.msft` contained the attributes and pysical design
functionality, and `circt.dialects.msft` contained the ops. To unify
things and avoid confusion, combine these into the
`circt.dialects.msft` Python namespace.
This makes sure not to rename FIRRTL to HWRTL :-), and I spot checked a
many things to avoid changing general references to RTL (e.g. when referring
to external tools) but I suspect that I missed some. Please let me know (or
directly correct) any mistakes in this mechanical patch.
This enables the new adaptors in integration tests:
* Re-juggle headers to work with new pybind adaptors.
* Use the new utility for getting channel types in ESI.
- Registers the SV passes when the 'circt' Python module is imported and the ESI passes when 'circt.esi' is imported.
- Adds a Python 'export_verilog' call.
- Enables LLVM 'pretty' stack traces for easier debugging. Makes assertion messages appear in Python instead of just crashing with no output.
This new Python API function takes a module and a list of ports then constructs and returns a ESI wrapper module. Sets up the infrastructure for the ESI Python API.
This adds the bindings and just checks that the dialects can be
imported in the integration test. Full integration test is coming, but
I have some small improvements to land first.
This is the first step towards #710. This should be the minimal amount
of boilerplate to set up a Python module such that we can write
`import circt`. Note that this module does not actually bind to or
expose any API at the moment; this is just the boilerplate, and that
will follow.
The setup here is based on both the upstream MLIR Python bindings, as
well as what NPComp does.