Simulation
In the previous section Getting Started, we saw how to download SoCMake inside our project.
Let's try to run a simple Verilog testbench now with Icarus Verilog and/or Verilator.
For this step make sure you have Iverilog and/or Verilator installed on your system.
Lets create a simple verilog testbench file:
tb.v
The following testbench will just print something to the stdout.
module tb;
reg [4:0] a, b;
wire [4:0] o;
adder adder_i (
.NUM1(a),
.NUM2(b),
.SUM(o)
);
initial begin
a = 5;
b = 10;
#1;
$display("Hello world, from SoCMake build system\n");
$display("%d + %d = %d", a, b, o);
$finish();
end
endmodule
CMakeLists.txt
The following CMakeLists.txt will create a library, add sources and create verilator and iverilog Makefile targets.
cmake_minimum_required(VERSION 3.25)
project(simple_verilog_example NONE)
include("../../SoCMakeConfig.cmake")
option_enum(SIMULATOR "Which simulator to use" "iverilog;vivado_sim;questa;modelsim;xcelium;vcs;verilator;all" "iverilog")
if(SIMULATOR STREQUAL "all")
set(ALL_SIMS TRUE)
endif()
add_ip(tb
DESCRIPTION "Simple verilog testbench")
ip_sources(${IP} VERILOG
tb.v)
add_subdirectory(adder)
ip_link(${IP} adder)
if(SIMULATOR STREQUAL "iverilog" OR ALL_SIMS)
iverilog(${IP})
endif()
if(SIMULATOR STREQUAL "questa" OR SIMULATOR STREQUAL "modelsim" OR ALL_SIMS)
modelsim(${IP})
endif()
if(SIMULATOR STREQUAL "vivado_sim" OR ALL_SIMS)
vivado_sim(${IP})
endif()
if(SIMULATOR STREQUAL "xcelium" OR ALL_SIMS)
xcelium(${IP})
endif()
if(SIMULATOR STREQUAL "verilator" OR ALL_SIMS)
verilator(${IP} MAIN VERILATOR_ARGS --timing)
endif()
if(SIMULATOR STREQUAL "vcs" OR ALL_SIMS)
vcs(${IP})
endif()
help()
add_ip()
We are creating an IP library called tb using add_ip() function.
Function add_ip takes the following arguments:
- First argument is positional NAME of the defined library
- VENDOR - name of the vendor (your company, organization, ...)
- LIBRARY - name of the library which the IP is part of
- VERSION - Version number of the IP
The library that will be created will hold a name <VENDOR>__<LIBRARY>__<NAME>__<VERSION>, there will be also a CMake alias library that is created with the name <VENDOR>::<LIBRARY>::<NAME>::<VERSION>.
In this a library called cern::ip::tb::0.0.1 is created.
This function also sets IP variable in the current scope from where it was called. The IP will hold the non alias full library name.
ip_sources()
To add design sources to the IP library, we can use ip_sources() function.
The function takes
- First argument is positional NAME of the library to add sources to.
- Second argument is positional TYPE and represents the file type to be added.
- Third argument is positional SOURCES and is a list of source files to be added
Using just the name of the library tb is possible only if the add_ip() call is in the same CMakeLists.txt (subdirectory), and it was the last library added.
In other cases you can use:
${IP}same astb, should be in same subdirectory and last library added- Full name
cern__ip__tb__0.0.1(always works, from any subdirectory) - Alias libray name
cern::ip::tb::0.0.1(always works, from any subdirectory)
iverilog()
This function will add a target to compile the Icarus Verilog testbench.
The name of the created Makefile target will be: ${IP}_iverilog in this case : cern__ip__tb__0.0.1_iverilog.
verilator()
This function will add a target to compile the Verilator testbench.
In this case because it is a Verilog only testbench, we are passing MAIN argument, to let Verilator create a main.cpp file for us.
For a custom C++ testbench checkout the next example.
The name of the created Makefile target will be: ${IP}_verilate in this case : cern__ip__tb__0.0.1_verilate.
Running the example
Video example
Checkout the video example below to see how to run the simulation.
Video demonstration
Instructions
To run the example we need to create a build directory as always:
mkdir build
cd build
Then we generate Makefiles with:
cmake ../
Now we have Makefile in the build directory, which contain generated targets.
The targets we are interested in are:
cern__ip__tb__0.0.1_iverilogcern__ip__tb__0.0.1_verilate
To run the simulation we can do:
make cern__ip__tb__0.0.1_iverilog # Compile with Icarus Verilog`
make cern__ip__tb__0.0.1_verilate -j$(nproc) # Compile with Verilator`
We can compile Verilator testbench with maximum threads with -j$(nproc) flag.
Once we execute one or both of these targets we will have the testbenches compiled as executables and available to run as a normal executables.
The executables will be present in ${PROJECT_BINARY_DIR} in this case build directory.
cern__ip__tb__0.0.1_ivcern__ip__tb__0.0.1_verilator_tb