Introduction
Kathryn is a hardware compiler for describing digital circuits at the register-transfer level (RTL) through a Python API and compiling that description to synthesizable Verilog. You write ordinary Python, but every statement you execute constructs a concrete piece of hardware: a register, a wire, an expression, a clocked assignment, a state machine step. When you emit Verilog, you get exactly the structure you declared.
from kathryn import *
class blinker(Module): @init def declare(self): self.count = reg(8, "count") self.count.mark_output("count_out")
@flow def run(self): with seq(): self.count |= self.count + 1That snippet does not simulate a counter, and no tool guesses a micro-architecture from it. It builds an 8-bit register, an adder expression, and a clocked assignment in Kathryn’s internal model — and the emitted Verilog contains precisely those parts.
Kathryn is not HLS
Section titled “Kathryn is not HLS”High-level synthesis tools take algorithmic code and infer hardware from it: scheduling, register allocation, and datapath structure are decided by the tool. Kathryn deliberately does the opposite. It does not infer micro-architecture from algorithmic code. You explicitly construct the hardware model — registers, wires, state machines, update events, modules, and control-flow graphs — and Kathryn synthesizes that model into clean, simulatable Verilog.
The practical consequences:
- Every register exists because you declared it.
reg(8)is one 8-bit register, not a hint. - Timing is explicit. A clocked assignment (
|=) is a flip-flop update; a combinational assignment (*=) is same-cycle logic. You choose, per assignment. - Control flow describes hardware, not execution. A
with seq():block builds a sequencer out of real state registers; a conditional block builds real enable logic.
Think of Python as a construction script for your circuit, with the full power of a general-purpose language available: parameterization, loops that stamp out repeated structure, classes that package reusable components, and tests that drive the whole thing.
Where Kathryn fits
Section titled “Where Kathryn fits”Kathryn is a Framework-Assisted Approach (FAA): hardware construction embedded in a general-purpose language, like Chisel. What sets it apart is that it bridges the usual gap between control-flow abstraction and cycle-accurate control — you get high-level control-flow and resource abstractions without giving up the precise, per-cycle behavior that HDLs provide. Three abstractions carry that promise, and the userbook is organized around them:
flowchart TB
F["Kathryn (FAA)<br/>cycle-accurate, in Python"]
F --> HDF["Hybrid Design Flow (HDF)<br/>control-flow abstraction"]
F --> DU["Decentralized Update<br/>relaxed, priority-resolved writes"]
F --> HA["Hardware Aggregator<br/>Table & Slot resource bundles"]
HDF --> HDFa["seq · par · cif/sif/zif<br/>pip · zync"]
DU --> DUa["multi-writer registers<br/>declared priority"]
HA --> HAa["karray: typed arrays,<br/>indexing, reduce trees"]
- Hybrid Design Flow (HDF) — an abstract model for hardware control flow.
In the DSL this is the flow blocks:
seq,par, conditionals, and pipelines. - Decentralized Update — any block may update a resource; multiple writers to one register resolve deterministically by declared priority.
- Hardware Aggregator — the Table & Slot abstraction, exposed as
karray, for managing bundles of hardware resources as one entity.
Python frontend, Rust core
Section titled “Python frontend, Rust core”Kathryn is split into two layers:
- A Rust core owns the entire hardware model. All long-lived objects live in a centralized generational arena; the model build, the control-flow elaboration, and the Verilog backend are all Rust.
- A thin Python DSL (
import kathryn) provides the user-facing surface: signal factories, operator overloading, flow-block context managers, and theModuleclass. Python objects hold only lightweight ident handles into the Rust arena — every operation routes back through Rust, which remains the sole owner of all model objects.
This split gives you the ergonomics of Python for describing hardware and the memory safety, determinism, and speed of Rust for building and emitting it. The Verilog emitter is fully isolated from the core model, so alternative backends can be added without touching the model itself.
The basic workflow
Section titled “The basic workflow”- Declare hardware in a
Modulesubclass: registers, wires, constants, memories, and I/O markings go in@initmethods. - Describe behavior in
@flowmethods using flow blocks (seq,par, conditionals, pipelines) and the assignment operators|=(clocked) and*=(combinational). - Build and emit:
build_model(top)elaborates the whole design, thenemit_verilog(out_dir)writes one.vfile per module.
The Quickstart walks through this end-to-end with a real example and its emitted Verilog.
What the userbook covers
Section titled “What the userbook covers”Getting started
- Installation — building the Rust extension and installing the Python package.
- Quickstart — a complete module, from Python source to emitted Verilog.
Core concepts
- Signals —
reg,wire,val,mem_blk, andmem_ele: the primitive hardware components. - Expressions — operator overloading, inclusive bit-slicing, and automatic wrapping of integer literals.
- Assignment — clocked
|=versus combinational*=, and sliced writes. - Reset & Defaults — register reset values and wire fallback values.
Behavior and structure
- Seq & Par and the rest of the flow-control chapters — sequencers, conditionals, state machines, and loops.
- Pipelines — the
pip/zyncpipeline system, stalls, flushes, and arbitration. - Write Priority — how multiple writes to the same register are ordered.
- Karray — typed multi-dimensional arrays of hardware, with static and runtime indexing.
- Modules & Build — module composition and building & emitting Verilog.
- Examples — a gallery of complete designs.
If you are curious about how the compiler itself works — the arena, the ident pattern, the flow-block build pipeline, the Verilog backend — see the Devbook section of this site.
Where next
Section titled “Where next”Head to Installation to build Kathryn, then the Quickstart to compile your first module.