FuseSoC is a package manager and a set of build tools for HDL code.
Its main purpose is to increase reuse of IP cores and be an aid for creating, building and simulating SoC solutions.
The package manager part can be seen as an apt, portage, yum, dnf, pacman for FPGA/ASIC IP cores. A simple ini file describes mainly which files the IP core contains, which other IP cores it depends on and where FuseSoC shall fetch the code.
A collection of cores together with a top-level is called a system, and systems can be simulated or passed through the FPGA vendor tools to build a loadable FPGA image.
Currently FuseSoc supports simulations with ModelSim, Icarus Verilog, Verilator, GHDL, Isim and Xsim. It also supports building FPGA images with Project Icestorm, Xilinx ISE and Altera Quartus.
capi (Core API) is the format for core description files. Current version is version 1.0. A capi 1.0 file is identified by the string "CAPI=1" in the beginning of a file. The rest of the file is a standard INI file that is compatible with Python’s configparser module. The options available for .core
files are described in the Core API definition
This tutorial describes how to create your own .core files
FuseSoC uses VLNV
tags to uniquely identify a core. VLNV
is a concept borrowed from the IP-XACT and stands for Vendor Library Name Version. This means that the name of the cores consists of four parts, which are generally separated by :, such as librecores.org:peripherals:uart16550:1.5
. In FuseSoC, it is allowed to leave out all parts of the VLNV tag except for the name part, e.g ::uart16550
. In those cases, the Vendor and Library parts will be empty strings, and the version will be set to 0.
As the VLNV concept was introduced in FuseSoC after many core files had already been created, FuseSoC still supports parsing files with the legacy naming convention. These can either be of the format name
, in which case they will be translated internally to VLNV tags with the Name field set, and Version set to 0, or they can be of the format name-version
, which will also set the Version field.
FuseSoC will pick up the core identifer from the name
option in the [main]
section of .core
files. If no identifier is specified there, the name of the core file without the .core
suffix will be used and treated as a legacy name.
As an extension to the VLNV naming scheme, FuseSoC also support specifying a revision of a core file. This is a fifth field that can be added to both legacy and VLNV names by adding -r<revision>
as a suffix (e.g. ::uart16550:1.5-r1
, uart16550-1.5-r1
, uart16550-r1
). This is used to make updates to the .core
file even if the source of the core is unchanged.
A collection of one or more cores in a directory tree is called a core library. FuseSoC supports working with multiple core libraries. The locations of the libraries are specified in the FuseSoC configuration file, fusesoc.conf
To find a configuration file, FuseSoC will first look for fusesoc.conf
in the current directory, and if there is no file there, it will search next in $XDG_CONFIG_HOME/fusesoc
(i.e. ~/.config/fusesoc
on Linux and %LOCALAPPDATA%\fusesoc
in Windows) and lastly in /etc/fusesoc
By running fusesoc init
after FuseSoC is installed, the standard libraries will be installed, and a default configuration file will be created in $XDG_CONFIG_HOME/fusesoc/fusesoc.conf
with the following contents:
[main] cores_root = ~/.local/share/fusesoc/orpsoc-cores ~/.local/share/fusesoc/fusesoc-cores
Once FuseSoC has found its configuration file, it will parse the cores_root
option in the [main]
section of fusesoc.conf
. This option is a space-separated list of library locations which are searched in the order they appear. Additional library locations can be added on the command line by setting the --cores-root
parameter when FuseSoC is launched. The library locations specified from the command-line will be parsed after those in fusesoc.conf
For each library location, FuseSoC will recursively search for files with a .core suffix. Each of these files will be parsed and addded to the in-memory FuseSoC database if they are valid .core
files.
Once a .core
file is encountered in a directory and successfully parsed, FuseSoC will not search its subdirectories. Several .core
files can reside in the same directory and they will all be parsed.
-
library/mor1kx/mor1kx-3.2.core
-
library/mor1kx/mor1kx.core
-
cores/uart16550/uart16550.core
-
de0_nano/de0_nano.core
-
de0_nano/uart/spi/simple_spi.core
1 and 2 reside in the same directory and are both parsed. 5 is not parsed since it resides in a subdirectory of 4
If several cores with the same VLNV identifier are encountered the latter will replace the former. This can be used to override cores in a library with an alternative core in another library by specifying them in a library that will be parsed later, either temporarily by adding --cores-root
to the command-line, or permanently by adding the other library at the end of the cores_root
parameter in the configuration file.
A common situation is that a user wants to use their own copy of a core, instead of the one provided by a library, for example to fix a bug or add new functionality. The following steps can be used to achieve this:
-
Create a new directory to keep the user-copies of the cores (this directory will be referred to as
$corelib
from now on) -
Download the core source (the repository or URL can be found in the
[provider]
section of the original core) -
If the downloaded core already contains a .core file, this step is ignored Copy the original .core file to the root of the downloaded core. Edit the file and remove the
[provider]
section. (This will stop FuseSoC from downloading the core and use files from the directory containing the .core file instead) -
Add
$corelib
to the end of your library search path, either by editingfusesoc.conf
or by adding--cores-root=$corelib
to the command-line arguments -
Verify that the new core is found by running fusesoc core-info $core. Check the output to see that "Core root: " is set to the directory where the core was downloaded
FPGA implementation flows are used to build binary FPGA configuration files (bitstreams) to be downloaded to an FPGA target. The FPGA implementation flows are uusually tied to a single FPGA vendor’s devices
Simulation flows are used to simulate HDL designs and are generally independent of the intended target device. Exceptions to this are when vendor-specific modules are instantiated in the source code, which might require vendor-specific libraries that are only available for some simulators.
To run a simulation with FuseSoC, the sim
subcommand is used followed by general simulator options, the core to simulate and core-specific options.
fusesoc sim <core> --help
lists all core-specific options
Example:
fusesoc sim --sim=modelsim de0_nano --vcd --timeout=100000 --bootrom_file=spi_uimage_loader.vh
The above command would build a simulation model and run a simulation of the de0_nano core using the core’s default testbench and explicitly using modelsim. If no simulator is selected, FuseSoC will use the default simulator which is selected by the core. A different testbench can be selected by setting the --testbench option. Use fusesoc sim --help
to list all general simulator options
The parameters vcd, timeout and bootrom_file would be passed to the simulator. While all three parameters look the same on the CLI (expect for vcd, which has no value associated with it), they are handled differently inside of FuseSoC.
vcd
and timeout
would be passed as plusargs to the simulator at run-time, while bootrom_file
would be passed as a top-level parameter during compile-time.
The cores themselves are responsible for describing in the .core file which externally accessible parameters they support. This is what the corresponding sections in the .core file look like
[parameter timeout] datatype = int description = Abort test case after n cycles paramtype = plusarg scope = public [parameter vcd] datatype = bool description = Enable VCD logging paramtype = plusarg scope = public [parameter bootrom_file] datatype = file description = Initial boot ROM contents (in Verilog hex format) paramtype = vlogparam scope = private
An observation to make here is that only the last parameter is actually defined in de0_nano.core. The first two parameters are specified in the .core file for vlog_tb_utils, which is a dependency of de0_nano. By setting their scope=public
, these parameters become available for other cores which depend on them.
As new features are added to FuseSoC, some older features become obsolete. Read the migration guide to learn how to keep the .core files up-to-date with the latest best practices