0bee952 Dec 4, 2017
146 lines (95 sloc) 9.71 KB


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.

Core description files

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

Core naming rules

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 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.

Core libraries

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:

cores_root = ~/.local/share/fusesoc/orpsoc-cores ~/.local/share/fusesoc/fusesoc-cores

Core search order

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.

Example 1. Locations of core description files.
  1. library/mor1kx/mor1kx-3.2.core

  2. library/mor1kx/mor1kx.core

  3. cores/uart16550/uart16550.core

  4. de0_nano/de0_nano.core

  5. 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.

Making changes to cores in a library

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:

Example 2. Replace a core in a library with a user-specified version
  1. Create a new directory to keep the user-copies of the cores (this directory will be referred to as $corelib from now on)

  2. Download the core source (the repository or URL can be found in the [provider] section of the original core)

  3. 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)

  4. Add $corelib to the end of your library search path, either by editing fusesoc.conf or by adding --cores-root=$corelib to the command-line arguments

  5. 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

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

Running simulations

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


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.

Backend-specific information

Migration guide

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