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 with5
. - 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
Post a Comment