Mixed language
The source code for this example can be found in examples/simple_mixed_language
No open-source solution support mixed language simulation for now. A free alternative is Questa Starter Edition that does support it.
Description
This example shows how to do mixed language simulation using SoCMake, using a VHDL IP and a Verilog testbench.
In this case we will have an IP library called adder, that is just a simple combinatorial adder with only 1 file adder.vhdl.
We will also have a Verilog testbench tb.v
Example
Directory structure
Lets take a look at the directory structure of the example first.
.
├── adder
│ ├── adder.vhdl
│ └── CMakeLists.txt
├── CMakeLists.txt
└── tb.v
We have a directory adder/ that contains the adder IP block, it as its own CMakeLists.txt to make it easier to reuse in a larger project.
For a design this simple it is not really necessary to have a separate CMakeLists.txt, but it is a good practice anyways.
adder/adder.v
Adder verilog file is just a simple two 5bit inputs, and a 5bit output module.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity adder is
Port ( NUM1 : in STD_LOGIC_VECTOR (4 downto 0) := "00000";
NUM2 : in STD_LOGIC_VECTOR (4 downto 0) := "00000";
SUM : out STD_LOGIC_VECTOR (4 downto 0));
end adder;
architecture Behavioral of adder is
begin
SUM <= NUM1 + NUM2;
end Behavioral;
adder/CMakeLists.txt
There is nothing new in this file from previous examples.
add_ip(adder
DESCRIPTION "Just a simple adder")
ip_sources(${IP} VHDL
adder.vhdl
)
tb.v
This is a standard Verilator testbench.
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
And finally we need a top CMakeLists.txt that will assemble the full design and create simulation targets.
cmake_minimum_required(VERSION 3.27)
project(simple_mixed_language NONE)
include("../../SoCMakeConfig.cmake")
option_enum(SIMULATOR "Which simulator to use" "questa;vivado_sim;xcelium;vcs;all" "questa")
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 "questa" OR ALL_SIMS)
questasim(${IP})
endif()
if(SIMULATOR STREQUAL "xcelium" OR ALL_SIMS)
xcelium(${IP})
endif()
if(SIMULATOR STREQUAL "vivado_sim" OR ALL_SIMS)
vivado_sim(${IP})
endif()
if(SIMULATOR STREQUAL "vcs" OR ALL_SIMS)
vcs(${IP})
endif()
help()
We can add the adder IP as a subdirectory with add_subdirectory() CMake function.
Then, we can just use the SoCMake function corresponding to the simulator we want to use, in our case questasim(), which will take care of the remaining part.
Running the simulation
Simulation can be run the same way as always:
mkdir build
cd build
cmake ../ -DSIMULATOR=questa # Configure project
make run_tb_questasim -j$(nproc) # Build and run testbench