Skip to content

Add Bambu (PandA) HLS backend - #1509

Draft
nghielme wants to merge 9 commits into
fastmachinelearning:mainfrom
nghielme:pr1-bambu-backend
Draft

Add Bambu (PandA) HLS backend#1509
nghielme wants to merge 9 commits into
fastmachinelearning:mainfrom
nghielme:pr1-bambu-backend

Conversation

@nghielme

@nghielme nghielme commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Adds a new HLS backend targeting Bambu (PandA framework,
https://panda.deib.polimi.it), an open-source high-level synthesis tool. The backend
emits C++ from an hls4ml ModelGraph, drives Bambu for synthesis and Verilog
generation, and parses the results back into hls4ml's report objects.

Dependency — #1448. The first commit ("Vivado/Vitis build flow and report
improvements (from PR #1448)"
) is vendored from #1448: the Bambu report parser reuses
that PR's report-parsing helpers and its vivado_reports/ file convention, so this
branch builds and tests standalone. Once #1448 merges it will be dropped in a rebase.
No divergence from #1448 is intended — I author and control that branch.

New backend surface:

  • hls4ml/backends/bambu/ — backend + layer optimizer passes
  • hls4ml/writer/bambu_writer.py — project/testbench/build-script emitter
  • hls4ml/report/parse_bambu_report
  • hls4ml/templates/bambu/ — HLS C++ nnet_utils headers + firmware templates
  • Two submodules the templates require: bambu/ac_types (ferrandi/ac_types, Bambu's
    ac_types fork) and bambu/nnet_utils/gcem (compile-time math)
  • docs/backend/bambu.rst
  • Bambu parametrization added to shared tests (test_activations, test_dense_unrolled,
    test_multi_dense, test_pooling, test_softmax, …) and conftest.py filters
    (--backend-filter, --backend-exclude, --ci-exclude-nodeid)

Known limitations (documented in bambu.rst):

  • Softmax: when fix_softmax_table_size resizes the inverse LUT, Bambu's clang-16
    rejects the resulting constexpr table (compile-time division by zero). Vivado/Vitis
    fill the LUT at runtime and are unaffected — the affected cases are skipped for Bambu.
  • Large complete-partitioned arrays can crash Bambu's frontend.
  • -m64 + ac_channel crashes Bambu's InterfaceInfer; the default build path avoids it.

Stack & dependencies

Part of a three-PR stack, review in order:

  1. Add Bambu (PandA) HLS backend #1509 — Bambu backend (this PR)
  2. Add NanoXplore NG-ULTRA accelerator backend #1510 — NanoXplore NG-ULTRA accelerator backend
  3. CI: route Bambu tests to a dedicated image #1511 — CI routing for Bambu tests

Depends on #1448 (Vivado/Vitis reporting rework): the first commit here vendors it
so the branch stands alone. #1448 must merge first, then this PR is rebased to drop
that vendored commit.

Type of change

  • New feature (non-breaking change which adds functionality)

Tests

test/pytest/test_build_bambu.py runs the backend end to end (csim, cosim, synth,
vsynth). Bambu cases were added to the shared activation/dense/softmax/pooling tests and
compared against the Keras/QKeras reference like the other backends.

Ran the full Bambu-parametrized suite in the Bambu CI image:
85 passed, 18 skipped, 0 failed; plus test_build_bambu.py and
test_report::test_bambu_report.

Reproduce:

pip install ".[da,testing,testing-keras2,sr,optimization]"
source /usr/local/bin/setup-bambu.sh   # provides `bambu`
cd test/pytest
pytest test_activations.py test_dense_unrolled.py test_multi_dense.py \
       test_pooling.py test_softmax.py test_build_bambu.py \
       --backend-filter=Bambu

Test Configuration: image gitlab-registry.cern.ch/fastmachinelearning/hls4ml-testing:0.1.0.bambu,
Bambu = PandA 2026.06, USE_BAMBU_ARRAY_PARTITION=1.

CI note

GitHub PR checks here cover pre-commit, the docs build, and the packaging step. The
pytest suite runs on hls4ml's self-hosted GitLab pipeline, which a maintainer triggers
with the please test label. The Bambu test cases need a private image and Bambu
itself, so they are gated off on upstream runners — the Bambu results reported above
(85 passed / 18 skipped / 0 failed) come from running that suite in the Bambu CI image
locally, not from upstream CI.

Acknowledgements

The Bambu backend grew out of a collaboration with Politecnico di Milano, developed over 30 merged PRs on the bambu-backend branch of this fork.

Thanks to Prof. Fabrizio Ferrandi (@fabrizioferrandi), who supervised the effort and contributed the nnet_utils foundation for Bambu, a redesign of the hls::stream class, softplus support, and numerical fixes to the activation helpers (exp_fcn_float overflow, iv_base initialisation, ac_int).

And to the students who worked on it:

  • Brendan Rios (@brios-polimi) — the BambuBackend.build() flow, refactored over several rounds into the Vitis-like interface this PR ships, plus the build_bambu.sh rewrite.
  • Tommaso Pauselli (@tommasopau) — compile-time activation LUTs (tanh, legacy softmax), softmax bug fixes and the Bambu cases in test_softmax.py, and initialisation fixes in nnet_conv1d_resource.h.
  • Daniele Cursano (@danielecursano) — the ac_channel constructor fix, compile-time SELU/ELU tables, and the fixes that got Bambu C-simulation running end to end.
  • Francesco Bazzano (@frabazz) — adapted the unrolled Dense codegen to Bambu and enabled test_resource_unrolled_dense, added Bambu to test_dense, and raised build_lib.sh to C++14.
  • Andrea Oggioni (@etabeta1) — dropped the vendored ap_types copy in favour of the headers Bambu ships, and enabled cosimulation in the pooling tests.
  • Pietro Benecchi (@pietrobenecchi) — a gcem-based compile-time softsign.
  • Gabriele Santandrea (@Gab-San) — carried the pytest 9 fixture rework (Remove parametrized fixtures from pytests for pytest 9 compatability #1417) through the Bambu tests.
  • Filippo Garofalo (@FilippoGarofalo) — a string bug fix in test_pooling.py.

Checklist

  • I have read the guidelines for contributing.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation.
  • My changes generate no new warnings.
  • I have installed and run pre-commit on the files I edited or added.
  • I have added tests that prove my fix is effective or that my feature works.

nghielme added 2 commits July 20, 2026 15:12
…earning#1448)

Vendored here so this branch builds and tests on its own. This code is
NOT part of this PR's contribution -- it is the content of open PR fastmachinelearning#1448
by the same author, on which the Bambu backend depends:

  * parse_vivado_report() split into per-report helpers; bambu_report.py
    reuses _parse_csim_results, _parse_rtl_cosim_results,
    _parse_implementation_report, _parse_timing_report, _parse_power_report
  * PATHS table and _path(), including the vivado_reports/post_route_*.rpt
    locations Bambu writes its own results into
  * statistics.tcl and the vivado_synth.tcl rewrite that produce them

Review it in fastmachinelearning#1448, not here. When fastmachinelearning#1448 merges, rebasing drops this
commit.
Firmware templates, build scripts and the nnet_utils header library used
by the Bambu backend. Two submodules come with them:

  templates/bambu/ac_types        ferrandi/ac_types, Bambu's fork
  templates/bambu/nnet_utils/gcem kthohr/gcem, constexpr math for tables

ac_types diverges from the hlslibs/ac_types already vendored for Catapult,
so it cannot be shared with that backend.
@fabrizioferrandi

Copy link
Copy Markdown

Popen is awaited, but its returncode is never checked. If Bambu fails
before creating bambu_results*.xml, parse_bambu_report returns an empty
dictionary and build() appears to succeed. With reset=False, it may also
parse a report left by a previous execution. This hides compilation or
synthesis failures and, in the accelerator backend, can reach wrapper and
manifest generation without valid RTL. Could you check the exit status right
after communicate() and raise an exception including the command, exit code,
and log paths? I would also add a test with a mocked Bambu process that exits
with a non-zero status.

Minimal proposed fix:

process.communicate()
if process.returncode != 0:
    raise RuntimeError(
        f'Bambu failed with exit code {process.returncode}: {build_command}'
    )

The final implementation may use a dedicated exception type and include log
paths, but it must not continue to report parsing after a failed process.

@fabrizioferrandi

Copy link
Copy Markdown

About Known limitations. They are going to be addressed in this PandA-bambu PR ferrandi/PandA-bambu#396

nghielme added 5 commits July 24, 2026 13:55
BambuBackend converts hls4ml models to HLS C++ and drives Bambu/PandA to
synthesizable Verilog, for both io_parallel and io_stream. partname_to_bambu
maps hls4ml part names onto Bambu device names.

Not registered yet -- registration lands with the writer and report modules
it depends on.
bambu_writer.py emits the HLS C++ project; bambu_report.py parses Bambu's
XML results and reuses the Vivado report helpers for the post-route
utilization, timing and power numbers.
Only the Bambu lines: the accelerator layer registers itself separately.
test_build_bambu.py drives csim, cosim, synth and vsynth on the default
Xilinx part. The existing keras/activation/softmax/pooling suites gain
'Bambu' alongside the other backends.

conftest.py grows --backend-filter / --backend-exclude / --ci-exclude-nodeid
so a pipeline without the Bambu toolchain can deselect these cases; the CI
wiring that uses them is a separate PR.
@nghielme
nghielme force-pushed the pr1-bambu-backend branch from c2f5dff to 336ec2d Compare July 24, 2026 11:57
nghielme added a commit to nghielme/hls4ml that referenced this pull request Jul 24, 2026
`build()` awaited the Bambu process but never checked its exit status, so a
failed run fell through to `parse_bambu_report()`. That returned an empty
result which looked like success, or, with `reset=False`, a report left by an
earlier run. In the accelerator backend it could reach wrapper and manifest
generation without valid RTL.

Raise a RuntimeError carrying the command, the exit code and the log paths,
and cover it with a test that mocks a non-zero Bambu process.

Reported by Fabrizio Ferrandi on fastmachinelearning#1509; backported
here from that PR branch.
nghielme added 2 commits July 28, 2026 13:32
Picks up six upstream commits on ferrandi/ac_types dev/panda-hls since
35e101a, mostly hls::stream/ac_channel work: DEPTH template parameter on
the stream copy constructor and assignment operator (#3), peek support
(#4), a gcc 15 / system C++ library fix (#5), improved hls::stream
channel data type support (#6), a cosim regression fix (#7), and better
set_slc/set_slc2 (#8).
Since ac_types became a git submodule the headers live under
ac_types/include, not at the top level, so the USE_HLS4ML_AC_TYPES
escape hatch was passing an include path with no headers in it.
@fabrizioferrandi

Copy link
Copy Markdown

The binary distribution in the AppImage format has been released and it is available at this URL: https://release.bambuhls.eu/appimage/bambu.ginevra4.AppImage
The following text describes what has been done from ginevra3 to the last release:

Release note — PandA-bambu

Highlights

  • Added support for __bambu_csroa_partition__ when the parameter is const.
  • Extended interface inference for aggregate payloads and internal calls with multiple fragments; reads reconstruct fields through extraction, shifting, and truncation, while writes rebuild the payload through OR and shifting.
  • Fixed InterfaceInfer cases involving channels, pointers, and aggregate data; added hls4ml regressions covering constant-array partitioning, dense layers, and streams.
  • Improved analysis scalability with versioned basic-block reachability caches and an edge index for the operation graph.
  • Hardened SDC scheduling: refinement steps are skipped when solutions or position maps are missing, avoiding invalid lookups while preserving solver restarts when constraints are added.

HLS and frontend fixes

  • Fixed SDS/CS memory handling and dual-port modules; variable allocation in OpenMP functions can align the base address to the object size.
  • Disabled asynchronous SDS memory selection in OpenMP contexts and corrected SDS BRAM module parameters and metadata.
  • Preserved predicates when lowering OpenMP calls.
  • Fixed undef pointer handling in Andersen analysis and constant/type serialization in the LLVM plugin.
  • Removed an overly restrictive CSROA check on non-partitioned pointer parameters.
  • Fixed a true-floating-point issue and a select_current_lut_cost_model issue with BTCD.

CI, regressions, and toolchain

  • Added the bambu2hls4ml job to the minimal workflow, including performance comparison and final result aggregation.
  • Report uploads now use self-hosted storage through local composite actions; uploads are enabled by default in the minimal workflow.
  • GRS VHDL and libm regressions now use ModelSim; the functional OpenMP regression has been switched back to I386_CLANG4.
  • Added hls4ml regression cases and updated the HLS regression list.
  • Updated the etc/ac_types, ext/glaze, and ext/pugixml submodule references.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants