A simple Python-to-Verilog synthesizer for numeric kernels, control systems, and DSP.
Project description
Holoso converts a subset of idiomatic Python into synthesizable and verifiable Verilog. It is primarily designed for heavy numerical code which is abundant in control systems and DSP where manual RTL coding is inefficient and error-prone.
Holoso focuses on Python because this is a popular language in modeling, system design, and verification domains; ability to generate production HDL directly from the original model allows the designer to work with much simpler harnesses and iterate faster.
See PRIOR_ART.md for a detailed review of existing alternatives, and why none are good enough for practical use.
Holoso is under active development and as such it has no burden of backward compatibility. Breaking changes will occur regularly without notice until v1.0 is out. Many critical features are missing which may limit applicability beyond applications that we are immediately involved with. Contributions of any kind are emphatically welcome!
Design
Holoso implements essentially a separate programming language whose syntax is a strict subset of Python, and whose semantics is largely equivalent to Python with minor deviations that make sense in chip design context. Save for the minor differences in semantics, Holoso ensures that one can execute the original Python code and run the generated circuit (RTL) side by side, and obtain equivalent results (bit-exact unless floating points are used, in which case small errors may creep up, due to the inherent limitations of floating points).
Unlike most (all known to us) HLS engines out there, Holoso does not generate a straight-line II=1 pipeline because this is rarely what you actually need in practice; instead, it designs a narrowly specialized computing core (a zero-instruction-set processor) with custom microcode, and statically schedules a program for the designed core. Being in control of both the core synthesis and the program compilation, Holoso tends to generate extremely efficient designs in terms of cycle latency and chip area utilization compared to the state of the art.
Holoso outputs a purely portable and vendor-agnostic Verilog that can be fed into thid-party synthesis tools as-is, along with its support library implementing various arithmetic operators. So far it has been tested at least with Yosys (ECP5), Diamond (ECP5), and Vivado (Artix-7).
By default, Holoso is tuned for the minimum cycle latency and minimum $f_\max$. If timing closure fails, one needs to locate the critical path and enable the staging knob that inserts a register stage into the offending path; then re-synthesize and repeat until timings close.
Holoso has its own efficient floating point engine that is a subset of IEEE-754, omitting support for subnormals and NaN. Arbitrary exponent and significand bit widths are supported (the IEEE-754 defaults map poorly onto FPGA DSP tiles).
Along with the synthesized Verilog, Holoso produces a Cocotb co-simulation testbench and a detailed and beautiful HTML report that provides a human-friendly view of the processor and the microcode sequence constructed by the synthesizer.
You can SEE the pipeline — every cycle, every landing, every spill. It's gorgeous. People love it. They come up to me with tears in their eyes, they say sir, that schedule report, it's the most beautiful report we have ever seen.
For a detailed review of the design and trade-offs, please refer to DESIGN.md.
Semantics
Holoso follows Python with minimal deviations where it makes sense for hardware synthesis.
- Static typing only.
- No implicit type conversions.
- Boolean short-circuiting is not supported, all operands evaluated eagerly.
- Floating-point precision depends on the selected floating-point format. See below for more info about floats.
- No exceptions: division by zero, domain errors, etc. produce the closest meaningful result and assert the error flag.
Floating point
The floating point engine is based on Zubax Kulibin Float (ZKF).
Differences from IEEE 754: no NaN, no subnormals (exponent 0 always encodes +0; finite magnitudes in (0, min_normal/2)
round to +0; magnitudes in [min_normal/2, min_normal) round to signed min_normal), no exceptions, overflow produces ±∞.
Canonical representations do not include negative zero (it is not an error to pass negative zero though).
Floating-point optimizations are fast-math style, assuming commutativity and associativity, allowing non-bit-exact rewrites.
Infinity cases that would be NaN in IEEE 754:
| Expression | Result |
|---|---|
| +∞ + −∞ | +0 |
| 0⋅±∞ | +0 |
| 0 ÷ 0 | +0 |
| ±∞ ÷ ±∞ | +0 |
Non-NaN infinity cases (same intent as IEEE 754):
| Expression | Result |
|---|---|
| finite≠0 ÷ 0 | ±∞ (sign = sign of dividend) |
| ±∞ ÷ 0 | ±∞ (sign = sign of dividend) |
| finite ÷ ±∞ | +0 |
| ±∞⋅±∞ | ±∞ (sign = signs XOR) |
| finite≠0⋅±∞ | ±∞ (sign = signs XOR) |
WEXP can be chosen freely depending on the required range, while WMAN is sensitive to the chip's DSP capabilities and thus requires careful selection to achieve best resource utilization.
| WMAN | ≈ε (interval) | Description |
|---|---|---|
| 16 | 3.052e-05 | DSP tiles in Lattice iCE40 and similar |
| 18 | 7.629e-06 | Classic FPGA DSP width, very common: ECP5, PolarFire, Trion, many Intel modes, etc. |
| 24 | 1.192e-07 | IEEE 754 binary32; also fits Versal DSP58's 27x24 asymmetric multiplier side |
| 27 | 1.490e-08 | Intel/Altera variable-precision DSPs |
| 32 | 4.657e-10 | 2x16 |
| 36 | 2.910e-11 | 2x18 (very common) or native Intel/Altera 36x36-style variable-precision mode |
| 48 | 7.105e-15 | 2x24 or 3x16; with an 8-bit exponent amounts to 7 bytes exactly |
| 53 | 2.220e-16 | IEEE 754 binary64 |
Narrower WMAN is rarely practical for computation due to low precision and fast error accumulation, although they can still be useful for storage/exchange. One notable exception is neural networks though.
Usage
Unlike most tools in this domain, Holoso is trivial to set up and get started with; it is not a framework.
Install: pip install holoso.
# Select the floating-point format you wish to use.
# Ideally, wman (mantissa width) should be a multiple of DSP tile operand width.
float_format = holoso.FloatFormat(wexp=6, wman=18)
# Define the numerical operators. This is where you can configure additional stages to close timings.
ops = holoso.OpConfig(
holoso.FAddOperator(float_format),
holoso.FMulOperator(float_format),
holoso.FDivOperator(float_format),
holoso.FMulILog2OperatorFamily(float_format),
holoso.FCmpOperator(float_format),
)
# Run Holoso -- construct the processor and the microcode.
# The results are returned in-memory; you can write them to disk where you want.
# They include the generated Verilog module, the fixed holoso_support.v/.vh, testbench, and the reports.
result = holoso.synthesize(your_function_or_method_here)
# Write the files -- this is usually what you want.
out = result.write(Path(__file__).resolve().parent)
# Show what's been written.
for filename, path in out.items():
print(f"{filename}: {path}")
See the examples/ directory for self-contained usage examples.
Verification
Just say nox. Read the noxfile.py and DESIGN.md for details.
You may find the zubax-fpga-toolchain container useful as it comes with all of the required tools out of the box.
License
Holoso is licensed under the Apache License 2.0. What you produce with it is yours: the Verilog this tool generates, together with the bundled support RTL it stitches into every design, is unencumbered and carries no license obligations. Use it in open-source or proprietary designs freely.
Project details
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 holoso-0.1.2.tar.gz.
File metadata
- Download URL: holoso-0.1.2.tar.gz
- Upload date:
- Size: 581.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e1793b6e24eccbbaa0d251d93321db9128862db19cc0f53e098de99dcf591ec
|
|
| MD5 |
37abd8df24a76fee44fd0aed80cb6ad1
|
|
| BLAKE2b-256 |
f57ec1523d5fbfd843280b271c51906d1fc627b8e9a94a9376a01410b41079ee
|
File details
Details for the file holoso-0.1.2-py3-none-any.whl.
File metadata
- Download URL: holoso-0.1.2-py3-none-any.whl
- Upload date:
- Size: 512.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
821e0a063b74e33ed675407515f98b7b127b3ea591969332957365aa41ab98a6
|
|
| MD5 |
090f69347b0f557d2bdc7c3bc6c771bc
|
|
| BLAKE2b-256 |
9c311a5e0d523475faf9e96a44ea1ddfddde496ebed95f6efa8ec478c0c334c5
|