4.8 Import ( Direct Programming Interface)
4.8.1 Hello World
It's very simple as below.
program hello_dpi_world; import "DPI-C" function void hello_world(); initial begin hello_world(); end endprogram
We recommend to use "vpi_printf" instead of using "printf".
#include "vpi_user.h" #include "svdpi.h" #include "..\source\dpi_veritak_header.h" DPI_LINK_DECL DPI_DLLESPEC void hello_world() { vpi_printf("Hello DPI World! \n"); }
program dos_command_test; import "DPI-C" function int dos_command(string ); initial dos_command("dir"); endprogram
In this project, we check No Bufffer on project setting.
The result is as follows.
***** Veritak SV6464 Engine Version 446 Build May 20 2013***** Volume in drive C has no label. Volume Serial Number is 422E-BEA3 Directory of C:\Users\tak.sugawara\Documents\Visual Studio 2012\Projects\veritak_sv52\test\dpi_samples\system_call\source 2013/05/20 15:37 <DIR> . 2013/05/20 15:37 <DIR> .. 2013/05/20 15:37 512 dpi_veritak_header.h 2013/05/20 15:36 4,683 gen_header.vtakprj 2013/05/20 15:37 191 system_call.cpp 2013/05/20 15:39 123 system_call.sv 2013/05/20 15:38 4,715 system_call_x64_debug.vtakprj 2013/05/20 16:41 225 veritak_command.txt 6 File(s) 10,449 bytes 2 Dir(s) 877,000,818,688 bytes free ---------- Simulation finished. time=0ns
Here is c++ source.
#include "vpi_user.h" #include "svdpi.h" #include "..\source\dpi_veritak_header.h" DPI_LINK_DECL DPI_DLLESPEC int dos_command(const char*command) { return system(command); }
Small integral values of inputs can be passed directly
However, for output or inout ports, they can not be passed directly. They can be passed by reference.
import "DPI-C" function int pass_simple_values(bit , reg , shortint,int ,longint, shortreal ,real,chandle ,string); import "DPI-C" function int pass_simple_values_output(output bit , reg , shortint,int ,longint, shortreal ,real,chandle ,string); import "DPI-C" function int pass_simple_values_inout(inout bit , reg , shortint,int ,longint, shortreal ,real,chandle ,string); import "DPI-C" function int pass_str(output string); bit b1=1; reg r1=1'bz; shortint si=16'haabb; int i=32'habcd_1234; longint l=64'hdead_beef_abcd_1234; shortreal sr=1.1; real r=1.11; chandle ptr=null; string s="Passing Simple Values"; initial begin $display("returnd value=%x",pass_simple_values(b1,r1,si,i,l,sr,r,ptr,s)); pass_simple_values_output(b1,r1,si,i,l,sr,r,ptr,s); $display("b1=%b r1=%b si=%x i=%x l=%x sr=%f r=%f ptr=%x s=%s",b1,r1,si,i,l,sr,r,ptr,s); $display(""); pass_simple_values_inout(b1,r1,si,i,l,sr,r,ptr,s); $display("b1=%b r1=%b si=%d i=%d l=%d sr=%f r=%f ptr=%x s=%s",b1,r1,si,i,l,sr,r,ptr,s); end endprogram
You'll know how to pass the values by checking generated header file.
In "pass_simple_values" function all ports are input.Small integral values can be passed directly.
The other function's ports are output or inout. ( You can not declare ref
in DPI.) In those cases, you must access the values by reference.
/* Copyright 2013 www.sugawara-systems.com * Note: * This file is automatically generated. * Please do not edit this file - you will lose your edits.*/ #ifndef INCLUDED_DPIHEADER #define INCLUDED_DPIHEADER #ifdef __cplusplus #define DPI_LINK_DECL extern "C" #else #define DPI_LINK_DECL #endif #include "svdpi.h" DPI_LINK_DECL DPI_DLLESPEC int pass_simple_values(svBit ,svLogic ,short ,int ,int64_t ,float ,double ,const void* ,const char* ); DPI_LINK_DECL DPI_DLLESPEC int pass_simple_values_inout(svBit* ,svLogic* ,short* ,int* ,int64_t* ,float* ,double* ,void** ,char** ); DPI_LINK_DECL DPI_DLLESPEC int pass_simple_values_output(svBit* ,svLogic* ,short* ,int* ,int64_t* ,float* ,double* ,void** ,char** ); DPI_LINK_DECL DPI_DLLISPEC int run_sc_task_vthread(unsigned sc_back_patch_no, void* first_arg_address); #endif
Below is an example source of c++.
#include "vpi_user.h" #include "svdpi.h" #include "..\source\dpi_veritak_header.h" extern "C" __declspec(dllexport) int pass_simple_values(svBit bit ,svLogic reg ,short si ,int i ,int64_t l ,float f //float is not Supported in VeritakSV. Use real(double) ,double d ,const void* ptr ,const char* s ) { vpi_printf("bit=%hhd reg=%hhd si=%hx int=%x, longint=%llx,f=%hf d=%g ptr=%x,s=%s \n",bit,reg,si,i,l,f,d,ptr,s); return i; } DPI_LINK_DECL DPI_DLLESPEC int pass_str(char**pp) { static char buffer[100]="Hi, I'm C."; *pp=buffer; return 0; } DPI_LINK_DECL DPI_DLLESPEC int pass_simple_values_inout(svBit* bit_p ,svLogic* logic_p ,short* short_p ,int* int_p ,int64_t* ll_p ,float* float_p ,double* double_p ,void** void_p ,char** str_p) { vpi_printf("I'm C. SV passing values are;bit=%hhd reg=%hhd si=%hx int=%x, longint=%llx,f=%hf d=%g ptr=%x,s=%s \n",*bit_p,*logic_p,*short_p,*int_p,*ll_p,*float_p,*double_p,*void_p,*str_p); *bit_p=1; *logic_p=0; *short_p=1234; *int_p=123456; *ll_p=123456789; *float_p=1110.1; *double_p=11110.1; *void_p=(void*)0; static char buffer[100]="Hi, I'm C again."; *str_p=buffer; return 0; } DPI_LINK_DECL DPI_DLLESPEC int pass_simple_values_output(svBit* bit_p ,svLogic* logic_p ,short* short_p ,int* int_p ,int64_t* ll_p ,float* float_p ,double* double_p ,void** void_p ,char** str_p) { *bit_p=0; *logic_p=1; *int_p=0x5678abcd; *ll_p=0x123456789abcdef0; *float_p=110.1; *double_p=1110.1; *void_p=(void*)0; static char buffer[100]="Hi, I'm C."; *str_p=buffer; return 0; }
***** Veritak SV6464 Engine Version 446 Build May 20 2013***** bit=1 reg=2 si=aabb int=abcd1234, longint=deadbeefabcd1234,f=1.100000 d=1.11 ptr=0,s=Passing Simple Values returnd value=abcd1234 b1=0 r1=1 si=aabb i=5678abcd l=123456789abcdef0 sr=110.099998 r=1110.100000 ptr=0000000000000000 s=Hi, I'm C. I'm C. SV passing values are;bit=0 reg=1 si=aabb int=5678abcd, longint=123456789abcdef0,f=110.099998 d=1110.1 ptr=0,s=Hi, I'm C. b1=1 r1=0 si= 1234 i= 123456 l= 123456789 sr=1110.099976 r=11110.100000 ptr=0000000000000000 s=Hi, I'm C again. ---------- Simulation finished. time=0ns **** Test Done. Total 0.00[msec] ****
Data types mapping between SystemVerilog and C for small values
SystemVerilog | C(input) | C(output/inout) |
---|---|---|
byte | char | char* |
shortint | short | short* |
int | int | int* |
longint | long long int | long long int* |
shortreal | float | float* |
real | double | double* |
string | const char* | char** |
chandle | void* | void** |
bit | char | svBit* |
logic | char | svLogic* |
4.8.12 Call OpenCV
4.8.13 Call Python
@You can embed your Python in C and bind them to SystemVerilog functions using DPI.
Here is an example of Python called by C. A function named "multiply" receives 2 arguments from C, then return the result to C.
def multiply(a,b): print ("I'm Python,will compute", a, "times", b) c = 0 for i in range(0, a): c = c + b return c def add (a,b): return a+b
4.8.13.1 Python Installation
First, you need python installation for your configuration.
Please note main program is simulator and python is now embeded program wrapped in C. Python itself can run both in 32bit and 64bit since it is interpreter based.. But interface to C needs explicit native linkage, such as x64(64bit) or X86(32bit).
In "libs" folder on Python, you'll find pythonxx.lib which should be imported to C program.
Native Language | Python Insallation | Remarks | |
---|---|---|---|
VeritakWinSV6464 | X64 (64bit) | X86-64 MSI | 64/64bit |
VeritakWinSV6432 | X86(32bit) | X86 MSI | 64/32bit |
VeritakWinSV3232 | X86(32bit) | X86 MSI | 32/32 |
4.8.13.2 C routine
We revised C program for DPI as below..
#include "vpi_user.h" #include "svdpi.h" #include "..\source\dpi_veritak_header.h" #include#include __declspec(dllexport) int call_python(const char* file_name,const char* function_name,int arg1,int arg2) { //vpi_printf("%s %s %d %d\n",file_name,function_name,arg1,arg2); PyObject *pName, *pModule, *pDict, *pFunc; PyObject *pArgs, *pValue; int i; int result=0; int argc=5;//[0] call [1]:file_name [2]:function_name [3] arg1 [4] arg2 try { Py_Initialize(); pName = PyUnicode_FromString(file_name); // Error checking of pName left out pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule != NULL) { pFunc = PyObject_GetAttrString(pModule, function_name); //Func is a new reference if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_New(argc - 3); for (i = 0; i < argc - 3; ++i) { switch (i){ case 0: pValue=PyLong_FromLong(arg1); break; case 1: pValue=PyLong_FromLong(arg2); break; default: assert(0); } if (!pValue) { Py_DECREF(pArgs); Py_DECREF(pModule); throw("Cannot convert argument\n"); } // pValue reference stolen here: PyTuple_SetItem(pArgs, i, pValue); } pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (pValue != NULL) { result= PyLong_AsLong(pValue); printf("I'm C, Result of call: %ld\n",result); Py_DECREF(pValue); } else { Py_DECREF(pFunc); Py_DECREF(pModule); PyErr_Print(); throw("Call failed\n"); } } else { if (PyErr_Occurred()) PyErr_Print(); throw("Cannot find function \n"); } Py_XDECREF(pFunc); Py_DECREF(pModule); } else { PyErr_Print(); throw("Failed to load \n"); } Py_Finalize(); return result; } catch (const char* str ) //catach the exception. { vpi_printf("Python Call Exception %s(%d)\n", __FILE__,__LINE__); printf("%s",str); vpi_control(vpiFinish); return 0; } }
4.8.3.3 SystemVerilog Routine
Finally, we call C as DPI function.
program call_python_test; import "DPI-C" function int call_python(string python_file, string function_name,int arg1,int arg2); int i; initial begin i=call_python("multiply","multiply",2,3); $display("I'm SV, result=%d\n",i); end endprogram
4.8.13.4 Result
We got the result of multiply from Python via C.
***** Veritak SV6464 Engine Version 446 Build May 18 2013***** I'm C, Result of call: 6 I'm Python,will compute 2 times 3 I'm SV, result= 6
You'll find out displaying order is strange. This is caused by different C-runtime libraries on DLLs. For C, we can use the same version of C compiler, but Python may use another version if we don't compile it from source.