pyCircuit is a Python-based hardware construction DSL that compiles Python modules to an MLIR hardware dialect and emits:
- C++ functional simulation (module instances become SimObjects with
tick()/transfer()) - Verilog (RTL integration + Verilator)
pyc4.0 is a hard-break release focused on ultra-large designs, scalable DFX, and strict IR legality gates.
- Hierarchy-preserving
@moduleboundaries (1:1 with simulation objects) - Two-phase cycle model:
tick()thentransfer() - Gate-first compiler: static-hardware IR legality, comb-cycle checks, logic-depth propagation
- Structured interfaces via
spec(Bundle/Struct/Signature) with deterministic flattening - Integrated
@testbenchflow (device + TB compiled together)
Build the backend tool (pycc):
bash flows/scripts/pyc buildThe staged toolchain is installed under .pycircuit_out/toolchain/install/ by default.
Install a release wheel instead of building locally:
python3 -m pip install /path/to/pycircuit_hisi-<version>-py3-none-<platform>.whl
pycc --versionThe platform wheel bundles the matching pycc toolchain under the pycircuit
package, so pycircuit.cli and the pycc wrapper use the same installed source
tree and do not require a separate repo-local build. The wheel must match both
your OS/architecture and Python 3.10+.
Published package install command:
python3 -m pip install pycircuit-hisiThe distribution name is pycircuit-hisi to avoid the existing unrelated
pycircuit package on PyPI. The Python import path remains pycircuit, and
the installed compiler command remains pycc.
Install the frontend from source for development:
python3 -m pip install -e .
python3 -m pycircuit.cli --helpEditable source install is frontend-only. It does not install pycc; build the
toolchain with bash flows/scripts/pyc build and point PYC_TOOLCHAIN_ROOT at
.pycircuit_out/toolchain/install, or use a release wheel.
Run the smoke gates:
bash flows/scripts/run_examples.sh
bash flows/scripts/run_sims.shfrom pycircuit import Circuit, module, u
@module
def build(m: Circuit, width: int = 8) -> None:
clk = m.clock("clk")
rst = m.reset("rst")
en = m.input("enable", width=1)
count = m.out("count_q", clk=clk, rst=rst, width=width, init=u(width, 0))
count.set(count.out() + 1, when=en)
m.output("count", count)Build a multi-module project (device + TB):
PYTHONPATH=compiler/frontend \
PYC_TOOLCHAIN_ROOT=.pycircuit_out/toolchain/install \
python3 -m pycircuit.cli build \
designs/examples/counter/tb_counter.py \
--out-dir /tmp/pyc_counter \
--target both \
--jobs 8For more end-to-end commands, see docs/QUICKSTART.md.
pyCircuit
├── compiler/
│ ├── frontend/ # Python frontend (pycircuit package)
│ └── mlir/ # MLIR dialect + passes + tools (pycc, pyc-opt)
├── runtime/
│ ├── cpp/ # C++ simulation runtime
│ └── verilog/ # Verilog primitives
├── designs/
│ └── examples/ # Example designs
└── docs/ # Documentation
docs/QUICKSTART.mddocs/FRONTEND_API.mddocs/TESTBENCH.mddocs/IR_SPEC.mddocs/updatePLAN.mdanddocs/rfcs/pyc4.0-decisions.md
| Example | Description |
|---|---|
| Counter | Basic counter with enable |
| Calculator | Stateful keypad calculator |
| FIFO Loopback | FIFO queue with loopback |
| Digital Clock | Time-of-day clock display |
| FastFWD | Network packet forwarding |
| Linx CPU | Full 5-stage pipeline CPU |
pyCircuit is licensed under the MIT License. See LICENSE.