Say I have a program in C++ or RUST. I wish to compile that so that part of it runs on an FPGA and then it has Linux kernel modules to handle the transfer of data from CPU to FGPA and back again. Can one use CIRCT to compile to two outputs. VHDL for the FGPA and then Linux kernel driver code for the CPU interface to the FGPA?
For example, if I add a new function to the FPGA part, it automatically updates the Linux kernel driver with the new fields and function calls.
Can anyone point me to any C++ or Rust examples that achieve this?
Of failing the full FGPA and Linux kernel driver, an example that takes C++ or RUST and creates VHDL from it?
Another viewpoint of the above might be write the code once, and run it on either FPGA, CPU or GPU or a mixture of the 3. Can CIRCT help towards this sort of goal?
You may want to take a look at SYCL and/or Intel OneAPI. The latter supports single source C++ for Intel FPGAs.
The RustHDL compiles rust to Verilog and then uses yosys and related tools to burn the firmware to FPGA. But it’s in the early stage and doesn’t support VHDL.
CIRCT provides some of what you’re interested in, but some of it is relatively new and in development, and none of it is an out of the box compiler you can use end-to-end.
First off, CIRCT does not support emitting VHDL directly; the community just hasn’t needed it, and has been focused on Verilog / SystemVerilog.
If I understand correctly, you’re looking for a kind of high-level synthesis flow. In other words, you want to write “normal” C++ or Rust as a description of hardware, as opposed to using a library for constructing hardware that is written in C++ or Rust. If that is indeed the case, you will need to use other tools to bring the program into the MLIR dialects CIRCT understands. For example, Polygeist or ClangIR both have mechanisms to compile C++ to MLIR dialects.
In terms of what CIRCT can compile, we have paths from Affine, SCF, and CF representations along with Arith down to hardware. There are several paths, which you can see starting from the purple boxes in the top left of diagram here: https://circt.llvm.org/. I’m happy to go into more detail about the kinds of hardware you can get from the different flows, and how to drive them.
This is definitely doable, like how GPU compilation works in MLIR. However, CIRCT is just a set of IRs, analysis, and transformations, and the parts related to host side compilation do not exist in CIRCT. So to achieve something like this, you’d have to put together your own end-to-end compiler, using CIRCT for the hardware side components. I don’t know of any open source example of such a compiler, but it would be very cool to see.
For this kind of workflow, CIRCT has some tooling around the ESI dialect. The docs here are a little sparse, and potentially out of date, since some work has started in this direction. Again, these are just the components, and not stitched up into a full compiler, but some examples of what this looks like do exist in CIRCT’s tests. For example, this test includes the CIRCT IRs that enable host <> device communication, as well as C++ code that interfaces with it.
Hopefully this helps shed some light on the current landscape. As it stands, it will require compiler engineering work to achieve what you’re looking for with CIRCT. If you are just interested in an out of the box solution, the something like the SYCL and OneAPI recommendations earlier might be worth looking into.