August 14, 2026 · 26 min read

NeuroCUDA FPGA HLS Explained

NeuroCUDA FPGA HLS is a proof of concept that generates HLS C++ for Xilinx Vitis HLS, not a synthesized bitstream and not a claim that the network runs on FPGA. Install with pip install neurocuda, then call neurocuda.to_hls_cpp or python -m neurocuda.export.fpga_pipeline. Artifacts live in results/fpga_rtl. Source on GitHub: https://github.com/Krishnav1/neurocuda.

This page documents generated HLS C++ and RTL estimate artifacts. It is not a board bring-up guide and it is not permission to write "runs on FPGA" in a paper.

TL;DR

NeuroCUDA FPGA HLS is a PoC, not a bitstream. Repo facts: neurocuda.to_hls_cpp, neurocuda.export.fpga_pipeline, run python -m neurocuda.export.fpga_pipeline. The pipeline generates NIR, HLS C++ aimed at Xilinx Vitis HLS, SystemVerilog RTL estimates, and a Python C-sim. Checked-in artifacts live in results/fpga_rtl. Synthesis, timing, and board runtime are still future work. Do not cite LUT estimates as Vivado results. Akida is a different gap: NOT SUPPORTED.

This page vs nearby URLs: this URL is the honest FPGA source-generation HowTo. /blog/akida-brainchip-neurocuda is BrainChip status (NOT SUPPORTED). export PyTorch to NIR is the graph handoff used as stage 1. SpiNNaker silicon is the only physical neuromorphic smoke test. Google should index this URL for HLS generation, not as "NeuroCUDA runs on FPGA."

NeuroCUDA FPGA HLS proof of concept generating HLS C++ not a bitstream

People search NeuroCUDA FPGA HLS after they see "FPGA" on the product hub or in a repository tree and want to know whether a converted SNN is already sitting on a PYNQ board. That is the wrong mental picture. High-level synthesis is a source-to-source step. A bitstream is a placed, routed, timing-closed binary for a specific part. NeuroCUDA currently performs the first kind of work as a proof of concept. It does not produce the second.

The README in github.com/Krishnav1/neurocuda already says this in one sentence: HLS C++ is generated but not yet synthesized to a physical bitstream, and the FPGA pipeline is a proof of concept. This article exists so that sentence cannot be skipped, so that the commands are copyable, and so that papers do not upgrade "generated C++" into "FPGA results."

NeuroCUDA FPGA HLS is a proof of concept

Say the label out loud before the commands. NeuroCUDA FPGA HLS means: the compiler can emit HLS C++ (and related RTL estimate files) from a NeuroCUDA SNN graph. It does not mean the network was synthesized. It does not mean place and route succeeded. It does not mean a .bit or .bin file exists. It does not mean a UART log from an Artix-7, Zynq, or Versal board exists. It does not mean energy was measured on programmable logic.

The product hub at /neurocuda already badges FPGA as "HLS C++ (proof of concept)." Keep that badge when you cite. If a comparison table needs a one-word FPGA cell, the word is PoC, not shipped, not silicon, not runtime.

Why keep a PoC at all? Because generating a Vitis-oriented C++ sketch is a real engineering artifact. Other researchers can inspect the IF update style, the Q8.8 comment trail, and the NIR round-trip that precedes it. That is useful. It becomes harmful only when the artifact is described with runtime verbs: ran, deployed, measured, closed timing, fit the part, beat the GPU in milliwatts on the board.

Repo facts you can verify

Do not take this page's word for the file names. Clone the repository and look.

Those paths are the citable surface. If a blog or a model card adds a bitstream filename that is not in that tree, treat it as fiction until the file appears on GitHub with a tool report next to it.

