How to Connect SystemVerilog with Octave

When we must verify a highly computational RTL, we may deal with complicated mathematical functions and algorithms. Implementing and debugging an RTL model can be tricky and time consuming. In such cases modeling using Octave/Matlab, C/C++ or SystemC can be a good alternative.

In this article we present a “Hello world!” example to illustrate how to use SystemVerilog as the verification language and Octave as the numerical modeling language. This is a simplified version of the Algorithm Verification with SystemVerilog and OpenSource presentation held at DVCon Europe.

First of all, we must install Octave’s main package and it’s development package.

Then we create a testbench and connect it to Octave as shown in the image below:


We need the C++ layer because Octave libraries are C++ libraries.

The SystemVerilog Layer

The SystemVerilog layer contains the implementation of an UVM component and imports a DPI-C function. By using the import DPI-C construct we can call from SystemVerilog a function implemented in C.

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

class amiq_hello_world extends uvm_component;
   function void sv_hello_world();
      `uvm_info("HELLO_WORLD", "Hello world from SV!", UVM_NONE);

      // Call the C layer hello world

The C Layer

The C layer forwards the call to C++. When mixing C and C++ code the extern “C” construct must be used. In this layer C – C++ type casting may be required.

extern "C" {
   void c_hello_world() {
      printf("[HELLO_WORLD] Hello world from C!\n");

      // Call C++ layer hello world

The C++ Layer

The C++ layer forwards the call to Octave. In this layer C++ – Octave type casting may be required.

// In order to access Octave libraries and to use Octave specific data types, 
// 3 header files must be included into the C++ layer:

// Main C++ Octave library
#include <octave/octave.h> 
// For octave_main()
#include <octave/oct.h> 
// For access to virtual terminal support 
#include <octave/parse.h>

// Hello world example - C++ function
void cpp_hello_world() {
   cout << "[HELLO_WORLD] Hello world from C++!" << endl;

   // Input parameters list for octave custom function
   octave_value_list oct_in_list;

   // Load Octave hello world function
   load_fcn_from_file("octave_hello_world.m", "", "", "octave_hello_world", true);

   // Call Octave layer hello world
   feval("octave_hello_world", oct_in_list, 1);

The Octave Layer

The Octave layer contains the mathematical function – in this case only a message will be printed.

% Hello world example
function octave_hello_world ();
    disp("[HELLO_WORLD] Hello world from Octave!");

Octave Initialization

The Octave interpreter must be initialized at the beginning of the simulation by calling octave_main():

// SystemVerilog

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

// Hello world environment
class amiq_hello_world extends uvm_component;
   virtual task run_phase(uvm_phase phase);
      // Initialize the Octave interpreter
// C++

void initialize_octave_cpp() {

   // Declare a string vector used to pass arguments to octave_main function
   string_vector argv(2);

   // Set the first argument to "embedded"
   argv(0) = "embedded";

   // Set verbosity to quiet
   argv(1) = "-q";

   // Call octave_main() to initialize the interpreter
   octave_main(2, argv.c_str_vec(), 1);


We must create a shared object that will be passed to the simulator. The mkoctfile utility helps us:

$: mkoctfile -link-stand-alone -v my_cpp_code.cpp

The mkoctfile output is the g++ command that creates the shared object:

g++ -c -fPIC -I/usr/include/octave-3.4.3/octave/.. -I/usr/include/octave-3.4.3/octave -I/usr/include/freetype2 -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic my_ccp_code.cpp -o my_ccp_code.o 
g++ -shared -Wl,-Bsymbolic -o my_ccp_code.oct my_ccp_code.o -link-stand-alone -L/usr/lib64/octave/3.4.3 -L/usr/lib64 -loctinterp -loctave -lcruft -L/usr/lib64/atlas -llapack -L/usr/lib64/atlas -lf77blas -latlas -lfftw3 -lfftw3f -lm -L/usr/lib/gcc/x86_64-redhat-linux/4.4.6 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../.. -lgfortranbegin -lgfortran -lm


Simulations can be run using any of the 3 major EDA vendors simulators (irun, vlog/vsim and vcs). For vsim the shared library must be included at run time and for irun and vcs at compile time. You can find some invocation examples here

Note: If you experience issues related to the octave_main() function, remove the macro call “OCTINTERP_API” from “octave.h” header file (usually located in “/usr/include/”). This macro is relevant only for Microsoft’s Visual C compiler. If you create a new file with the macro call removed, you must include it before including the Octave libraries.


The results should look like this:

UVM_INFO @ 0 [HELLO_WORLD] Hello world from SV!
[HELLO_WORLD] Hello world from C!
[HELLO_WORLD] Hello world from C++!
[HELLO_WORLD] Hello world from Octave!

Source Code

The source files for the “Hello world!” example above, as well as more elaborate ones can be found on AMIQ’s github amiq_sv_octave project repository. There are three packages that you can download:

The slides from this presentation can be viewed here.


12 Responses

  1. Hello.

    I downloaded the amiq_hello_world tutorial
    Nevertheless, I am getting the following error messages at simulation time:

    ncsim: *W,LIBRUN: Could not load the dynamic library: ./INCA_libs/
    System ERROR: cannot open shared object file: No such file or directory or file is not valid ELFCLASS64 library..
    ncsim: *F,NOFDPI: Function initialize_octave not found in any of the shared object specified with -SV_LIB switch

    As you can see the library has been created:

    masia@ctolx646: ls -latr ./INCA_libs/
    -rwxr-x— 1 masia 99xgrp 8196 Jun 22 11:05 ./INCA_libs/

    Can you provide some feedback about my issue ?

    Thanks in advance,.
    Best Regards.

    1. Hi Andrea, is the name of an internal Cadence shared object not the one you created.
      If you are using the scripts from here your shared object should be called Have you created this shared object?

      Best regards,

    2. Hello Daniel.

      First of all, thanks for your prompt answer.

      I created (using the g++ command provided into the exmaple “amiq_hello_world”) the shared library:

      masia@ctolx646: ls -latr
      -rwxr-x— 1 masia sp_plus 49380 Jun 23 11:25

      Also the Cadence shared object has been created (invoking “irun” called into your example):

      masia@ctolx646: ls -latr INCA_libs/
      -rwxr-x— 1 masia sp_plus 8234 Jun 23 11:18 INCA_libs/

      Best Regards.

  2. Hi Daniel.

    Respect to your example, I added the following lines to irun command:

    1. -sv_lib /sw/freetools/octave/3.6.1/Linux/rh60/x86_64/lib/octave/3.6.1/ \
    2. -sv_lib ${SCRIPT_DIR_AMIQ_HELLO_WORLD}/INCA_libs/ \

    So doing, the simulation worked fine.

    Best Regards.

    1. Thanks Daniel.

      Please keep in mind that the example “as it is” did not worked fine at my end .

      Best Regards.

    2. I was expecting that the compiler arguments would change as new tool versions are released. Unfortunately I don’t have the time to test the scripts for every new version. But the example should be a good starting point for other users.

      Best regards,

  3. Hi,

    I have been following this post and your DVCon paper.
    It has helped me significantly for complex function verification and also in AMS to some extent.

    Lately I tried to check performance with SV simulator when I coded required algorithm in octave/matlab only and communicated to SV through file I/O. I found it to be fruitful.
    My data may be limited to certain scope.

    My question is whether you have checked on performance with purely file I/O. And then calling octave/matlab through SV system function – “$system()”


    1. Hi Kunal,

      We have not tried going through the system API. It could actually be faster than DPI-C calls.
      Our goal was to see if we could get better performance and faster implementation using Octave and not System Verilog, for mathematical models. We used DPI-C because we tried to make it system independent and we previously had a fair amount of experience with it. DPI-C also allows you to easily pass complex data between SV and Octave.

      Thank you for your input. I will try it in the future if I get to work with similar problems again.
      Best regards,

  4. Hi Daniel,

    I have looked into the g++ compilation code given above. However, when I run the following, it is throwing an error stating “cannot find -link-stand-alone”
    Is there anything that I have missed in here?

    Another query is that, when I run the irun simulator, it is launching in gui mode, and once the run is done, when I exit the xcelium, it is throwing an error stating “*** Error in `xmsim’: corrupted double-linked list: 0x000000000b3ff480 ***”. What could be the reason behind that?

    1. Hi, Akhil!

      I do expect issues with the exact compilation arguments described in this article. The post is 9 years old and it worked for the simulator, OS, and Octave versions available to me and Andra at that time. A lot has changed in the meantime so the compile arguments should be updated according to your setup.

      Please check Andrea Masi’s comment from June 23rd, 2016. While his solution is also old, it might help with updating the compile options.

      Best regards,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to our newsletter

Do you want to be up to date with our latest articles?