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."
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.
neurocuda.to_hls_cppis exported from the top-level package inneurocuda/__init__.pyvianeurocuda/export/nir_exporter.py.neurocuda.export.fpga_pipelineis the module atneurocuda/export/fpga_pipeline.py.- Run it with
python -m neurocuda.export.fpga_pipeline. - The module docstring states that it generates a NIR graph, HLS C++ for Xilinx Vitis HLS, SystemVerilog RTL estimates, FPGA synthesis estimates, and C-simulation style functional verification.
results/fpga_rtlis checked in withneurocuda_snn.sv,neurocuda_snn.xdc, andtb_neurocuda_snn.sv.results/fpga_validation.jsonrecords a pipeline run (timestamp 2026-06-19 in the public file) including HLS line counts and resource estimates.
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.
| Stage | Artifact | Honest name | Not this |
|---|---|---|---|
| 1. NIR export | In-memory / serializable NIR graph | Vendor-neutral spiking graph | FPGA netlist, Akida binary |
| 2. HLS C++ | C++ string aimed at Xilinx Vitis HLS, Q8.8 comments | High-level synthesis source PoC | Synthesized RTL from Vitis, bitstream |
| 3. SystemVerilog | RTL estimate bundle / checked-in .sv | Generated HDL sketch | Timing-closed, board-proven RTL |
| 4. C-sim | Python C-model with Q8.8-style arithmetic | Functional sketch | Vitis csim, gate-level sim, ILA capture |
| 5. Resources | LUT/FF/BRAM/DSP/power estimates | Literature-calibrated guess | Vivado 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.
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.
- 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. - 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.
- 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.
- 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.
- 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. - 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.
- 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.
- Do not write "NeuroCUDA runs on FPGA."
- Do not write "deployed to FPGA" or "FPGA backend accuracy."
- Do not write that a bitstream was produced by
pip install neurocuda. - Do not cite 5800 LUTs, 92.8 mW, or 100 MHz as measured results.
- Do not treat Python C-sim spike counts as hardware validation.
- Do not treat dummy-graph artifacts as ResNet-18 on a PYNQ.
- Do not fold FPGA PoC, SpiNNaker jobs #420148 and #420186, and Loihi simulation into one "neuromorphic hardware" bar chart.
- Do not use FPGA HLS as a substitute for NeuroCUDA Akida support. Akida is NOT SUPPORTED. FPGA is a different artifact and still not a bitstream.
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.
| Path | Status | Evidence |
|---|---|---|
| GPU / CPU | Shipped execution | Published SNN accuracy, spike parity checks |
| NIR export | Shipped graph file | to_nir, residual round-trip docs |
| SpiNNaker-1 | Physical smoke test | EBRAINS jobs #420148, #420186 |
| Loihi 2 | Simulator only | IF equations, not Loihi silicon |
| NeuroCUDA FPGA HLS | Source PoC | HLS C++, results/fpga_rtl, estimates |
| BrainChip Akida | NOT SUPPORTED | No 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
- NeuroCUDA GitHub (MIT), github.com/Krishnav1/neurocuda -
to_hls_cpp,export/fpga_pipeline.py,results/fpga_rtl - README limitation: HLS C++ generated, not synthesized to a physical bitstream
results/fpga_validation.json- estimates and HLS metadata from a pipeline run- Product hub FPGA badge, quantaracore.in/neurocuda
- 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