Andy Ray on Designing and Running OCaml on FPGAs

HardCaml turns OCaml into a hardware design language. Andy Ray explains FPGA fundamentals, simulation and verification, then demonstrates an OCaml software stack running on a soft CPU.

ARAndy Ray연사 · Jane Street
채널
Jane Street
게시일
2018년 5월 10일
영상
1:02:34
읽기
12분
슬라이드
11
원문
영어
YouTube에서 열기
스크롤하면 영상이 오른쪽 아래로 작아져 계속 재생됩니다. 자막은 읽기 언어를 따릅니다.
읽기 언어2개 언어로 읽을 수 있음
이 글은 아직 한국어 번역이 없어 영어 원문으로 표시합니다.
요약

30초 요약

Andy Ray introduces FPGA design and HardCaml, the OCaml library he developed for describing hardware. He walks through simulation, waveform testing and formal verification, then demonstrates an OCaml bytecode stack on a MicroBlaze FPGA system. In the discussion he addresses limitations, generated Verilog, soft CPU uses and possible future directions.

  1. 1OCaml nearly all the way downHardCaml describes hardware and OCaml drives embedded software, but the demonstration still relies on a vendor CPU and backend tools.
  2. 2Hardware as a graphHardCaml represents registers, memories and operations as OCaml data, with wires allowing cycles.
  3. 3Concurrent hardware testsThe step test bench coordinates independent tasks and can integrate a MicroBlaze instruction-set simulator with a hardware design.
  4. 4Prove by searching for a counterexampleA SAT solver checks the negation of a property: UNSAT proves it for the modeled inputs, while SAT supplies a failing assignment.
  5. 5OCaml on a soft CPUThe demo cross-compiles the OCaml runtime for MicroBlaze and packages bytecode and C stubs into an executable.
  6. 6Generated Verilog remains a tradeoffThe backend consumes generated Verilog, which Ray says is difficult to read; naming registers helps interpret timing reports.

핵심 정리

  1. FPGAs combine configurable lookup tables and routing with registers, block RAM, DSP and other specialized resources.
  2. HardCaml represents a hardware design as an OCaml graph and generates Verilog for vendor backend tools.
  3. Cycle simulation, concurrent test benches, waveform expect tests and SAT-based checks address different verification needs.
  4. OCaml bytecode and libraries can run on a MicroBlaze soft CPU using a cross-compiled C runtime, with significant size and platform limitations.
  5. The soft CPU can support control and debugging, while the performance-critical path remains in hardware.
전문

챕터별로 다듬은 전문 읽기

원본 자막만 보기
01

A blinking FPGA and the design

Ray introduces the demo, its soft CPU and HardCaml peripherals. He explains what the bootloader and LEDs are doing.

The title contains a lie: this is not quite OCaml all the way down. We can design FPGA and ASIC hardware in the HardCaml domain-specific language and write embedded software in OCaml, but this demo uses a vendor's soft CPU rather than one designed in HardCaml. The back-end place-and-route tools are also the vendor's.

The first demonstration blinks LEDs. You might think that takes ten lines of Verilog; I prefer to call it 200,000 lines of OCaml. Resetting the FPGA loads a design with a MicroBlaze CPU, 256 MB of DDR3 memory and a timer, as well as a HardCaml design connected to the CPU through a bus and register interface.

FPGA demonstration architecture
슬라이드 1 / 11FPGA demonstration architectureMicroBlaze, DDR memory and the HardCaml peripherals are connected in the demo.

That design connects three cores: a DigiLED driver for the strip, an SPI interface for a light sensor, and a CORDIC core. CORDIC computes functions such as sine, cosine and hyperbolic functions using additions and shifts. A custom bootloader loads a program from SPI flash into DDR memory; the blinking LEDs indicate its progress as it loads blocks of roughly 64 KB.

02

How FPGAs work

An overview of LUTs, routing, RAM, DSP, clocks, configuration and hard blocks. These resources make programmable hardware practical.

FPGA fabric
슬라이드 2 / 11FPGA fabricThe drawing shows LUTs, local connections and switch boxes for global routing.

