np2hw
NumPy → streaming hardware (Verilog) compiler for image and 2-D pipelines.
Write streaming image-processing code as ordinary NumPy. np2hw traces it (like JAX/TVM)
into a streaming line-based IR and emits synthesizable Verilog — with line buffers,
shift registers, edge handling, config registers, and ZeroAsic-stack interfaces
generated for you. The same NumPy function is the spec, the hardware, and the
validation reference.
# my_isp.py — a complete model file
import numpy as np
from np2hw import Param, Params
PARAMS = Params([Param("gain", np.uint8, default=16)]) # a config register
def model(img, p):
x = np.pad(img.astype(np.uint16), 1, mode="edge") # 3x3, replicate edges
blur = (x[:-2,:-2] + 2*x[:-2,1:-1] + x[:-2,2:]
+ 2*x[1:-1,:-2] + 4*x[1:-1,1:-1] + 2*x[1:-1,2:]
+ x[2:,:-2] + 2*x[2:,1:-1] + x[2:,2:]) // 16
return ((p.gain * blur) // 16).clip(0, 255).astype(np.uint8)
Save that as my_isp.py and run it — or use a shipped model from
examples/isp/:
np2hw run examples/isp/gain.py in.png out.png --param gain=24 # NumPy reference
np2hw run examples/isp/gain.py in.png out.png --param gain=24 --backend sim --sim cxxrtl # the generated RTL
np2hw view examples/isp/gain.py --source camera # live, with a gain slider
Why
For image processing and DSP, NumPy is the natural language — but mainstream HLS
targets C/C++ (Bambu, Vitis HLS, Catapult), and the Python accelerator DSLs
(HeteroCL, Allo, PyLog) use their own APIs, not plain NumPy, and target CPU/GPU/ML
rather than streaming ISP RTL. np2hw traces standard, unmodified NumPy into
streaming image-processing RTL, leaning on a hardware pattern library drawn
from production ISP experience. See design/07-prior-art.md
for the competitive map.
The engine traces general streaming NumPy — stencils, pointwise, edge handling,
mux (np.where), and phase-sliced planes (out[py::2, px::2] = ... with a
register-valued phase, which is how a per-CFA-colour operation is written).
Generated cores can be wired together with compose(), a composed module nests
inside another, and control_wrap() puts an AXI-Lite register file in front of
either. The hardest exerciser is a full ISP
built on np2hw end to end — models, netlist, control plane and verification.
(Next on the tracing roadmap: reductions, @/matmul, convolve — the
authoritative list of what traces today is
docs/supported-ops.md.)
Install
uv venv
uv pip install -e ".[media]" # core + image/video IO (np2hw run/view)
uv pip install -e ".[media,camera]" # + webcam for `view --source camera` (opencv-python)
uv pip install -e ".[media,switchboard]" # + run through the ZeroAsic Switchboard stack
uv installs the Python package and its extras. RTL simulation uses external
tools installed separately — Icarus (iverilog), Yosys (yosys), and Verilator
(verilator), e.g. from Homebrew, your package manager, or the OSS CAD Suite. A
non-uv setup (PYTHONPATH=src python3 …) also works — see
docs/install.md.
Documentation
| Doc | Covers |
|---|---|
| docs/install.md | Install, uv, optional extras, system tools |
| docs/cli.md | np2hw run / np2hw view — full reference |
| docs/writing-models.md | The model-file convention; which NumPy is traceable; gotchas |
| docs/supported-ops.md | Exact list of traced operators/methods/np.* functions (and what isn't yet) |
| docs/parameters.md | Config registers: Param, Params namespace, defaults, matrix kernels, bool/bypass, live control |
| docs/streaming-and-bitwidths.md | Streaming model, line buffers, edge handling, dtype/bitwidth semantics |
| docs/framing-and-resolution.md | SOF/EOF framing, continuous frames, parametric & dynamic resolution |
| docs/interfaces.md | AXI4-Stream Video, Switchboard, AXI-Lite/UMI register files, control_top |
| docs/backends.md | numpy / iverilog / cxxrtl / switchboard (verilator, icarus) |
| docs/view.md | Live viewer: camera/screen sources, sliders, FPS |
| docs/zeroasic.md | Switchboard stack, Logik/FPGA, Platypus, cloud emulation |
| docs/api.md | Python API: to_ir, generate, adapter generators |
Design rationale (the "why" behind each mechanism) lives in
design/ (01–07).
What it can do (built and validated)
- Trace NumPy → Verilog: slicing/arithmetic/
astype/clip/np.pad/np.where, flattened to a weighted tap map and lowered to a line IR (line buffers + shift registers, automatic delay-line counting, hash-consed sharing). - Faithful dtypes:
uint8wraps unless widened withastype; signed via NumPy types;.clip/.saturate/.truncatefor narrowing. The oracle is the same function on real NumPy dtypes. - Config registers:
Param(scalar/matrix/bool) with resetdefault=, aParamsnamespace for many-register ISPs, programmable kernels,np.wherebypass. - Edges: same-size output via replicate/zero padding (top/bottom flush during blanking, left/right replicate).
- Framing: honors AXI-Video
TUSER(SOF); EOF-driven height-agnostic framing; continuous multi-frame. - Resolution: WIDTH/HEIGHT as Verilog parameters (per-synthesis), or full
runtime resolution (
MAX_WIDTHbuffers +active_widthregister + VSYNC). - Interfaces: AXI4-Stream Video, Switchboard (SB + packed gearbox), AXI-Lite and
UMI register files (with frame-synced shadow registers), and a
control_topthat wires geometry/config registers to the core. - Control plane: registers at addresses the CALLER allocated (
Reg), including read-only identity words and SLVERR on an unmapped access, andcontrol_wrap(), which puts that register file in front of any self-describing module — a single core or a whole composed design. - Run anywhere: NumPy reference, Icarus, cxxrtl (fast compiled C++), and the real
Switchboard stack (Verilator/Icarus +
PySbTx/PySbRxqueues) — every path validated bit-exact against the NumPy reference. - Tooling: a generic CLI (
runfile-to-file,viewlive camera/screen with sliders + FPS); models are plain.pyfiles (no built-in names). - FuseSoC: ships as a generator (
np2hw.core, commandnp2hw-fusesoc) -- a consuming core names a model file and geometry, and the Verilog core is traced during that project's own build, byte-identical on every run.
Status
The compiler, interfaces, register files, simulation backends and CLI are implemented and validated (NumPy == RTL, bit-exact, across the example suite). Pointwise expression DAGs cover LUT-with-gather and matrix arithmetic with register coefficients, so multi-channel packed streams (a CCM's shape) trace today. Next: reductions, >1 pixel/clock, and the FPGA bitstream flow via Logik — see docs/zeroasic.md for the path to FPGA/Platypus.
Funding
Developed independently; recurring support via github.com/sponsors/lanserge, or write first: s.rabykin@gmail.com. Sponsorable capability targets -- each a generic NumPy-level feature that unblocks everyone downstream, ISP or otherwise:
- Reductions (#1) -- per-zone accumulate/min/max over a frame, which is what any statistics or metering block needs.
- Buffered forks (#2) -- one stream feeding consumers that accept at different rates, with the elasticity stated and verified.
- Status registers (#3) -- live core state (sticky flags, counters) readable back through the generated register file, alongside the config it already carries.
- Multi-stream tracing (#4) -- blocks that merge or split streams, which today refuse to trace.
- Bypass-aware power gating (#5)
-- for every register-driven mux
(
np.where(enable, ...)), compute the exclusive logic cone it disables -- exact graph reachability on the traced IR, not a netlist heuristic -- and emit operand isolation plus flop clock-enables for it, with the savings proven by toggle counts in simulation, not asserted.
Scope is agreed in writing before work starts; sponsored work lands in the open tree immediately, MIT like everything else -- sponsorship buys ordering and named credit, not exclusivity.
Author
Serge Rabyking — 12 years at Apical (acquired by Arm) on production ISP/image-processing IP; patent inventor (WO2016063023A1 / US10063787B2); sole architect of ChipFlow's open-source RTL-to-GDSII backend.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file np2hw-0.3.0.tar.gz.
File metadata
- Download URL: np2hw-0.3.0.tar.gz
- Upload date:
- Size: 91.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76fa6d0410d5db70118902f61237176c1b0868bcc60096305b8fe4de94414502
|
|
| MD5 |
e3837095612f41ea306c55aa1fa8cd7e
|
|
| BLAKE2b-256 |
9689226a94f563413f8fabb05a2c287ea04a69e178a3cb85848b6b6058bb149b
|
Provenance
The following attestation bundles were made for np2hw-0.3.0.tar.gz:
Publisher:
publish.yml on lanserge/np2hw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
np2hw-0.3.0.tar.gz -
Subject digest:
76fa6d0410d5db70118902f61237176c1b0868bcc60096305b8fe4de94414502 - Sigstore transparency entry: 2397969939
- Sigstore integration time:
-
Permalink:
lanserge/np2hw@8554c6cbfbc459427c7821b53a1407ff8c402eeb -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/lanserge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8554c6cbfbc459427c7821b53a1407ff8c402eeb -
Trigger Event:
release
-
Statement type:
File details
Details for the file np2hw-0.3.0-py3-none-any.whl.
File metadata
- Download URL: np2hw-0.3.0-py3-none-any.whl
- Upload date:
- Size: 93.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a33a087791822a71df2b3ea4b41700569147f94b2ea1ee19dc08588ad7eb3983
|
|
| MD5 |
517337b3a0a30e447a93acc0a0f7b023
|
|
| BLAKE2b-256 |
de7e0d101abf51849932eeca8f82c6e13591dcbf4155bf59804662d8ef38d6ad
|
Provenance
The following attestation bundles were made for np2hw-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on lanserge/np2hw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
np2hw-0.3.0-py3-none-any.whl -
Subject digest:
a33a087791822a71df2b3ea4b41700569147f94b2ea1ee19dc08588ad7eb3983 - Sigstore transparency entry: 2397970436
- Sigstore integration time:
-
Permalink:
lanserge/np2hw@8554c6cbfbc459427c7821b53a1407ff8c402eeb -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/lanserge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8554c6cbfbc459427c7821b53a1407ff8c402eeb -
Trigger Event:
release
-
Statement type: