SystemVerilog and Direct Programming Interface
SystemVerilog and Direct Programming Interface
INTRODUCTIONS
What Is Dpi-C ?
From long time , Users have needes a simple way of communication to foreign
languages from verilog. VPI and PLI are not easy interfaces to Use . Users need
detailed knowledge of PLI and VPI even for a simple program. Most of the time, users
do not need the sophisticated capabilities of VPI and PLI. DPI also permits C/C++
code to wait for Verilog events and C/C++ tasks and functions can be disabledfrom
SystemVerilog.
SystemVerilog introduces a new foreign language interface called the Direct
Programming Interface (DPI). The DPI provides a very simple, straightforward, and
efficient way to connect SystemVerilog and foreign language code unlike PLI or VPI.
DPI consists of two separate layers: the SystemVerilog layer and a foreign language
layer. Both sides of DPI-C are fully isolated. Which programming language is actually
used as the foreign language is transparent and irrelevant for the System-Verilog side
of this interface. Neither the SystemVerilog compiler nor the foreign language
compiler is required to analyze the source code in the others language. Different
programming languages can be used and supported with the same intact
SystemVerilog layer.
DPI-C follows the principle of a black box: the specification and the implementation
of a component are clearly separated, and the actual implementation is transparent
to the rest of the system. Therefore, the actual programming language of the
implementation is also transparent, although this standard defines only C linkage
semantics. The separation between SystemVerilog code and the foreign language is
based on using functions as the natural encapsulation unit in SystemVerilog.
DPI-C consists of two separate layers: the SystemVerilog layer and a foreign language
layer. The SystemVerilog layer does not depend on which programming language is
actually used as the foreign language. Although different programming languages
can be supported and used with the intact SystemVerilog layer, SystemVerilog
defines a foreign language layer only for the C programming language. Nevertheless,
SystemVerilog code shall look identical and its semantics shall be unchanged for any
foreign language layer.
Dpi-C Systemverilog Layer
The SystemVerilog side of DPI-C does not depend on the foreign programming
language. In particular, the actual function call protocol and argument passing
mechanisms used in the foreign language are transparent and irrelevant to
SystemVerilog. SystemVerilog code shall look identical regardless of what code the
foreign side of the interface is using. The semantics of the SystemVerilog side of the
interface is independent from the foreign side of the interface.
Functions implemented in C that can be called from SystemVerilog and can in turn
call exported tasks; such functions are referred to as imported tasks.
IMPORT
Import Methods
In SV Code
Step1 : Import the C function
initial
begin
string_sv2c();
end
In C code:
Step3: Define the Imported function
void string_sv2c(){
printf(" C: Hellow from C ");
}
Full Example:
CODE: SV_file
program main;
string str;
initial
begin
string_sv2c();
end
endprogram
CODE: C_file
#include "svdpi.h"
void string_sv2c(){
printf(" C: Hellow from C ");
}
RESULTS
C: Hellow from C
Standard C Functions
EXAMPLE:
import "DPI" function chandle malloc(int size);
import "DPI" function void free(chandle ptr);
NAMING
Global Name
EXAMPLE
export "DPI-C" foo_plus = function \foo+ ; // "foo+" exported as "foo_plus"
import "DPI-C" init_1 = function void \init[1] (); // "init_1" is a linkage name
Local Name
If a global name is not explicitly given, it shall be the same as the SystemVerilog task
or function name.
EXAMPLE:
export "DPI-C" function foo;
EXAMPLE:
import "DPI-C" \begin = function void \init[2] (); // "begin" is a linkage name
EXPORT
Export Methods
In SV Code :
Setp1: Export the systemverilog function
In C code :
Step3: Export the Systemverilog function
void import_func()
{
export_func();
}
Full Example:
CODE: SV_file.sv
program main;
initial
begin
import_func();
end
endprogram
CODE: C_file.c
#include "stdio.h"
#include "vc_hdrs.h"
#include "svdpi.h"
void import_func()
{
export_func();
}
RESULTS:
SV: Hello from SV
CODE:SV_file.sv
program main;
task export_task();
$display("SV: Entered the export function . wait for some time : %0d
",$time);
#100;
$display("SV: After waiting %0d",$time);
endtask
initial
begin
$display("SV: Before calling import function %0d",$time);
import_task();
$display("SV: After calling import function %0d",$time);
end
endprogram
CODE: C_file.c
extern void export_task();
void import_task()
{
printf(" C: Before calling export function\n");
export_task();
printf(" C: After calling export function\n");
}
RESULTS
Pure Function
A function whose result depends solely on the values of its input arguments and with
no side effects can be specified as pure. This can usually allow for more
optimizations and thus can result in improved simulation performance.
A pure function call can be safely eliminated if its result is not needed or if the
previous result for the same values of input arguments is available somehow and can
be reused without needing to recalculate. Only nonvoid functions with no output or
inout arguments can be specified as pure.
Context Function
Some DPI imported tasks or functions or other interface functions called from them
require that the context of their call be known. The SystemVerilog context of DPI
export tasks and functions must be known when they are called, including when they
are called by imports. When an import invokes the svSetScope utility prior to calling
the export, it sets the context explicitly. Otherwise, the context will be the context
of the instantiated scope where the import declaration is located.
CODE: SV_file_1.sv
module module_1;
module_2 instance_1();
initial
import_func();
endmodule
CODE: SV_file_2.sv
module module_2;
initial
import_func();
endmodule
CODE:C_file.c
#include "svdpi.h"
#include "stdio.h"
void import_func()
{
printf(" C: Im called fronm Scope :: %s \n\n
",svGetNameFromScope(svGetScope() ));
export_func();
}
RESULTS
DATA TYPES
The SystemVerilog DPI supports only SystemVerilog data types, which are the data
types that can cross the boundary between SystemVerilog and a foreign language in
both the direction. On the other hand, the data types used in C code shall be C types.
A value that is passed through the DPI is specified in SystemVerilog code as a value of
SystemVerilog data type, while the same value is declared C code as a value of C
data type. Therefore, a pair of matching type definitions is required to pass a value
through DPI, the SystemVerilog definition and the C definition.
The following SystemVerilog types are the only permitted types for formal
arguments of import and export tasks or functions:
void, byte, shortint, int, longint, real, shortreal, chandle, and string
Scalar values of type bit and logic
Packed arrays, structs, and unions composed of types bit and logic. Every packed
type is eventually equivalent to a packed one-dimensional array. On the foreign
language side of the DPI, all packed types are perceived as packed one-dimensional
arrays regardless of their declaration in the SystemVerilog code.
Enumeration types interpreted as the type associated with that enumeration
Types constructed from the supported types with the help of the constructs:
struct , union , Unpacked array , typedef
The DPI defines the canonical representation of packed 2-state (type svBitVecVal)
and 4-state arrays (type svBitVecVal). svLogicVecVal is fully equivalent to type
s_vpi_vecval, which is used to represent 4-state logic in VPI.
CODE:SV_file.sv
program main;
logic a;
import "DPI" function void show(logic a);
initial begin
a = 1'b0;
show(a);
a = 1'b1;
show(a);
a = 1'bX;
show(a);
a = 1'bZ;
show(a);
end
endprogram
CODE: C_file.v
#include <stdio.h>
#include <svdpi.h>
}
RESULTS
a is 0
a is 1
a is z
a is x
ARRAYS
Open Arrays
The size of the packed dimension, the unpacked dimension, or both dimensions can
remain unspecified,such cases are referred to as open arrays (or unsized arrays).
Open arrays allow the use of generic code to handle different sizes. Formal
arguments in SystemVerilog can be specified as open arrays solely in import
declarations, exported. SystemVerilog functions cannot have formal arguments
specified as open arrays.
OpenArrays are good for generic programming, since C language doesn't have
concept of parameterizable arguments. Standared query and library functions are
provided to determine array information to acess array elements.
CODE:SV_file.sv
program main;
int fxd_arr_1[8:3];
int fxd_arr_2[12:1];
initial
begin
for (int i = 3; i<=8 ; i++)
begin
fxd_arr_1[i] = $random() ;
$display("SV:fxd_arr_1 %0d %d ",i, fxd_arr_1[i] );
end
CODE: C_file.c
#include <stdio.h>
#include <svdpi.h>
RESULTS:
SV:fxd_arr_1 3 303379748
SV:fxd_arr_1 4 -1064739199
SV:fxd_arr_1 5 -2071669239
SV:fxd_arr_1 6 -1309649309
SV:fxd_arr_1 7 112818957
SV:fxd_arr_1 8 1189058957
Passing fxd_arr_1 to C
C: 3 303379748
C: 4 -1064739199
C: 5 -2071669239
C: 6 -1309649309
C: 7 112818957
C: 8 1189058957
Passing fxd_arr_2 to C
Array Left 12, Array Right 1
C: 1 -1295874971
C: 2 -1992863214
C: 3 15983361
C: 4 114806029
C: 5 992211318
C: 6 512609597
C: 7 1993627629
C: 8 1177417612
C: 9 2097015289
C: 10 -482925370
C: 11 -487095099
C: 12 -720121174
Packed Arrays
CODE:SV_file.sv
program main;
initial begin
get_nums(nums);
foreach (nums[i]) $display(i,nums[i]);
end
endprogram
CODE:C_file.c
#include "svdpi.h"
RESULTS:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
svLow() shall return the minimum of left index and right index of the dimension.
svHigh() shall return the maximum of left index and right index of the dimension.
svIncrement() shall return 1 if left index is greater than or equal to right index and
-1 if left index is less than right index.
svLength() shall return the number of elements in the dimension, which is
equivalent to high index - low index + 1.
CODE: SV_file.sv
program main;
int fxd_arr_1[8:3];
int fxd_arr_2[1:13];
initial
begin
$display("\n Passing fxd_arr_1 to C \n");
pass_array( fxd_arr_1 );
$display("\n Passing fxd_arr_2 to C \n");
pass_array( fxd_arr_2 );
end
endprogram
CODE: C_file.c
#include <stdio.h>
#include <svdpi.h>
RESULTS:
Passing fxd_arr_1 to C
Array Pointer is 80fdc58
Lower index 3
Higher index 8
Left index 8
Right index 3
Length of array 6
Incremental 1
Dimentions of Array 1
Size of Array in bytes 24
Passing fxd_arr_2 to C
DPI allows to pass the structs and Unions . This can be done by passing pointers or by
packing.
In the following example, a "struct" is passed from SystemVerilog to C and also from
C to Systemverilog using import and export functions. While passing the "struct"
data type, the data is packed in to array and passed from SV to C and then the array
is decoded back to Struct in C. The same when the Struct is passed from C to
SystemVerilog.
CODE: C_file.c
#include "stdio.h"
#include "vc_hdrs.h"
#include "svdpi.h"
extern "C" {
typedef struct{
int a;
int b;
char c;
} C_struct;
void import_func()
{
C_struct s_data;
unsigned int arr[3];
s_data.a = 51;
s_data.b = 242;
s_data.c = 35;
arr[0] = s_data.a ;
arr[1] = s_data.b ;
arr[2] = s_data.c ;
export_func(arr);
}
}
CODE: SV_file.sv
program main;
SV_struct s_data;
s_data.a = arr[0];
s_data.b = arr[1];
s_data.c = arr[2];
initial
begin
import_func();
end
endprogram
RESULTS:
C : s_data.a = 51
C : s_data.b = 242
C : s_data.c = 35
SV: s_data.a = 51
SV: s_data.b = 242
SV: s_data.c = 35
CODE: C_file.c
#include "svdpi.h"
CODE: SV_file.sv
initial begin
endprogram
RESULTS:
SV: 0 : [303379748,-1064739199]
SV: 1 : [-2071669239,-1309649309]
SV: 2 : [112818957,1189058957]
SV: 3 : [-1295874971,-1992863214]
SV: 4 : [15983361,114806029]
C : 0 : [303379748,-1064739199]
C : 1: [-2071669239,-1309649309]
C : 2: [112818957,1189058957]
C : 3: [-1295874971,-1992863214]
C : 4: [15983361,114806029]
CODE:SV_file
module m;
initial begin
a = 3'b100;
u.a = 3'b100;
foo8(a, u);
end
endmodule
CODE:C_file
#include "svdpi.h"
void foo8(
const svBitVecVal* fa,
const svBitVecVal* fu)
{
printf("fa is %d, fu is %d\n", *fa, *fu);
}
ARGUMENTS TYPE
Pass By Ref
For arguments passed by reference, a reference (a pointer) to the actual data object
is passed. In the case of packed data, a reference to a canonical data object is
passed. The actual argument is usually allocated by a caller. The caller can also pass
a reference to an object already allocated somewhere else, for example, its own
formal argument passed by reference. If an argument of type T is passed by
reference, the formal argument shall be of type T*. Packed arrays are passed using a
pointer to the appropriate canonical type definition, either svLogicVecVal* or
svBitVecVal*.
Pass By Value
Only small values of formal input arguments are passed by value. Function results
are also directly passed by value. The user needs to provide the C type equivalent to
the SystemVerilog type of a formal argument if an argument is passed by value.
Passing String
CODE: SV_file.sv
program main;
string str;
endprogram
CODE: C_file.c
#include "svdpi.h"
int string_sv2c(const char* str){
printf(" C: %s",str);
return 0;
RESULTS
From the Data type mapping table, a SystemVerilog "String" is mapped to "const
char*" in C. In the Following example, string "HELLO: This string is created in C" is
assigned to a string and passed as return value to function import "string_c2sv" and
this import function is called in SystemVerilog.
CODE: SV_file.v
program main;
string str;
import "DPI-C" context function string string_c2sv();
initial
begin
str = string_c2sv();
$display(" SV: %s ",str);
end
endprogram
CODE: C_file.c
#include "svdpi.h"
RESULTS:
DISABLIE
Include Files
Applications that use the DPI with C code usually need this main include file. The
include file svdpi.h defines the types for canonical representation of 2-state (bit)
and 4-state (logic) values and passing references to SystemVerilog data objects. The
file also provides function headers and defines a number of helper macros and
constants. The content of svdpi.h does not depend on any particular implementation;
all simulators shall use the same file.