Emulating a fabric on a commercial FPGAΒΆ
This guide describes how to run a FABulous-generated fabric on a commercial FPGA board and reconfigure it with user designs at runtime, over UART. The FABulous_fabric_demo repository is used as the worked example. It targets a Digilent Nexys Video board, but the same approach applies to any FPGA large enough to hold the fabric. Note that the FPGA needs to support latch cells, since the configuration bitstream is stored in latches.
Two kinds of emulationΒΆ
FABulous supports two different ways of testing a fabric in real hardware. They are easy to confuse, so it is worth being explicit about which one this page covers.
Hardwired-bitstream emulation. The user-design bitstream is baked into the fabric RTL at synthesis time and the configuration port is removed. Swapping the mapped design means re-synthesizing the whole fabric. This is the mode described in Emulation setup.
Runtime-reconfigurable emulation (this page). The fabric is synthesized onto the host FPGA once, with its configuration loader left intact. Different user-design bitstreams are then streamed into the fabric over UART at runtime, exactly as they would be on a taped-out chip. No re-synthesis is needed to change the mapped design.
The second mode is the closer analogue to real silicon: the host FPGA plays the
role the ASIC would, and you exercise the same configuration path
(config_UART -> ConfigFSM -> frame registers) that a hardened fabric uses.
The first mode results in a lower resource utilization, since the bitstream does not have to be stored and
all the switch matrices collapse into simple, hardwired connections.
How it worksΒΆ
There are two nested layers of FPGA in this setup.
The host FPGA (the Nexys Video) treats the FABulous fabric RTL as an ordinary synthesizable design. Vivado synthesizes, places, and routes the fabric onto the host device just like any other design.
The FABulous fabric sits inside that design as a soft, reconfigurable core. Its own
config_UARTloader receives FABulous bitstreams and programs the fabricβs configuration frames.
host bitstream (Vivado) user-design bitstream (FABulous)
loaded once, over JTAG streamed at runtime, over UART
β β
βΌ βΌ
βββββββββββββββββββββββββ Nexys Video (host FPGA) βββββββββββββββββββββββ
β top.v (clock wizard, reset, UART Rx, switch/LED wiring) β
β βββ eFPGA_top (the FABulous fabric) β
β βββ eFPGA_Config (config_UART -> ConfigFSM -> frames) β
β βββ tile array (LUT4AB, RegFile, BRAM, IO, ...) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Because the fabric keeps its configuration port, you build the host bitstream once and then iterate on user designs purely by uploading new FABulous bitstreams over the serial link.
PrerequisitesΒΆ
A working FABulous installation and CAD tools (see the Quick start).
AMD/Xilinx Vivado for the host FPGA. The demo targets the Nexys Video (
xc7a200tsbg484-1); install board support via Digilentβs board files tutorial.A host FPGA board with a UART bridge to the host PC. The Nexys Video exposes an FTDI-based USB-UART (default VID
0403, PID6014).Python 3 on the host PC for the
board.pyupload script.
Step 1: Generate the fabric and a user-design bitstreamΒΆ
Generate the fabric RTL and at least one user-design bitstream with the normal FABulous flow. Using the default demo project:
FABulous create-project demo
FABulous -p demo run "run_fab; compile_design user_design/sequential_16bit_en.v"
This produces:
the fabric RTL under
demo/Fabric/anddemo/Tile/(this is what Vivado will synthesize onto the host FPGA), andthe user-design bitstream at
demo/user_design/sequential_16bit_en.bin(this is what you will stream over UART).
See FASM to Bitstream for how compile_design produces
the .bin, and for generating further bitstreams from other user designs. Every
user design you want to try on the board just needs its own .bin from
compile_design β the fabric RTL does not change.
Step 2: The top-level wrapperΒΆ
The host design needs a thin top-level module that instantiates the fabric and
connects it to the boardβs physical resources. The demoβs top.v does four
things.
Clocking: A Vivado clocking wizard (clk_wiz_0) derives the fabric clock
from the boardβs oscillator. The demo runs the fabric at 10 MHz.
Reset: resetn is asserted only when the external reset is released and
the clocking wizard reports locked, so the fabric is not clocked before its
PLL is stable.
Configuration link: The boardβs UART receive line drives the fabricβs Rx
port through eFPGA_Config, and the fabricβs ReceiveLED is brought out to a board LED.
If it will be solid on during the bitstream transmission and blink when there is no transmission,
so you can see if the config logic receives a bitstream. This is useful for debugging something
like a baud rate mismatch.
The relevant configuration ports exposed by eFPGA_Config are:
Port |
Direction |
Role |
|---|---|---|
|
in |
UART serial input β this is what |
|
in |
Bit-bang serial config (unused in the UART flow) |
|
out |
On while configuration data is being received, blinking otherwise |
|
out |
High while a configuration transfer is in progress |
The fabric prioritizes configuration sources as UART > bit-bang > parallel,
so wiring only Rx is sufficient for this flow.
User I/O: The fabricβs user I/O buses (I_top / O_top in the demo, sized
by NUM_USED_IOS) are mapped to board switches and LEDs so you can drive inputs
and observe outputs. In the demo, dip switches feed fabric inputs and a slice of
the fabric outputs drive led[7:2], with led[0] used as a free-running
heartbeat and led[1] as the configuration-receive indicator.
Tip
Match the wrapperβs user-I/O mapping to the top-level ports of the user design you compiled in Step 1. The mapped designβs inputs and outputs appear on the fabric I/O in the order defined by the fabricβs I/O tiles, so keep the wrapper and the user design consistent.
Step 3: Build the host bitstream in VivadoΒΆ
Create a project targeting the Nexys Video board.
Add design sources. Add the generated fabric directory and make sure Add sources from subdirectories is checked so all tile RTL is picked up. Add
top.vand the constraint (.xdc) files.Set the top module to
top.Scope implementation-only constraints. Any constraint file that only applies during implementation (for example an
efpga_loops.xdcthat constrains generated nets) should have its used in property set to implementation only, so it does not interfere with synthesis.Enable out-of-context (OOC) synthesis on the tile instances and the block RAM. Select them in the Sources panel, right-click, and set them out of context. The fabric is highly repetitive, so OOC synthesis of the tiles drastically reduces synthesis time and RAM usage.
Configure the clocking wizard (
clk_wiz_0): inputclk_in, outputclk_out1at 10 MHz.Generate the bitstream from the Flow Navigator, then program the board through the Hardware Manager.
A correctly programmed board shows the heartbeat LED blinking. At this point the host FPGA is running the fabric but the fabric is still unconfigured.
Step 4: Upload a user design over UARTΒΆ
With the board programmed, stream a FABulous bitstream into the fabric using the
board.py helper from the demoβs upload_bitstream/ directory:
pip install -r requirements.txt
./board.py upload path/to/sequential_16bit_en.bin
Useful options:
Flag |
Default |
Meaning |
|---|---|---|
|
β |
Select a specific board by serial/device id |
|
off |
Verbose progress output |
(VID/PID/baud) |
|
FTDI USB-UART identity and baud rate |
The configuration-receive LED (led[1] in the demo) is solid while the bitstream
is being received. When the upload finishes, the fabric holds the mapped design.
To try a different design, compile it to a .bin with compile_design
(Step 1) and run board.py upload again β no Vivado re-run is required.
Step 5: Exercise the mapped designΒΆ
Once configured, the fabric behaves like the hardware it emulates. Drive the
board switches wired to the fabric inputs and observe the LEDs wired to the
fabric outputs. For the sequential_16bit_en demo, the switches enable and
reset the counter and the LEDs show its running output.
TroubleshootingΒΆ
No heartbeat after programming. The host bitstream is not running β check the Vivado programming step and the boardβs mode/power jumpers.
Heartbeat but no reaction to uploads. Confirm the UART device (VID/PID), baud rate, and that
board.pyis talking to the right port. The configuration-receive LED should be solid on during a valid transfer.Upload completes but outputs look wrong. Re-check that the wrapperβs switch/LED mapping lines up with the user designβs top-level ports, and that the
.binwas built against the same fabric RTL that was synthesized onto the board.Synthesis is very slow. Make sure OOC synthesis is enabled on the tiles and BRAM.
See alsoΒΆ
Emulation setup β the hardwired-bitstream alternative.
Simulation β verifying the fabric in RTL before taking it to a board.
FASM to Bitstream β producing the
.binfiles you upload.