Install remains the same as every other NeuroCUDA HowTo: pip install neurocuda or pip install neurocuda[all]. HLS generation may additionally want sc-neurocore, because to_hls_cpp calls to_sc_neurocore, which imports sc_neurocore.compiler.intelligence.hls_export.generate_hls_cpp. If that import fails, status is sc_neurocore_missing and the helper returns a comment stub instead of C++. NIR export still works. Missing an optional FPGA extra is not a GPU conversion failure.

What each pipeline stage actually is

The pipeline prints five stages. Name them the way a reviewer will unpack them.

StageArtifactHonest nameNot this
1. NIR exportIn-memory / serializable NIR graphVendor-neutral spiking graphFPGA netlist, Akida binary
2. HLS C++C++ string aimed at Xilinx Vitis HLS, Q8.8 commentsHigh-level synthesis source PoCSynthesized RTL from Vitis, bitstream
3. SystemVerilogRTL estimate bundle / checked-in .svGenerated HDL sketchTiming-closed, board-proven RTL
4. C-simPython C-model with Q8.8-style arithmeticFunctional sketchVitis csim, gate-level sim, ILA capture
5. ResourcesLUT/FF/BRAM/DSP/power estimatesLiterature-calibrated guessVivado utilization report

Stage 1 is the same NIR path documented in what is NIR and export PyTorch to NIR. Residual graphs and the 0.000000 ResNet round-trip are NIR facts. They are not FPGA facts. Do not carry the bit-exact residual number into an FPGA sentence.

Stage 2 is the namesake of NeuroCUDA FPGA HLS. The exporter asks SC-NeuroCore for C++ with hls_tool="vitis", data_width=16, and fraction=8. That is a 16-bit Q8.8 fixed-point sketch. The public validation JSON recorded 82 lines and 2175 bytes of HLS for the demo graph named neurocuda_fpga_demo. Eighty-two lines is a generator sample, not a ResNet-18 fabric.

Stage 3 is easy to over-claim because SystemVerilog looks like "real hardware." Checked-in results/fpga_rtl/neurocuda_snn.sv is auto-generated RTL with an IF neuron module, subtractive reset comments, and a 100 MHz comment in the header. The same validation JSON recorded an HDL error ('NIRGraph' object has no attribute 'populations') on that run. Live with both facts: files exist in results/fpga_rtl, and the JSON is not a clean bill of health for every HDL path. Neither fact is a bitstream.

Stage 4 uses random exponential inputs and a Python loop. The JSON reports 193 spikes over T=64 with verified: true because spikes were nonzero. That is a smoke assertion for the sketch, not equivalence to Vitis C-simulation, and not equivalence to the GPU SNN on CIFAR-10.

Stage 5 prints a target device string (Xilinx Artix-7 XC7A35T, PYNQ-Z2 equivalent) and numbers such as 5800 LUTs, 92.8 mW, 100 MHz. The JSON methodology field says these are calibrated estimates based on published FPGA SNN papers, not a place-and-route log. If you put 92.8 mW in a comparison against GPU joules, you are comparing a formula to a measurement. Do not do that in a results table.

NeuroCUDA FPGA HLS generates source and estimates. It does not synthesize a bitstream. Do not write that the SNN runs on FPGA.

HowTo: generate HLS C++ from a converted SNN

Follow these steps in order. Skipping convert and asking HLS to speak for a ReLU ANN is not this protocol. Skipping validation and treating HLS line count as accuracy is not this protocol.

Step 1: Install NeuroCUDA

python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install torch torchvision
pip install neurocuda
# optional extras used elsewhere in the project
pip install neurocuda[all]
# optional: only if you need generate_hls_cpp via SC-NeuroCore
# pip install sc-neurocore
python -c "import neurocuda; print(hasattr(neurocuda, 'to_hls_cpp'))"

Source: github.com/Krishnav1/neurocuda. Environment notes: pip install neurocuda guide. Notebook path: NeuroCUDA Google Colab. Container notes when you want a locked image: NeuroCUDA Docker. Colab and Docker do not add Vitis. Hosted GPUs do not synthesize bitstreams.