An FPGA can be thought of as a grid of lookup tables (LUTs) and registers, connected by fast local routing. Switch boxes connect LUT outputs to global routing resources that can carry signals across the chip. This is an abstraction, but it gives a useful picture of the fabric.

A four-input LUT can be built from 16 static RAM cells whose contents are set when the FPGA loads. Its inputs select one cell, so it can implement any four-input Boolean function. Set all cells to zero except the last and you have an AND; reverse that pattern for an OR. Modern devices often use six-input LUTs. An optional register captures the result, or can be bypassed for larger combinational functions.

A four-input LUT
슬라이드 3 / 11A four-input LUTSixteen configurable cells feed a multiplexer and an optional register.

FPGAs also have block RAM, ranging in the examples I discuss from about 10 kilobits to 288 kilobits per block, with hundreds to tens of thousands of blocks on modern devices. Their combined bandwidth can be enormous. Dedicated DSP blocks provide multipliers and related arithmetic, while clocking resources derive and distribute clocks with different frequencies and phases.

Configuration commonly comes from flash, and USB interfaces make it convenient to program a board from a PC. The I/O pins are complex resources in their own right. Vendors also add hard silicon blocks for functions such as PCIe and Ethernet, and some FPGAs include ARM processor cores.

03

RTL languages and verification

Ray explains combinational and clocked logic, event-driven Verilog, simulation tools and property checking. He contrasts simulation traces with formal proofs.

RTL design sits near the bottom of a hierarchy of abstractions. It combines combinational logic such as adders and encoders with clocked elements such as registers and RAM. Soft CPUs bring embedded programming, instruction sets and operating systems into the picture too; a programmable state machine can have its own instruction set, even without a conventional CPU.

The main RTL languages are VHDL, Verilog and increasingly SystemVerilog. SystemC is primarily a modeling language, while other tools try to turn untimed C into hardware, with varying results. These hardware languages were originally conceived as documentation languages. Their event-driven semantics take some getting used to.

In Verilog an always block may update an output when an input changes, describing combinational logic. A block sensitive to a clock's positive edge instead loads a register once per cycle. RTL is passive, so a test bench generates changes and delays to exercise it. Those event-generating constructs are for simulation, not synthesis into hardware.

Event-driven Verilog
슬라이드 4 / 11Event-driven VerilogThe examples contrast combinational updates, clocked registers and test-bench events.

Commercial simulators include ModelSim and VCS; open-source options include Icarus Verilog and GHDL. Verilator converts synthesizable Verilog into an optimized C++ model and can be very fast. At the time of this talk, I see a gap in open-source SystemVerilog simulation support, especially as vendors move their IP to that language.

RTL debugging often means looking at waveforms: signal transitions plotted over time. Even a small simulation produces a busy display, and real designs can be enormous. Constrained random stimulus and coverage-driven frameworks help exercise interesting parts of a design, such as the supported packet protocols of a network core.

Temporal assertions can check that, for example, one event follows another within five clock cycles. Simulation checks properties on the traces it runs; formal verification tries to prove properties for every trace. That is the really interesting part, even if the machinery feels like black magic.

04

The HardCaml representation

Hardware becomes a cyclic graph of OCaml values. The API supports bit vectors, sequential primitives, state machines and vendor IP.

HardCaml hardware graph
슬라이드 5 / 11HardCaml hardware graphThe slide sketches an OCaml variant for hardware nodes and explains cycles through wires.

At its heart HardCaml represents hardware as an OCaml data structure with nodes for registers, memory, multiplexers and operations. It resembles a compiler AST, but wires can be created and used before being assigned, allowing cycles. It is more useful to think of the design as a potentially cyclic graph of hardware nodes and connections.

The core API offers arithmetic, logic, comparisons, constants and multiplexers over bit vectors of arbitrary widths. A design can query the width of a signal and construct logic that adapts to it. Instantiation also lets us leave a hole in the HardCaml graph for third-party Verilog or VHDL, vendor primitives or macros.

