Writing core files
A core is described in a core description file, or core file.
Core files are written in YAML syntax and follow the FuseSoC’s own CAPI (version 2) schema, which describes the structure of core files (e.g. which keys and values are allowed where). Don’t worry: using FuseSoC neither requires a full understanding of YAML, nor an up-front knowledge of CAPI. However, some key facts about YAML are important.
Things one should know about YAML
Whitespace matters (as in Python): indentation is used to group settings together to form a hierarchy. The exact amount of whitespace used for indentation does not matter; typically two or four spaces are used.
Think of a YAML file as a hierarchical, typed data structure. There are lists, dictionaries (key/value pairs), integers, strings, etc.
YAML syntax provides multiple ways to describe the same structure. It does not matter to FuseSoC which syntax variant is used. For example, a list of items can be written in the following two, semantically identical ways.
[ "item1", "item2" ]
is semantically identical to
- "item1" - "item2"
The same is true for dictionaries (key/value pairs).
{ key1: "value1", key2: "value2" }
is semantically identical to
key1: "value1" key2: "value2"
In most cases, the longer (second) form is preferred, as it is easier to make changes while keeping the diff easy to read.
We recommend always adding double quotes around strings used as value. In most cases, strings in YAML do not need to be surrounded by (single or double) quotation marks. However, the exact rules when quoting is needed are not easily summarized without in-depth understanding of the YAML language syntax. At minimum quotation marks are required when strings start with an exclamation mark. Always using double quotes avoids having to even think about the exact rules.
Examples:
recommended: "quotedvalue" required: "!tool_verilator (something)" possible: unquotedvalue
For a quick introduction into most of YAML’s features have a look at Learn YAML in Y minutes. The full YAML 1.2 specification is available at yaml.org (it’s not an easy read, though).
An example: the blinky core
The following sections explain how to add FuseSoC support to a hardware project.
The code is taken from an example design in the FuseSoC source tree in the tests/userguide/blinky
directory.
The design consists of two SystemVerilog files, a testbench, a Xilinx constraint file (with pin mappings for a Nexys Video FPGA board), and finally, the FuseSoC core file.
$ tree tests/userguide/blinky/
tests/userguide/blinky/
├── blinky.core
├── data
│ └── nexys_video.xdc
├── rtl
│ ├── blinky.sv
│ └── macros.svh
└── tb
└── blinky_tb.sv
3 directories, 5 files
To get started, here’s the full blinky.core
file.
The following sections will refer back to this example to discuss it in detail.
blinky.core
, an exemplary core file 1CAPI=2:
2name: fusesoc:examples:blinky:1.0.0
3description: Blinky, a FuseSoC example core
4
5filesets:
6 rtl:
7 files:
8 - rtl/blinky.sv
9 - rtl/macros.svh:
10 is_include_file: true
11 file_type: systemVerilogSource
12
13 tb:
14 files:
15 - tb/blinky_tb.sv
16 file_type: systemVerilogSource
17
18 nexys_video:
19 files:
20 # YAML short form, see rtl/macros.svh above for the longer form.
21 - data/nexys_video.xdc: {file_type: xdc}
22
23targets:
24 # The "default" target is special in FuseSoC and used in dependencies.
25 # The "&default" is a YAML anchor referenced later.
26 default: &default
27 filesets:
28 - rtl
29 toplevel: blinky
30 parameters:
31 - clk_freq_hz
32
33 # The "sim" target simulates the design. (It could have any name.)
34 sim:
35 # Copy all key/value pairs from the "default" target.
36 <<: *default
37 description: Simulate the design
38 default_tool: icarus
39 filesets_append:
40 - tb
41 toplevel: blinky_tb
42 tools:
43 icarus:
44 iverilog_options:
45 - -g2012 # Use SystemVerilog-2012
46 modelsim:
47 vlog_options:
48 - -timescale=1ns/1ns
49 parameters:
50 - pulses=10
51
52 # The "synth" target synthesizes the design. (It could have any name.)
53 synth:
54 <<: *default
55 description: Synthesize the design for a Nexys Video FPGA board
56 default_tool: vivado
57 filesets_append:
58 - nexys_video
59 tools:
60 vivado:
61 part: xc7a200tsbg484-1
62 parameters:
63 - clk_freq_hz=100000000
64
65parameters:
66 clk_freq_hz:
67 datatype : int
68 description : Frequency of the board clock, in Hz
69 paramtype : vlogparam
70 pulses:
71 datatype : int
72 description : Number of pulses to run in testbench
73 paramtype : vlogparam
Naming the core file
The core file can have any name, but it must end in .core
.
It is recommended to choose a file name matching the core name, as discussed below.
The first line: CAPI=2
A core file always starts with the line CAPI=2
.
No other content (including comments) is allowed before this line, as FuseSoC uses this line to differentiate between different versions of the CAPI schema.
Only CAPI version 2 is specified at the moment.
The core name, version, and description
Each core has a name, given in the name
key.
Core names can be freely chosen, but need to follow a common structure called VLNV.
VLNV stands the four parts of a core name, which are separated by colon (:
): Vendor, Library, Name, and Version.
Version numbers should be three numbers in the form major.minor.patch and follow semantic versioning (SemVer).
Cores can also have a description, given in the description
key.
A description is optional, but recommended.
name: fusesoc:examples:blinky:1.0.0
description: Blinky, a FuseSoC example core
In this example, the vendor is fusesoc
, the library is examples
, and the name of the core is blinky
.
The version is set to 1.0.0
.
Specifying source files
A core typically consists of one or multiple source files.
Source files are grouped into file sets under the filesets
key.
FuseSoC does neither mandate a specific grouping, nor naming of file sets. It is common to use one file set for RTL (design) files, and one for testbench files.
The following example shows a single file set, rtl
, with a set of common keys.
filesets:
rtl:
files:
- rtl/blinky.sv
- rtl/macros.svh:
is_include_file: true
file_type: systemVerilogSource
For each named file set, several keys are supported:
files
: An ordered list of source files. The list of source files is ordered: the files will be passed to the tool in exactly the given order. This is important, for example, in SystemVerilog, where packages need to be compiled before they can be used by subsequent source files.file_type
: The default file type for all files in thefiles
list.depend
: Dependencies on other cores. Dependencies are explained in depth at Dependencies: link cores together for re-use.
Source files
For local cores, source files are resolved relative to the location of the core file and must be stored in the same directory as the core file, or in a subdirectory of it. For remote cores, file names are typically relative to the repository or archive root.
Source file names cannot be absolute paths, or start with ../
.
Optionally, source files can have attributes; the file macros.svh
is an example of that.
When specifying attributes, end the file name with a colon (:
), and specify attributes as key-value pairs below it.
(Alternatively, the equivalent short form syntax can be used, e.g. macros.svh: {is_include_file: true}
.)
The most common attributes are:
is_include_file
: The file is an include file. In Verilog and C/C++, this means the file is not passed to the tool directly, but instead the file is included by another source file. FuseSoC ensures that the tool finds the include file, e.g. by passing an appropriate include path to the tool.file_type
: Override the default file type of the fileset for this particular file.
Refer to the CAPI2 reference documentation for more details.
File types
A file type describes the type of source file. FuseSoC does not use this information itself, but passes it on to tool backends which then configure the tool appropriately depending on the file type encountered.
Commonly used file types are:
verilogSource
: Verilog source code, up to Verilog-2001. Files ending in.v
or.vh
should use this type.systemVerilogSource
: SystemVerilog source code (design and test code). Files ending in.sv
or.svh
should use this type.vhdlSource
: VHDL source code. Files ending in.vhd
or.vhdl
should use this file type.
Refer to the CAPI2 reference documentation for more details.
Targets
A target can be seen as something you would like to do with the source code in the core: synthesize it, simulate it, lint it.
Targets are specified as dictionaries under the targets
top-level key.
targets:
# The "default" target is special in FuseSoC and used in dependencies.
# The "&default" is a YAML anchor referenced later.
default: &default
filesets:
- rtl
toplevel: blinky
parameters:
- clk_freq_hz
# The "sim" target simulates the design. (It could have any name.)
sim:
# Copy all key/value pairs from the "default" target.
<<: *default
description: Simulate the design
default_tool: icarus
filesets_append:
- tb
toplevel: blinky_tb
tools:
icarus:
iverilog_options:
- -g2012 # Use SystemVerilog-2012
modelsim:
vlog_options:
- -timescale=1ns/1ns
parameters:
- pulses=10
# The "synth" target synthesizes the design. (It could have any name.)
synth:
<<: *default
description: Synthesize the design for a Nexys Video FPGA board
default_tool: vivado
filesets_append:
- nexys_video
tools:
vivado:
part: xc7a200tsbg484-1
parameters:
- clk_freq_hz=100000000
The blinky example shown above defines three targets: the default
target, a sim
target to simulate the design, and a synth
target to synthesize it.
Many designs also define a lint
target to run static analysis jobs.
The sim
and synth
targets are optional and could have had any name.
The default
target is special and required.
Within a target
Within each target block multiple keys determine what the target does. The most common keys are:
filesets
: An ordered list of file sets (source files) included in the target.description
(optional): A description of the target.toplevel
(optional): The name of the design toplevel. (For advanced scenarios it is possible to specify a list of multiple toplevels instead of just a single one.)default_tool
(optional): The default tool to be used to build the target. The tool can also be set or overridden through a FuseSoC command-line argument.tools
(optional): Tool-specific settings, grouped by tool name.parameters
(optional): Parameters (Verilog parameters and defines, VHDL generics, etc.) to be passed to the design, or forced to a certain value.
The filesets_append
key is part of an inheritance schema and explained further in section Inheritance and the default target.
The default
target
The default
target is the only required target.
It serves two purposes:
The
default
target is used if no other target is explicitly selected when running FuseSoC.The contents of the
default
target are used if the core is used as dependency (described in detail in Dependencies: link cores together for re-use).
All reusable code in the core should go into the default
target: RTL files, lint waivers, reusable constraints, etc.
Inheritance and the default
target
Importantly, other targets in the same core do not inherit the contents of the default
target automatically.
To achieve such inheritance behavior, FuseSoC provides a flexible inheritance mechanism, based on YAML anchors/references, YAML <<
merge operator, and a FuseSoC-specific list append feature.
The blinky.core shows the recommended template to inherit configuration between targets.
Add
&default
after thedefault:
text. This defines a YAML anchor nameddefault
, which can be referenced later in the file.Add a line
<<: *default
to the target where you want to inherit fromdefault
(thesim
andsynth
targets in the example code). This line will effectively “copy over” all configuration under thedefault
target.
As always with inheritance the interesting questions are around overriding behavior.
Settings (keys) given in the target which inherits from
default
override the keys indefault
. For example, thetoplevel
key in thesim
target is overridden to betb
. Note that no merging of setting data structure is performed.For settings which are lists, for example the
filesets
key, FuseSoC provides a way to combine lists by adding_append
to the name of the key.This behavior is best explained by example. The
filesets
list in thedefault
target consists of a single item,rtl
. Thesim
target wants to append the itemtb
(a file set with testbench files) to the list. To do so, it specifies the specialfilesets_append
key with a partial list. When evaluating the core file, FuseSoC appends the contents ofsim.fileset_append
at the end ofdefault.fileset
to form a list with two items:rtl
, andtb
. The same behavior works for all lists in core files.