A Rocket Core on the AX7A200B, over Ethernet
FireSim runs simulated RISC-V systems on an FPGA. Its design with one Rocket core, Berkeley’s 64-bit RISC-V processor, now runs on an Alinx AX7A200B board. The host reaches the board over an Ethernet cable instead of PCIe, and the simulated core’s memory is the board’s DDR3. The core loaded programs, printed on its UART, read UART input, wrote an instruction trace, and ran a compute-bound loop at 42.5 MHz effective, on a 50 MHz FPGA clock. The full write-up is a three-page paper: FireSim over Ethernet: A Rocket Core on a Low-Cost FPGA Board (PDF).
This post continues FireSim Over Ethernet on the AX7A200B, where FireSim’s GCD example ran over the same link.
Updated on October 29, 2026. The speed was 45.7 MHz in the first version of this post. That run counted the cycles of the run before it on the same simulator. The instruction trace failed in the first version, and it now works. The section The stream path gives the cause.
What changed since GCD
GCD needs only the simulator’s control registers. A Rocket core needs three more things:
- Memory. The target’s DRAM is the board’s 1 GiB of DDR3, through AMD’s MIG controller. An AXI clock converter crosses from the simulator’s 50 MHz to the controller’s 100 MHz.
- Streams. FireSim moves bulk data, such as the instruction traces of
its TracerV bridge, through CPU-managed streams on a second, 128-bit port.
These now have their own Ethernet frames, under EtherType
0x88b6, one 16-byte beat per frame. - The design. FireSim’s Rocket design is large to build: elaboration and Golden Gate, FireSim’s compiler from a design to a simulator, need two Scala toolchains.
For the design, the Bazel rules now build it in continuous integration and attach the result to each release, as a 0.9 MB archive. The GitHub build of release v0.2.1 took 14 minutes. Its files are identical, byte for byte, to a build on my machine, which took 62 minutes from a cold cache. TxHDL fetches the archive by its SHA-256, so the board build needs no Scala.
The board
TxHDL’s EthShare unit reads each frame’s EtherType.
Control frames go to the register master from the GCD milestone, and stream
frames go to a new unit, StreamBridge.
TxHDL compiles the three units together into one Verilog module.
Joined wire to wire, the channels between them would form combinational
loops, so the compiler puts buffers between them.
A frame can be lost, so the host repeats a request under the same tag. Neither port can safely perform a request twice: some control registers start an action, and a stream read removes data from a queue. So each master keeps the tag and the answer of its last request, and answers a repeat from them. The first request of a run is harmless if it repeats an old tag: a status read on the control path, and a no-op on the stream path.
The bitstream meets timing with 0.096 ns of setup slack, and uses 60% of the part’s LUTs and 55% of its block RAM.
The host
The host program is FireSim’s own, with its bridge drivers from Chipyard, the
framework FireSim is part of.
Only the platform file is new: it sends the two kinds of frame on raw sockets.
A raw socket needs the cap_net_raw capability, and Linux ignores
LD_LIBRARY_PATH for a binary with a file capability.
So the driver links Spike, the RISC-V reference simulator that FireSim’s
bridges use, statically.
It is one 3.7 MB file.
The runs
| Program | What it checks | Result |
|---|---|---|
hello.riscv |
DDR3, UART output | passed |
echo.riscv |
UART input | passed |
bench.riscv |
speed | 42.5 MHz effective |
hello.riscv with TracerV |
the stream path | passed |
hello.riscv, 7 runs in a row |
the reset before each run | passed |
The first Rocket run printed this, shortened:
simif_ax7a200b_eth: device 5 on fpga-a200t-eth0, answering
FireSim fingerprint: 0x46697265
Hello from Rocket on the AX7A200B, over Ethernet.
*** PASSED *** after 68162012 cycles
bench.riscv counts a loop of 50 million iterations with the core’s own
counters: 350,000,004 instructions in 600,000,056 cycles.
The whole run, 639,520,037 target cycles, took about 15 s of the host’s time.
FireSim reports this as an effective target clock of 42.5 MHz on the 50 MHz
FPGA clock, or about 23 million instructions per second.
The GCD run measured 0.938 kHz, so the link looked slow. The difference comes from how often the host has to act. GCD needs register accesses on every step, and each access is a frame and its answer. A Rocket core runs on its own until a bridge needs the host, and this loop needs none, so the link costs almost nothing.
The stream path
With FireSim’s TracerV bridge writing a trace, hello.riscv wrote 399 trace
lines.
They show the boot ROM, the wait while the program loads, and the program’s
print loop.
The host read them as 1,596 beats of 16 bytes.
The first attempt, on October 27, wrote an empty trace.
The run after it got no answer from the simulator, and the board needed
reprogramming.
The cause was not the stream path: the board kept one simulator for every
run, and FireSim expects a fresh one each time.
Each run writes the simulator’s STEP register once, and the step does not
finish after the driver exits.
STEP takes a new value only after the step before it has finished.
So the fourth run on one simulator waited on STEP and never continued, and
after that the board answered nothing.
The fix is a reset frame. The driver now sends it first, and the board resets the simulator and its host link. With the reset, seven runs in a row passed with the same cycle count. A board left in the stuck state answered again, with no reprogramming. The fix is TxHDL issue 2007.
What is not done yet
- Linux on the Rocket core, with FireSim’s block-device bridge over the cable.
- The bitstream as a prebuilt: each board build still runs Vivado.
The code is in the TxHDL repository: the board design, the platform
file and the programs are under firesim/ax7a200b/, and the stream units are
in lib/parts/src/remote/stream.rs.