Step 2: Convert and validate on GPU or CPU

HLS generation does not replace QCFS calibration or BPTT. Convert first. Compile to a backend that actually executes spikes in software. Record accuracy. Then consider export.

import torch
import neurocuda

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.eval()
snn, meta = neurocuda.convert(model, calib_loader)
neurocuda.compile(snn, target="gpu")  # or "cpu"
acc = neurocuda.evaluate(snn, test_loader, device=device)
print("software-backend accuracy", acc)
# This number is GPU/CPU. It is not FPGA accuracy.

Conversion HowTo: convert PyTorch to SNN. Published table clone: reproduce NeuroCUDA results. Timesteps: SNN timesteps explained. The FPGA demo graph in fpga_pipeline.py defaults to T=64 on a dummy 3-conv net. That T is a generator setting, not the ResNet T=32 protocol, and not a board latency.

Step 3: Call neurocuda.to_hls_cpp

This is the small helper. It wraps to_sc_neurocore. On success it returns a C++ string. On missing SC-NeuroCore it returns a comment that starts with // HLS export failed.

import neurocuda

hls = neurocuda.to_hls_cpp(snn, T=64, model_name="neurocuda_snn")
print(hls[:500])
if hls.startswith("// HLS export failed"):
    print("PoC helper did not emit C++. Check sc-neurocore. Still not a bitstream.")
else:
    open("results/neurocuda_fpga.h", "w").write(hls)
    print("Wrote HLS C++ source. Next real step would be Vitis, which this package does not run.")

Read the string. If it is a stub, you have an environment issue, not FPGA runtime. If it is C++, you have source. Either way you do not have a bitstream.

Step 4: Run the full pipeline module

The module path is the one to put in scripts and CI logs because it writes JSON.

# from a clone of https://github.com/Krishnav1/neurocuda
python -m neurocuda.export.fpga_pipeline
# optional: pass a torch.save path as argv[1]
# python -m neurocuda.export.fpga_pipeline path/to/snn.pt

# writes:
#   results/fpga_validation.json
#   results/neurocuda_fpga.h   (HLS snippet when code is present)

Without argv, build_sample_snn_graph builds a dummy 3-layer conv SNN named neurocuda_fpga_demo with random weights. A dummy graph is enough to prove the generator runs. It is not enough to prove your ResNet fits an XC7A35T. Do not paste dummy-graph LUT estimates next to ResNet-18 GPU accuracy.

The printout may say "READY FOR SYNTHESIS" and "Next: Install Xilinx Vitis HLS." Treat that as a TODO line, not as a pass. Ready-for-synthesis in a Python print is a wish. Ready-for-synthesis in engineering is a Vitis report with a target II, a latency, and no blocking errors. NeuroCUDA does not attach that report.

Step 5: Inspect results/fpga_rtl

ls results/fpga_rtl
# neurocuda_snn.sv
# neurocuda_snn.xdc
# tb_neurocuda_snn.sv

Open the SystemVerilog header. You should see comments that it is auto-generated, a clock comment, and an IF neuron with subtractive reset. Open the XDC as constraints source, not as proof that timing closed. Open the testbench as a stim sketch, not as a UVM regression from a silicon vendor.

Commit hashes matter if you cite these files. Reproduction of generator output is a git problem. Reproduction of FPGA measurements would be a board problem you do not have yet.

What synthesis would still require

