Describe hardware in Python. Compile once. Simulate in C++ or Verilog.
Get started · Language reference · Examples · Repository map · Contribute
pyCircuit is a hardware programming language and compiler built on Python syntax and MLIR. Typed modules, persistent state and stateless rules describe the design. The compiler checks types, dependencies and effects, then emits C++ simulation models and Verilog from the same verified hardware IR.
Use it to build reusable hardware modules, compose stateful designs, and run closed simulation systems with compiler-generated drivers. Python supplies the authoring syntax; capture parses the source without executing the design.
- Hardware semantics in familiar syntax. Fixed-width values, records, Tables, rules and module composition, with explicit admission and diagnostics.
- Two backends, one verified design. GFSIM C++ models and Verilog consume the same final artifact, with source ownership preserved across compilation units.
- Executable systems. A closed
@systemdescribes the DUT, stimulus and checks. The compiler generates native and Verilator simulation harnesses. - Atomic simulation steps. Independent autonomous Rules start from committed state; nested calls share that Rule's sequential candidates. Local Rule declarations are scheduled automatically; independent Rules never forward candidates. Whole-system checks precede commit, so a failed epoch changes no state or clock history and publishes no source observations.
- A separate Runtime package. Generated C++ consumers use the Runtime CMake component without installing LLVM or the compiler development package.
The checkout identifies itself as pyCircuit 6.1. The language is under active development: general parameter-dependent elaboration, broader clock scheduling, wide/four-state observation transport and some collection forms remain limited. The language reference defines supported constructs; known limitations records the boundaries.
# ruff: noqa: F823 -- the nested Rule updates System-owned state.
import pycircuit as ac
@ac.system
def HelloCounter():
count: ac.u8 = 0
@ac.rule
def increment() -> None:
ac.log("info", "count", count)
count = count + 1count is eight-bit persistent storage. The rule observes its current value and
proposes an increment modulo 256. The compiler infers storage, clock/reset
connections and write enables, and generates the simulation harness.
From a checkout with an installed toolchain:
pycircuit run examples/hello_counter --target cpp --cycles 5
pycircuit run examples/hello_counter --target verilog --cycles 5Each cycle contains low and high sampling epochs, so both runs log
0, 0, 1, 1, 2, 2, 3, 3, 4, 4. Generated files and simulator builds stay under
.pycircuit_out/run/hello_counter/. Verilog execution requires Verilator.
Use --toolchain /absolute/path/to/install when selecting an external toolchain.
See the quickstart for explicit compile/link/ emit commands and the tutorial for inspecting and running the generated artifacts.
A bounded shared execution model
can declare calculation, architectural state/effects and finite queue/II timing
once. Native link --execution functional|timing derives the selected execution
entry; cpp|verilog remains a separate backend choice. The
word and state-dependent digest example
shows installed input-driven runs and independent transaction/timing checks.
Architectural timers, cancellation and unsupported topology are rejected by
this slice, rather than erased during functional projection.
For a portable bounded model project, the installed tool also provides
pycircuit doctor, init, verify and benchmark. They reuse the same
compiler/Runtime and supplied raw/state expectations. See the
project workflow and
product scope/roadmap.
A separate complete-state clocked profile
supports pure hierarchy and checked idle-cycle folding. The
accumulator example demonstrates
installed native/physical-RTL execution without a second authored model.
For a model with NDF requirements, pycircuit spec-check checks the versioned
Spec and named Python implementation/test bindings using a pinned external NDF
CLI. See the specification workflow.
Traceability, behavioral validation and specification approval remain distinct.
| Task | Requirements |
|---|---|
| Build the compiler | Python 3.11+, CMake 3.25+, Ninja, a C++20 compiler, LLVM and MLIR 22.1.8 |
| Run generated C++ | C++20 toolchain, CMake/Ninja and pyCircuit Runtime |
| Run generated Verilog systems | Installed pyCircuit compiler, Verilator, CMake/Ninja and a C++20 toolchain |
Install LLVM/MLIR first. The build helper discovers llvm-config-22 or a matching
llvm-config; alternatively set LLVM_CONFIG, or both LLVM_DIR and MLIR_DIR,
to that installation. Installing the Python package alone does not install the
native compiler.
git clone https://github.com/PTO-ISA/pyCircuit.git
cd pyCircuit
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
PYC_BUILD_TESTING=OFF bash tools/pyc build
export PYC_TOOLCHAIN_ROOT="$PWD/.pycircuit_out/toolchain/install"
export PATH="$PYC_TOOLCHAIN_ROOT/bin:$PATH"
pycircuit run examples/hello_counter --target cpp --cycles 5These commands use a POSIX shell. The installation guide covers CMake build options, Runtime-only installations and package consumers. For prebuilt wheels, check the assets and platform support of the specific release.
Python modules and systems
│ syntax capture
▼
MLIR type, dependency and effect analysis
│ hardware lowering and verification
▼
Independent source units ── explicit link closure ── verified final IR
│
┌────────┴────────┐
▼ ▼
GFSIM C++ Verilog
| Command | Purpose |
|---|---|
pycircuit compile |
Compile one source and publish its body, interface and dependencies. |
pycircuit link |
Check the complete explicit source-unit closure and select the design root. |
pycircuit emit |
Emit C++ or Verilog from the verified final artifact. |
pycircuit run |
Build and execute a closed system through those same public stages. |
Reusable functional numeric source units
provide binary32/binary64 arithmetic examples, direct and integral rounding,
configurable FP4/FP8 value codecs, word arithmetic and bit transformations
through this public flow. Their inspectable providers,
build driver and independent native/RTL oracles live in
examples/functional_float; they are
bounded example algorithms, rather than a complete floating library or ISA.
The same reference separately records actual latest-selected Bench802/ASL
validation and the SSM-owned matrix-default consumer fix; it does not replace
older frozen or newcc799 measurements with new-asset results.
The registered word-state System example
now demonstrates public numeric composition, commit state and sticky logical
effects with native workers1/2 and RTL, independently of SSM.
@module defines reusable hardware, @rule defines an atomic stateless
transition, and @system defines a closed simulation composition. The current
system path owns its generated clock/reset scaffolding; ordinary module drivers
can provide explicit physical inputs. See
system execution for sampling, reset,
observation and failure semantics.
| Start with | For |
|---|---|
| Repository map | Folder responsibilities, source boundaries and the right place for a change. |
| Recommended examples | The 21 current teaching and design examples, ordered by purpose. |
| Design gallery | Self-contained projects, including the RV32I core and an NDF project starter. |
| Example catalog | Generated navigation and exact verification owners for those examples. |
| Python language | Types, source constructs, composition and rejection boundaries. |
| Compiler architecture | Capture, MLIR analyses, source publication and code generation. |
| Build and test workflow | Bounded gates, native tests and nightly coverage. |
| Contribution guide | Scope, contracts, review and reproducible changes. |
For compiler development, enable PYC_BUILD_TESTING=ON and install the native
test dependencies, including GoogleTest and lit. With that testing build
installed, run the bounded checks from the repository root:
bash tools/run_api_tests.sh --tier gate
bash tools/run_examples.sh --tier gateFor a nondefault build, set PYC_BUILD_DIR and PYC_TOOLCHAIN_ROOT as described
in the testing guide. PR CI checks Python, publication, repository hygiene and
documentation; native, example and release evidence have their own documented
entrypoints. A green CI badge does not imply full backend or platform coverage.
The active catalog contains 21 current examples. Fifty-four superseded wrappers and their original oracles remain in the historical fixture archive; an archived fixture is not a passing result. Retired frontends, Signal APIs and compiler aliases are not compatibility paths.
pyCircuit is licensed under BSD-3-Clause.