Operators distinguish unsigned or sign-independent operations from those where signedness matters, such as multiplication and comparison. Many checks happen at elaboration time, when the graph is constructed, not when the hardware runs. The API is strict about widths: adding a two-bit value to a three-bit value, for example, raises an error.

The API operates over two representations. Bits compute values directly, while signals record the computation. We use signals to describe the hardware graph and bits to drive concrete values into its ports during simulation.

HardCaml's sequential primitives are registers and an asynchronous-read memory. Higher-level structures, including state machines, are built on them. The always DSL resembles Verilog always blocks: guarded conditions, if statements and switches determine assignments to registers or combinational values. We use it especially for state machines and their next-state logic.

Registering a memory's address or output produces different read/write behaviors that vendor tools should infer, although inference does not always succeed. Some structures, including a true dual-port RAM, require vendor macros; that issue also arises with Verilog.

05

FIR filter and hardware testing

A filter illustrates the design API. Cycle simulation, concurrent test benches and waveform tools help test and debug hardware.

Four-tap FIR filter
슬라이드 6 / 11Four-tap FIR filterRegisters hold recent samples, which are multiplied by coefficients and added in a tree.

My hardware hello world is a finite impulse response filter. Four registers hold a moving window of the last four samples. Each sample is multiplied by a constant coefficient, and a balanced tree adds the results. HardCaml builds the register window as a list, maps signed multiplication over it and reduces the results with a reusable tree function.

HardCaml provides cycle-accurate simulation, rather than event-driven simulation. Build the simulator, set input ports, advance one cycle, read outputs and repeat. That works for simple designs, but hardware may have several independent interfaces, such as FIFOs, registers and memory, which makes a single flow of control awkward.

Cycle simulation
슬라이드 7 / 11Cycle simulationThe code sets input values, advances the simulator and reads an output.

HardCaml's step test bench is roughly Async for hardware testing: multiple independent tasks can drive different interfaces and still communicate. We integrated it with a MicroBlaze instruction-set simulator, written by Mark. It loads a MicroBlaze ELF program and runs it at a few megahertz while interacting with simulated hardware over a standard bus such as AXI.

For debugging I wrote an interactive terminal waveform viewer. HardCaml can also produce standard VCD files for viewers such as GTKWave, or stream simulation data to GTKWave as it runs. Waveform expect tests put the expected waveform in the test itself, so continuous integration can show a diff when behavior changes.

Text waveforms become unwieldy after perhaps 30 cycles, but they are useful for documenting small protocol details that should remain stable. When a test changes, the diff makes it clear that something needs attention.

06

SAT and formal verification

Ray describes proof by negation, equivalence checking and bounded model checking. He states the limits of his experimental checker.

Consider proving a ten-bit adder correct. Its two inputs make 20 input bits, or about a million test cases; exhaustive testing becomes impractical at 200 bits. A SAT solver instead looks for an input assignment that makes a Boolean function true. If such an assignment exists, it returns SAT and the values; if none exists, it returns UNSAT.

Proving a property with SAT
슬라이드 8 / 11Proving a property with SATThe slide explains why UNSAT for the negated property proves it and SAT yields a counterexample.

To prove a property always holds, ask the solver about its negation. UNSAT means there is no input that makes the negation true, so the property holds; SAT supplies a counterexample showing where it fails. HardCaml can turn a one-bit property over a combinational circuit into a SAT problem.

We also have a framework for sequential equivalence checking. To verify a Verilog-to-HardCaml port, I used Yosys to turn the Verilog into a low-level netlist, loaded that into HardCaml and asked whether the outputs always match. This method requires registers in corresponding places in both circuits.

Bounded model checking can compare circuits with different states over a fixed trace, using temporal properties. A proof over 100 cycles says nothing about cycle 101. My checker works on small cases, although I do not yet fully trust it; even with the bound, the technique is powerful.

07

The embedded OCaml stack

An OCaml bytecode interpreter and libraries run on MicroBlaze. Ray describes cross-compilation, missing platform features and executable size.