This section is the gap list. If you skip it, you will accidentally claim runtime.

  1. A licensed or officially obtained HLS tool. The generator names Xilinx Vitis HLS. Installing Vitis, accepting the EULA, and selecting a part are outside pip install neurocuda.
  2. A target board and part. The estimate string mentions Artix-7 XC7A35T / PYNQ-Z2 equivalent. Estimates are not board ownership. Other parts will change LUT counts, IO, and whether the design fits.
  3. Real synthesis of the generated C++ or RTL. Vitis HLS must compile the C++, schedule loops, and emit RTL. Then Vivado (or an equivalent) must synthesize, place, and route.
  4. Timing closure. A 100 MHz comment in a header is not a timing summary. You need WNS/TNS, clock constraints that match the board, and a route that meets them.
  5. A bitstream and a way to program the part. Only after bitstream generation do you have something a board can load. NeuroCUDA does not emit .bit.
  6. On-board bring-up. Clocks, resets, DMA or UART, host drivers, and a test vector from the same dataset you used on GPU. Until spikes or labels come back from the part, you still have a PoC generator.
  7. Accuracy and energy protocols. FPGA accuracy is a measured classification rate on the board. FPGA energy is a measured joule or watt on the board. Neither equals GPU accuracy from the technical report at paper.pdf.

Labs that already own Vitis can start from the generated C++. That is the intended next step. Starting is not finishing. If you finish, publish the Vitis project, the utilization report, the bitstream hash, and the board log. Then this status page can gain a new section. Until then the status is PoC.

What you must NOT claim in papers

Use cite NeuroCUDA for BibTeX and backend labels. The FPGA-specific prohibitions follow. They are the reason this URL exists.

Allowed sentences: "NeuroCUDA can generate HLS C++ as a proof of concept via neurocuda.to_hls_cpp and python -m neurocuda.export.fpga_pipeline." "Checked-in artifacts live under results/fpga_rtl." "We did not synthesize a bitstream." "GPU/CPU accuracy is reported separately." Those sentences match the repository.

If a reviewer asks "does it run on FPGA," the correct answer is "not claimed; HLS source only." If you later run Vitis yourself, that is your experiment, cited as your Vitis run, not as a NeuroCUDA product feature until the project publishes it.

Contrast with other NeuroCUDA paths

Keep the backend matrix boring and strict. Boring is how claims survive.

PathStatusEvidence
GPU / CPUShipped executionPublished SNN accuracy, spike parity checks
NIR exportShipped graph fileto_nir, residual round-trip docs
SpiNNaker-1Physical smoke testEBRAINS jobs #420148, #420186
Loihi 2Simulator onlyIF equations, not Loihi silicon
NeuroCUDA FPGA HLSSource PoCHLS C++, results/fpga_rtl, estimates
BrainChip AkidaNOT SUPPORTEDNo backend, no job ID

SpiNNaker details: physical silicon write-up. Loihi details: PyTorch to Loihi 2. Akida details: NeuroCUDA Akida status. Chip encyclopedia (not a compiler status): neuromorphic chips guide. Field language for CUDA versus compilers: neuromorphic CUDA.

Notice FPGA is richer than Akida (there are files) and poorer than SpiNNaker (there are no board jobs). Place it in the middle in prose, not at the top of a hardware slide.

Debugging generator failures without faking success

If to_hls_cpp returns a failed comment, print the status from to_sc_neurocore directly.

from neurocuda.export.nir_exporter import to_sc_neurocore
result = to_sc_neurocore(snn, T=64, model_name="neurocuda_snn")
print(result["status"])
print(result.get("next_step"))
print(result.get("error"))

sc_neurocore_missing means install or skip. error means the optional stack imported and then threw; read the exception; do not replace it with a success screenshot from GPU evaluate. NIR can still be written with neurocuda.to_nir so your conversion work is not lost.

If the pipeline's HDL stage errors as in the public JSON, you may still have HLS text and you may still have checked-in .sv files from an earlier generator. Do not silently drop the error key when you quote the JSON. Quoting only the LUT estimate and hiding hdl.error is how PoCs become fake product pages.

If you needed a container to freeze Python and CUDA wheels, that is a Docker job, not an FPGA job. Point at NeuroCUDA Docker. Vitis does not live in that story unless a future image documents it, and even then the image would still not be a bitstream.

How to talk about this in related work

