Skip to content

Latest commit

 

History

History
149 lines (105 loc) · 7.45 KB

createcore.adoc

File metadata and controls

149 lines (105 loc) · 7.45 KB

Creating core files

The basics

In order to create our first core, we will start with some example verilog code. This is a simple SPI slave to GPIO bridge that will be used in the first examples.

Create the following directory structure, and put spi_slave.v in rtl/verilog

  • spi_slave

    • rtl

      • verilog

        • spi_slave.v

File and directory names

File and directory names for the source code are not important in FuseSoC. The structure described above is just a convention that is quite commonly used

These are all the preparations we need to create our first FuseSoC .core.

In the spi_slave directory, create a file called spi_slave.core. On the first line of the file enter CAPI=1. This will let FuseSoC know that this is a .core file which is using version 1 of the core API (which is currently the only version), which gives information on how to parse the rest of the file. CAPI1 files are standard INI files, which are parsed by Python’s configparser

On the next line, enter [main]. This starts the main configuration section. Add a single option to the main section by writing name = ::spi_slave:0 on a new line.

Core name

Technically, the name option can be left out in this case, see core naming rules for more information

Create a new fileset section by writing [fileset rtl] on a new line. The name of the fileset (i.e. rtl) is not important, but should preferrably describe what kind of files that goes into each fileset. List the source files on a new line by writing files = rtl/verilog/spi_slave.v. File paths are relative to the core root, which in this case is where the .core file resides. Also describe the file type of the files in the fileset by adding a new line with file_type = verilogSource

Verilog sections

Many older cores have a section called verilog instead of filesets. This section is deprecated, and information on how to migrate to filesets can be found in the migrations document

The complete .core file should now look like this

CAPI=1
[main]
name = ::spi_slave:0
[fileset rtl]
files = rtl/verilog/spi_slave.v
file_type=verilogSource

You can now use FuseSoC to get information about your core, and confirm that it has been picked up correctly. Run fusesoc --cores-root=<core path> core-info spi_slave, where <core path> is the path to the spi_slave directory.

FuseSoC should return something like this

CORE INFO
Name:                   ::spi_slave:0
Core root:              /home/olof/code/staging/spi_slave
== fileset ==
rtl
File sets:
Name  : rtl
Scope : public
Usage : sim/synth
Files :
 rtl/verilog/spi_slave.v verilogSource False

Please verify that Core root points to the correct directory, in case there is some other core with the same name that is being picked up by the FuseSoC configuration files.

Congratulations, you have now finished writing your first .core file, and anyone who wants to use your code can now add a dependency on your core in their .core file. We will now investigate how dependencies work in FuseSoC and making our core a bit more useful by making the spi_slave core depend on some other cores, and by adding a testbench.

Core API

For all options that are introduced in this tutorial, you can see the core API definitions to learn more about them and other options available for core files

Adding simulation support

In order to convince the world and ourselves that the core actually works, we want to add a testbench to the core and be able to run a simulation. For this we will create two new files. spi_slave_tb is the top-level testbench and spi_bfm is a BFM module to create SPI transactions. These files are put in a new directory called bench as shown below. Again, the file and directory names are not important. It’s just a convention.

  • spi_slave

    • bench

      • spi_bfm.v

      • spi_slave_tb.v

    • rtl

      • verilog

        • spi_slave.v

In order to let FuseSoC know about the two testbench files, they must be added to the .core file. In this case, we will create two new filesets for reasons that will be soon explained. The first one for spi_bfm.v looks like this:

[fileset bfm]
files = bench/spi_bfm.v
file_type=verilogSource
usage = sim

And the one for spi_slave_tb.v looks like this:

[fileset tb]
files = bench/spi_slave_tb.v
file_type=verilogSource
scope = private
usage = sim

The main difference between these two filesets is the use of the scope parameter. For the top-level testbench, scope is defined to private, instead of its default value public. Setting it to private means that if the files in this fileset will only be visible if we run operations (such as simulations) directly on the core. If the core is used as a dependency of another core, the private filesets will not be seen. As another core might want to use spi_bfm.v, we make this public, but top-level testbenches are usually only used when directly simulating the core.

The testbench also instantiates a module called vlog_tb_utils. This isn’t part of the spi_slave core, but is defined in a core in the FuseSoC base library called vlog_tb_utils. In order to use this module, we must therefore list vlog_tb_utils as a dependency of our core. We do this by adding depend = vlog_tb_utils to our [main] section.

The next thing to do is to list which simulators that can be used to simulate the core. This is done by setting the simulators option in the [main] section to a space-separated list of simulator names. The first one listed, will be used as the default simulator, unless the simulator argument --sim is added to teh command-line to manually select the simulator

List of simulators

As any value can be specified with the --sim parameter, regardless if they are in the list of simulators, only the first entry in the list (the default simulator) has any meaning.

The last thing we need to do before running a simulation is to specify the name of the top-level module used for the testbench. Please note that this is not the file name, but the name of the verilog module or VHDL entity to be used. This is done by creating a new section with the following contents:

[simulator]
toplevel = spi_slave_tb

The complete .core file should now look like this

CAPI=1
[main]
name = ::spi_slave:0
simulators = icarus
depend = vlog_tb_utils
[fileset rtl]
files = rtl/verilog/spi_slave.v
file_type=verilogSource
[fileset bfm]
files = bench/spi_bfm.v
file_type=verilogSource
usage = sim
[fileset tb]
files = bench/spi_slave_tb.v
file_type=verilogSource
scope = private
usage = sim
[simulator]
toplevel = spi_slave_tb

The simulation can now be started by executing fusesoc --cores-root=<core path> sim spi_slave. If everything works as expected, it should print out some information and then finally Test passed!. Congratulations, you have now run your first simulation with FuseSoC