The software stack runs on MicroBlaze, a Xilinx soft RISC CPU built from FPGA fabric. There is no native OCaml compiler for this architecture, but a GCC cross-compiler exists. I cross-compiled the OCaml C runtime and its Zinc bytecode interpreter, then used ordinary x86 builds of the bytecode libraries, even though the target is 32-bit.

The OCaml `-output-obj` option produces a C file containing the program bytecode as an integer array, which the cross-compiler can compile. The tricky part is finding, compiling and linking the C stubs used by the OCaml libraries; I found around 40 C files in all.

Building OCaml libraries for the FPGA
슬라이드 9 / 11Building OCaml libraries for the FPGAThe slide outlines the bytecode libraries and the output-object step.

Signals and threads do not work in this setup, and there is no filesystem or Unix environment. An RTOS might offer threads, though I am unsure whether they would match OCaml's expectations. Base, Core_kernel and Async_kernel do work, as does the OCaml top level: the compiler itself runs on the FPGA.

The cost is size. The smallest executable is about 400 KB; adding Jane Street libraries brings it to roughly 700 KB, with more features quickly reaching 4–5 MB. The top level with these libraries totals about 23 MB: it cannot discard potentially usable code, and the CMI files used for type checking occupy roughly 16 MB.

08

Live demonstrations

The OCaml top level drives LEDs, a light sensor, a CORDIC core and concurrent Async tasks. Ray discusses plans for releasing the tools.

In the live top-level demo, the processor's standard input and output travel over USB to a laptop driver, which bridges them to a TCP socket; I connect with netcat. When I enter `let a = 1`, OCaml running on the FPGA compiles it and displays the result.

The pulse-width modulation demo turns LEDs on and off rapidly so they appear to have intermediate brightness. Varying that brightness makes them breathe. The Cylon demo moves a light back and forth along the strip, with a busy loop to slow it down and a pass that halves each LED's intensity to leave a fading tail.

A light-sensor Pmod is read through SPI: start a transfer, wait for completion and read the result. The lower four bits are discarded and the next eight contain intensity. I am not sure whether the noisy readings reflect flickering lights or sensor accuracy, so the demo averages about 500 readings and displays the result on the LED strip.

Light sensor demo
슬라이드 10 / 11Light sensor demoOCaml code reads and averages SPI sensor values and displays them on the LEDs.

An audience member asks about the LED driver. Mark wrote the DigiLED driver in HardCaml. A single line carries pulse-width-modulated bits for the RGB values; the driver programs the LEDs in sequence along the strip.

Another demo uses the HardCaml CORDIC core to calculate cosine. The core can also compute functions such as arctangent, hyperbolic functions and coordinate rotations. It computes sine and cosine together; I configure its inputs, set the angle and wait for completion. Because convergence is limited to roughly minus pi over two through pi over two, the code reduces the angle and uses quadrant symmetry.

CORDIC cosine demo
슬라이드 11 / 11CORDIC cosine demoThe code configures the CORDIC core and displays computed cosine values.

The cosine values appear on the LEDs, with color distinguishing positive and negative values and brightness indicating magnitude. Incrementing the phase moves the waveform across the strip. My favorite demo runs Async on the FPGA: three independently moving colored strobes cover different ranges, while a fourth task halves intensities to create trails.

At the time of the talk, I expect a substantially improved HardCaml release in the Jane Street repositories within a day or two, particularly with more testing. I hope to release older waveform tools, the step test bench and the MicroBlaze simulator later. The demo code needs cleanup, and packaging the cross-compiled C dependencies for OPAM is a difficult part of making it available.

09

Questions and answers

The audience asks about soft CPUs, direct bytecode execution, Unix, generated Verilog, Bluespec, RISC-V and solvers. Ray explains practical tradeoffs and potential future work.

An audience member asks whether the software runs on a processor implemented in the FPGA. Yes: MicroBlaze is a five-stage RISC soft CPU. The board used here has no hard processor; where an FPGA does have one, I would use it. The soft CPU is for administrative or debugging work, not the hot path.