Academic FPGA SNN papers usually report a part, a frequency that closed, utilization from a vendor report, and a dataset accuracy measured after the bitstream loaded. NeuroCUDA's current FPGA story has a generator and a dummy graph. Cite those papers for FPGA SNN context if you must. Do not imply NeuroCUDA reproduced them.

If your paper is about conversion quality, you do not need this page in the results section. You need GPU numbers and maybe NIR. Mention FPGA only in future work, with the PoC label. If your paper is about compilers, you may mention HLS emission as an export experiment with negative runtime claims clearly stated.

QuantaraCore's own technical report should be cited for software-backend methodology, not for FPGA joules. Hub: quantaracore.in/neurocuda. PDF: quantaracore.in/neurocuda/paper.pdf.

Primary sources

  1. NeuroCUDA GitHub (MIT), github.com/Krishnav1/neurocuda - to_hls_cpp, export/fpga_pipeline.py, results/fpga_rtl
  2. README limitation: HLS C++ generated, not synthesized to a physical bitstream
  3. results/fpga_validation.json - estimates and HLS metadata from a pipeline run
  4. Product hub FPGA badge, quantaracore.in/neurocuda
  5. Technical report (software backends), quantaracore.in/neurocuda/paper.pdf

Frequently asked questions

Does NeuroCUDA FPGA HLS mean the SNN runs on FPGA?

No. NeuroCUDA FPGA HLS is a proof of concept that generates HLS C++ and related estimates. It is not a synthesized bitstream and not a claim that the network runs on FPGA.

How do I generate HLS C++ with NeuroCUDA?

Install with pip install neurocuda, convert a model, then call neurocuda.to_hls_cpp or run python -m neurocuda.export.fpga_pipeline. Source: https://github.com/Krishnav1/neurocuda.

What artifacts does the FPGA pipeline produce?

A NIR graph, HLS C++ aimed at Xilinx Vitis HLS, SystemVerilog RTL estimates, and a C-sim style check. Checked-in files include results/fpga_rtl (neurocuda_snn.sv, neurocuda_snn.xdc, tb_neurocuda_snn.sv) and results/fpga_validation.json.

Are LUT and power numbers in fpga_validation.json synthesis results?

No. They are calibrated resource estimates printed by the pipeline, not Vivado or Vitis reports. Do not cite them as measured FPGA utilization or milliwatt silicon power.

What does synthesis still require after HLS generation?

Xilinx Vitis HLS (or equivalent), a target board and part, constraints, timing closure, place and route, bitstream generation, and on-board bring-up. NeuroCUDA does not perform those steps.

What must I not claim in a paper about NeuroCUDA FPGA HLS?

Do not claim a bitstream, FPGA accuracy, FPGA energy, or that the SNN runs on FPGA. Claim generated HLS C++ / RTL estimate artifacts and GPU or CPU accuracy separately. See cite NeuroCUDA.

Is this the same as NeuroCUDA Akida support?

No. Akida is BrainChip silicon and is NOT SUPPORTED in NeuroCUDA. FPGA HLS is a different PoC on programmable logic source generation. See NeuroCUDA Akida status.

Does to_hls_cpp require sc-neurocore?

The helper calls to_sc_neurocore. If sc-neurocore is missing, status is sc_neurocore_missing and to_hls_cpp returns a comment stub instead of synthesisable C++. NIR export still works via neurocuda.to_nir.

Is the C-sim the same as Vitis C simulation?

No. The pipeline's C-sim is a Python C-model using Q8.8 style arithmetic. It is not Vitis HLS csim of generated RTL, and it is not a board test.

Where do I find results/fpga_rtl?

In the NeuroCUDA GitHub repository under results/fpga_rtl. Files include neurocuda_snn.sv, neurocuda_snn.xdc, and tb_neurocuda_snn.sv. Treat them as generated RTL estimates, not a bitstream.

Start now: pip install neurocuda · python -m neurocuda.export.fpga_pipeline · GitHub · Product hub · PDF report · label remains PoC, not bitstream