User Guide: DSim Using the DPI and PLI

Modified on Thu, 11 Jul at 11:43 AM

User Guide: DSim Using the DPI and PLI

The following only applies to SystemVerilog support.


DSim uses shared libraries for the DPI and PLI.



DPI

The following options pertain to the DPI:


Option Description
-sv_lib name Loads the named shared library at runtime. The shared library extension for your platform (e.g. ".so") is optional.
-dpiheader ... Generate C/C++ DPI header file for exported items.

-dpiheader is a compile-time option. It is given the name of an include file to write out which contains prototypes for any exported SystemVerilog tasks/functions, as well as definitions for any structs that have C compatible layout.


-sv_lib is a runtime option only. This option may be given multiple times, to load more than one DPI library.



DPI Import

If SystemVerilog code declares a DPI import function, then the resulting image will reference the function, which ought to be resolved by loading a library (see above). Resolution failures are detected at the point where a DPI function is called to allow images to run without the DPI library, as long as they don't try to call the DPI functions.



DPI Export

If SystemVerilog code declares a DPI export function, then the resulting image will define the corresponding C function. This function will link properly with any DPI code provided, even if the call into the DPI export is made from a DPI import function. (Not all simulators support this smoothly!)



PLI

PLI support is evolving. The current support is sufficient to support licensing calls for specific partners, and fetch/deposit for UVM register model backdoor operations. Other applications may work, but this is not guaranteed. If your application does not work, use -trace-vpi to help find out why and contact Metrics support for assistance.


DSim aims to support the VPI interface. As of SystemVerilog, the tf and acc interfaces are deprecated. New code should not be using these. DSim supports a very limited set of tf routines, and does not support acc at all.


The following options pertain to the PLI:


Option Description
-pli_lib name Loads the named shared library at compile time and run time. The shared library extension for your platform (e.g. ".so") is optional. dsim will look in the shared library for the vlog_startup_routines array and will call the routines within the array. Note: The routines listed in the array should be declared as static to avoid conflicting with other bootstrap routines.
+acc+[rwcbfsWF] Instruments the compiled code for VPI access. Using this option incurs a runtime penalty.
-acc-specs file Allows fine-grained specification of VPI accessibility.

Unlike DPI, PLI libraries must be loaded in both at compile time and run time. The set of system calls defined by a PLI library is given in a table in the library, which also contains pointers to functions used at compile time to validate arguments (checktf,sizetf).



Specifying VPI Object Accessibility

Each variable/net in the design has a VPI accessibility, which consists of one or more of the following permissions:


Name Description
r The object's value can be read, or attributes can be queried.
w The object's value can be written, but not forced.
c The object's connectivity can be extracted (vpiLowConn, vpiHighConn)
b Callbacks can be set on the object. This permission is required to allow waveform dump of the object.
f The object can be forced as a whole.
W Individual elements of an unpacked array variable can be forced.
F Individual bits of an integral variable can be forced.
s (Whole design only) Enables inclusion of the PLI simulation regions (Pre/PostNBA, Pre/PostReNBA used for cbReadWriteSynch or cbReadOnlySynch). Enabling these regions will result in a slight loss of performance.

The +acc+[rwcbfsWF] option is used to specify the default accessibility for the whole design. Default is no access. A value of +acc is equivalent to +acc+rwb.


For finer-grain control, one may specify the accessibility of any net in an external file, using the -acc-specs option. The file is of a common format described in Setting Options by Scope Using Specification File. Each line in the -acc-specs file is either a module line, a path line, or a net line.


The key word module indicates a module line of the form


 

module name +mode

 

where name is the name of a module (not an instance) and mode is one or more of the permissions rwcbf. The module line specifies the default permissions of all variables/nets in the module.


The key word path indicates a path line of the form


 

signal path +mode

 

where path is indicates a scope starting point and mode is one or more of the permissions rwcbf. A net(s)/variable(s) in the path's scope will have the mode applied.


The keyword signal indicates a net line of the form


 

signal name +mode

 

where name is the name of a net/variable, and mode is one or more of the permissions rwcbf.


The # or // strings may be used to introduce comments.



Impact of Specifying Permissions

The VPI permissions allow DSim to optimize the design and choose implementations without impacting VPI requirements. Absent any VPI access requirements, DSim's optimizers may transform the design in ways that would result in incorrect behavior.



Read Permission

Consider the code:


 

reg [3:0] foo = 10;
always @(x) y = {foo,x};

 

