Emacs, scripting and anything text oriented.

"Hello World" for SV/C++ DPI-C integration

Kaushal Modi

A little example demonstrating calling a C++ written function in SystemVerilog.

Let’s say we want to call a C++ function named hello_from_cpp in SystemVerilog, and for simplicity, let’s say that this is a void returning function and takes no arguments.

C++ Header #

So that function signature would look like:

void hello_from_cpp();

We need to export that function from the C++ compiled library. So we need to prefix that signature with the extern keyword and wrap it with extern "C" as shown below, in libdpi.h:

// libdpi.h
#ifdef __cplusplus
extern "C" {
#endif

  extern void hello_from_cpp();

#ifdef __cplusplus
}
#endif
Code Snippet 1: C++ Header file marking the hello_from_cpp function as exportable

C++ Source Code #

And here’s the implementation of that hello_from_cpp function in C++:

// libdpi.cpp
#include <iostream>
using namespace std;

#include "libdpi.h"

void
hello_from_cpp() {
  cout << "Hello from C++!\n";
}
Code Snippet 2: Implementation of the hello_from_cpp function in C++

Creating shared object (.so#

Cadence Xcelium uses a libdpi.so by default as an “SV/DPI Lib” (-sv_lib switch) if it is present in the compilation directory. So we will simply compile the above to a libdpi.so.

g++ -c -fPIC libdpi.cpp -o libdpi.o
g++ -shared -Wl,-soname,libdpi.so -o libdpi.so libdpi.o
Code Snippet 3: g++ commands to compile libdpi.cpp into the shared object libdpi.so

Verifying that the .so actually contains that exported function #

This is a wonderful SO answer that taught me the existence of a CLI GNU development tool called nm. From its man page, this utility nm list symbols from object files.

Here, I need to know which symbols from the text/code section got exported to the libdpi.so. When I did nm libdpi.so, it listed about two dozen symbols, most of which were gibberish to me. But the symbol that I cared about: hello_from_cpp has a T before it.

man nm says this about that T:

"T"
"t" The symbol is in the text (code) section.

So after kind of understanding that, I do:

nm libdpi.so | rg '\bT\b'

and I get:

0000000000000888 T _fini
0000000000000698 T _init
00000000000007cc T hello_from_cpp

SystemVerilog test bench #

With the libdpi.so object containing the exported hello_from_cpp ready, we just need to DPI-C import it into the SystemVerilog test bench.

program top;

  import "DPI-C" function void hello_from_cpp();

  initial begin
    hello_from_cpp();
    $finish;
  end

endprogram : top
Code Snippet 4: SystemVerilog test bench importing function from C++

Result #

And running:

xrun -64bit tb.sv

gives:

xcelium> run
Hello from C++!