Gain performance with your DPI - understand nuances of SystemVerilog DPI Pure Functions

Is your DPI-enabled SystemVerilog simulation running slow? Are you looking for ways to improve performance? Sometimes, a small remodelling of your DPI functions and using pure functions can help significantly.

The Direct Programming Interface (DPI) allows SystemVerilog to interact with C code. Among the DPI constructs, pure functions are special because they are side-effect free and predictable. Using them correctly can improve simulation speed and reliability.

However, SystemVerilog LRM imposes several subtle restrictions on imported pure functions. Let's delve into one such nuance today a bit deeper!


Referential Transparency

Referential transparency is a concept from programming. An expression is referentially transparent if it can always be replaced by its value without changing the behaviour of the program. For example:

  • The expression 2 + 3 can always be replaced with 5.
  • The expression rand() cannot, since each call may give a different result.

In SystemVerilog, a pure DPI function must follow this rule:

  • Its result depends only on its inputs.
  • It must not change any state that the caller can see.
  • It must be safe for tools to reuse, reorder, or remove repeated calls.

The Problem with output

Using an output or inout argument in a pure DPI function is illegal. Even though SV functions do not advance simulation time, modifying caller-owned storage breaks referential transparency.

For example, consider this illegal declaration:

import "DPI-C" pure function int f(int a, output int b);

On the C side:

int f(int a, int* b) {
    *b = *b + 1;      // side effect
    return a * a;     // result
}

On the SystemVerilog side:

int y = 0;
int r1, r2, s;

r1 = f(3, y);   // user expects y = 1
r2 = f(3, y);   // user expects y = 2
s  = y;         // so s = 2

Reusing the function result may break expectations and show why output arguments are not allowed.


The Correct Form

A proper pure DPI function returns its result through the return value only:

import "DPI-C" pure function int f(int a);

C implementation:

int f(int a) {
    return a * a;
}

This ensures correctness and enables simulators to safely reuse results for better performance.


Detecting Issues and Improving Simulation

A Custom build BYOL (Build Your Own Linter) such as a DPILint checker can flag illegal use of output or inout arguments. This helps engineers remodel their code correctly, improving simulation performance by allowing optimisers to safely inline or reuse pure function calls.


Conclusion

Remodelling your DPI functions to use pure correctly not only ensures correctness but can also speed up your simulations. DPILint helps detect violations and guide improvements, making your simulation safer and faster.

Comments

Popular posts from this blog

Join Us in Cambridge - Advancing Chip Verification with UVMLint & SVALint

Open Source Chip Design and Verification Event: Unlocking the Future of Semiconductor Innovation

SVALint Technical Meetup – Reading, UK