If we knew that there was no requirement to read foo, then we can change the code to:


 

always @(x) y = {4'd10,x};

 

However, if there were a VPI reader, then after the optimization, the VPI code would fail due to optimization removing the declaration of foo.



Write Permission

Consider the code:


 

assign a = b & c;
assign d = a | e;

 

If we knew that nothing outside the code could possibly write to a, then we can change the code to:


 

always @(b or c or e) begin
  a = b & c;
  d = a | e;
end

 

Since two processes have been reduced to one, we can amortize the overhead of block scheduling. Assuming that the computations are cheap (e.g. the variables are single-bit reg) this is a big savings. However, this transform fails if VPI writes to a: since the transformed block is no longer sensitive to a, a write to a will never provoke an update of d. Adding +w permission to a will disable this optimization and result in correct behavior, but lower performance.


More importantly, write permission is required if vpi_put_value() will be called with a delay, so that the variable can be instrumented with the data structures required to implement the delay mechanism.



Callback permission

When +b permission is specified for a net/variable, then every time the variable is updated, the new value is compared to the previous value, and the value change callback is invoked if there is a change. The code to compare and execute callback is compiled into every expression that may update the variable, and the compare logic may be as costly as the update to the variable itself. Although DSim also has to do comparisons on variables for which other processes are sensitive, DSim tries to generate the comparison code only when necessary.


When the +b permission is specified for a scope containing a concurrent or immediate assertion, then every time an assertion evaluation starts or ends, DSim checks for registered callbacks to invoke. These checks add extra overhead to assertion evaluation, even if no callbacks are registered.



Force permission

When a variable is forced, the compiled code tracks whether or not the variable is currently forced. The force state of a variable is checked prior to each write, so that the write is "not done" when the variable is forced. Similar to callbacks, this adds considerable overhead to each write. Normally, DSim will instrument variables for forcing only if a Verilog force statement could potentially reference the variable - this property can be statically computed at compile time. However, with +f, DSim must instrument every single variable having this permission, which again is quite costly.


The situation is worse for nets. Individual bits of a net can be forced, so a write to a multi-bit net may result in some bits (the unforced bits) changing value, and other bits not changing. Net forcing is actually done using an interpreted engine, which also handles inout ports, strength logic modelling, tran solving and net delays. Again, this treatment is usually reserved only for those nets that can be determined to be forced at compile time, but +f will force this treatment for every affected net.


The SV-LRM restricts variable forcing as operating only on singular (ie non-unpacked-array) variables. As an extension, DSim lifts such a restriction to permit the operation on bit-select/part-select of singular variables, and individual singular elements (a.k.a. words) of an unpacked array. Bit-level and word-level forcing requires additional overhead to track possible forces down to the bit or word level. The required instrumentation level (none, entire, word, bit) is determined for each variable separately. For Verilog/SystemVerilog code this is done by analyzing all references to the variable to determine the correct level. For VPI access, the required level is determined by the VPI flags: * +acc+f instruments for forcing of singular variables. * +acc+W instruments for forcing of individual words of an uni-dimensional or multi-dimensional unpacked array. * +acc+F instruments for forcing of individual bits of a singular variable or word.


+acc+WF is relevant only for variables; all VPI forces to 4-state nets work at bit-level, even with +acc+f.


Performance loss with a global +acc+f, +acc+W, or +acc+F is so bad that it is strongly recommended to use an -acc-specs file to apply force permission only to those nets that specifically require it.



Tracing/debugging DPI/PLI/VPI

Name Description
-debug-vpi Log all failed/invalid VPI calls.
-trace-vpi Log all VPI calls, successful or otherwise. Also log actions associated with PLI library loading.
-trace-dpi Log all actions associated with DPI library loading.

Building Shared Libraries

This is platform-specific.



Linux x86, 32-bit

To compile:


 

gcc -c -o file.o file.c -I$DSIM_HOME/include

 

To create shared library:


 

gcc -shared -o mylib.so file1.o file2.o ...

 


Linux x86, 64-bit

To compile:


 

gcc -c -fPIC -o file.o file.c -I$DSIM_HOME/include

 

To create shared library:


 

gcc -shared -o mylib.so file1.o file2.o ...

 


Windows 10/11 x86, 64-bit

DSim was built with MinGW gcc. Internally, compiling and linking shared libraries with gcc has been tested. In theory, MSVC can also be used, but this has not been extensively tested.


For gcc, the compile command line is the same as for Linux on x86_64:


 

gcc -c -fPIC -o file.o file.c -I$DSIM_HOME/include

 

Linking, unfortunately, is complicated due to Windows restrictions on symbol import and export through dynamic link libraries (DLL).


For the discussion that follows, DLL and "shared library" refer to the same thing. It does not matter if the file extension is .dll (typical for Windows) or .so (typical for everything else).


  • A DLL may reference only symbols from other DLLs. However, the name of the referred-to DLL must be known at compile time. e.g. if you have a DPI import from image.so that refers to mydpi.so then image.so must be explicitly linked against mydpi.so so that the import can be recognized. A fine point: only the base filename is required to be known. It is legal to import from some name, and then arrange for a library of that name to be available in any visible directory (perhaps through %PATH% at run time).
  • Consequence of the previous: a Windows DLL is not permitted to import a symbol from the application. For this reason, the bulk of DSim is packaged as a DLL in itself.
  • A DLL "exports" symbols, both code and data, so that other DLLs, and applications can use them. However, at most 65536 symbols can be exported from any one DLL.

By default, the minGW linker (ld) will export every function symbol defined by a shared library. However, if you run afoul of the 64K limit, then you must explicitly export only those symbols you need. Furthermore, if you need to export a data definition, then you must use explicit export.



Import Implications

On Linux, -sv_lib is a run-time only option. However, on Windows, it is also required at compile-time. DSim will link the image against any library mentioned with -sv_lib or -pli_lib so that the linker knows which target DLL an import comes from.


If you are using SV task/function exports, then your DPI DLL must import symbols from the image. Details given below.


The bulk of DSim's run-time functionality is supplied as a DLL: dsim-dll.dll. dsim itself is just a small stub that loads dsim-dll.dll and runs the bulk of the compiler there. If you are using VPI functions, then you must import those symbols from dsim-dll.dll, by linking against it explicitly.



Explicit Export

In the absence of an explicit export file, the linker will export every symbol defined in your DLL.


Explicit export is done using an export file, whose name typically ends in .def. The format of this file is:


 

LIBRARY some_dll.so
EXPORTS
   <list all your functions and variables here>
   my_dpi_func1
   my_dpi_func2
   etc.

 

Note that an explicit .def file must list everything you want to export.



Simple Usage Scenario: no DPI Task/Function Export

In this scenario, you are writing a C library that contains DPI/PLI code. This library may call VPI routines (e.g. vpi_handle_by_name()) or DPI routines (e.g. svGetScope()) but will not be calling any tasks/functions exported via VPI from SystemVerilog.


The DLL you create for this will be linked with dsim-dll.dll (the main simulation engine). In turn, your DLL will be used to link the SystemVerilog image (which may be referencing imported tasks/functions defined in your DLL).


For your DPI DLL, you may use either implicit or explicit export. If you are writing a PLI DLL that defines the vlog_startup_routines array, then you must use explicit export, and export this array.


Implicit export link procedure:


 

gcc -shared -o mylib.so file1.o file2.o ... -L$DSIM_HOME/lib -ldsim-dll
dsim ... -genimage image -sv_lib mylib.so

 

Explicit export link procedure:


 

(prepare my_export.def)
gcc -shared -o mylib.so file1.o file2.o my_export.def ... -L$DSIM_HOME/lib -ldsim-dll
dsim ... -genimage image -sv_lib mylib.so

 


Complex Usage Scenario: DPI Task/Function Export

In this scenario, you are writing a C library that will call exported SystemVerilog tasks/functions. Your DLL must (eventually) link against the SystemVerilog image. However, your image likely contains calls into your DPI library, and must link against it! Here's how to navigate this chicken-and-egg situation:


  1. Create a stub image_export.def file that "exports" the SV tasks/functions that your library needs to call. This file represents what the image will eventually export on its own, except that the image doesn't exist yet.
  2. Use dlltool to prepare a stub import library from the stub exports file.
  3. (optional) Create a real "dpi_export.def" file that explicitly exports anything that your DPI DLL needs to export.
  4. Link your DPI library, passing both dpi_export.def and linking against the stub import library.


    (prepare image_export.deflisting the SV task/functions your DPI calls) (preparemy_export.def` listing the C functions that SV code will call) dlltool -d image_export.def -l libstub.a gcc -shared -o mylib.so file1.o file2.o my_export.def ... -lstub -L$DSIM_HOME/lib -ldsim-dll dsim ... -genimage image -sv_lib mylib.so


Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article