Asked about executing OCaml bytecode directly in hardware, I say I previously built a state machine capable of running about three quarters of the Caml bytecode VM, in the HardCaml Zinc project. I would like to finish it, but much of Caml is still implemented in C, so a RISC CPU is needed as well.

An audience member asks what I mean by no Unix. The Unix module handles files and networking, but this soft CPU has no filesystem. The design does have a network interface that I have not yet got working; Unix-style sockets would need an emulation layer, and we would probably use lower-level APIs instead.

HardCaml describes a hardware graph in memory on the PC, then generates Verilog for the backend tools. It is not simply running the design as bytecode. A drawback is that the generated Verilog is hard to read, and retaining useful names through to the netlist for timing closure requires care.

Asked about Bluespec, I explain that HardCaml stays close to the abstraction level of Verilog and VHDL; it does not infer a microarchitecture in the way Bluespec can. I like Bluespec's ideas, although I have only read papers about it, and we are considering a DSL above HardCaml that models atomic actions.

For timing problems, the architecture matters. HardCaml generates Verilog corresponding closely to the design the engineer wrote. Naming each register in the HardCaml design makes timing reports understandable as paths from one named element to another, though the generated Verilog itself remains difficult to read.

I would like to replace MicroBlaze with RISC-V. Beyond personal interest, controlling that part of the technology could make upgrades and compiler management easier than depending on large vendor toolchains that change frequently.

The interactive top level on a small board is partly for fun, but soft CPUs do have practical uses in our designs. Some embedded code, such as a kill switch, can be critical and needs review. The team knows how to review OCaml, whereas introducing a large amount of C is less comfortable. An interactive top level could also help early debugging by letting engineers inspect registers.

Finally, asked about solvers, I say I am currently using SAT tools, principally MiniSat, rather than SMT. Z3 and its OCaml bindings have recently entered the repository, and I would like to experiment with them when I have time.

같은 채널의 다른 글

슬라이드 6장15:33EN
JSJane Street· 2026년 10월 26일Figgie Strategy: Reading Hands, Winning Majorities and Pricing CardsBradley, Mike · Jane StreetJane Street traders Bradley and Mike analyze three games to show how private information, market competition and timing affect card prices.Decision MakingMathematicsFintech
1:48:29EN
JSJane Street· 2026년 10월 16일How AI Is Changing Programming: John Krazit and Ron MinskyRon Minsky, John Krazit · Jane StreetJane Street’s AI tooling lead and the Signals and Threads host examine agent infrastructure, security, code review and the changing experience of writing software.코딩 에이전트Developer productivity평가(Evals)+2
1:36:37EN
JSJane Street· 2026년 9월 23일Aaron Bauer on Teaching Software Engineering in the Age of AIRon Minsky, Aaron Bauer · Jane StreetHow learning goals, active practice and editor design shape engineering education when models can generate the code.AI in EducationSoftware engineeringEducation+2
슬라이드 9장1:05:45EN
JSJane Street· 2026년 9월 11일Cyrus Omar on Live Programming and a Computational Commons for Humans and AICyrus OmarA demonstration of Hazel shows how immediate feedback, structured collaboration and carefully scoped permissions could support people and AI agents working together.Programming LanguagesHuman-AI Collaboration개발 워크플로와 테스트+2
1:25:00EN
JSJane Street· 2026년 9월 2일Eric Mannes on Turning Messy External Data Into Trading ResearchRon, Eric Mannes · Jane StreetFrom commodity futures and an Excel risk system to point-in-time datasets and AI, Eric Mannes explains the domain knowledge behind data engineering at Jane Street.Data quality & curation개발 워크플로와 테스트Investing+2
슬라이드 7장1:16:29EN
JSJane Street· 2026년 8월 26일Grant Sanderson and Alok Puranik: Positional Encodings Through Group TheoryGrant Sanderson, Alok Puranik · 3Blue1BrownStarting with assumptions about attention, they derive matrix exponentials and connect rotations, decay and Jordan blocks to RoPE and ALiBi.Transformers & attentionMathematics머신러닝 기초+1