文件后缀名为c,VCS会使用gcc编译器;文件后缀名为cpp,cxx,cc,VCS会使用g++编译器。VCS的DPI接口是兼容C的,所以如果使用g++编译器,需要在c++的文件中加入如下:
#ifdef __cplusplus
extern "C" {
#endif
// code
// code
#ifdef __cplusplus
}
#endif
语法:
import "DPI" [c_identifier =] [pure][context] function type name (args);
import "DPI" [c_identifier =] [context] task name (args);
规则说明:
1. Context
使用context修饰的函数和任务,可以访问申明时的范围内的变量,而不仅仅局限在他的参数上。函数可以是pure,context或者其他类型的,任务只能是context或者non-context类型的。Context会导致仿真的效率变低,所以应当慎重使用。如果某个导出的函数或者任务,在C的环境中,需要通过PLI,VPI访问SV范围内的全局变量,或者调用EXPORT的函数或任务,那么需要Context修饰符。
// SystemVerilog side, test.sv
module top;
import "DPI" context function void c_display();
export "DPI" task sv_display;
m1 m1_inst();
m2 m2_inst();
initial begin
c_display();
end
task sv_display();
$display("SV: top");
endtask
endmodule
module m1;
import "DPI" context function void c_display();
export "DPI" task sv_display;
initial begin
c_display();
end
task sv_display();
$display("SV: m1");
endtask
endmodule
module m2;
import "DPI" context function void c_display();
export "DPI" task sv_display;
initial begin
c_display;
end
task sv_display();
$display("SV: m2");
endtask
endmodule
#include
extern int sv_display();
void c_display() {
io_printf("\nC: c_display\n");
sv_display(); }
这个TB的执行结果如下:
C: c_display
SV: m1
C: c_display
SV: m2
C: c_display
SV: top
// SystemVerilog side, test.sv
module top;
import "DPI" context function void c_display();
export "DPI" task sv_display;
m1 m1_inst();
m2 m2_inst();
initial begin
#1;
c_display();
end
task sv_display();
$display("SV: top");
endtask
endmodule
module m1;
import "DPI" context function void c_display();
import "DPI" context function void mygetscope();
export "DPI" task sv_display;
initial begin
mygetscope();
c_display();
end
task sv_display();
$display("SV: m1");
endtask
endmodule
module m2;
import "DPI" context function void c_display();
export "DPI" task sv_display;
initial begin
#1;
c_display;
end
task sv_display();
$display("SV: m2");
endtask
endmodule
#include
#include
extern int sv_display();
svScope myscope;
void mygetscope() {
myscope = svGetScope();
}
void c_display() {
svSetScope(myscope);
io_printf("\nC: c_display\n");
sv_display();
}
这个TB的执行结果如下:
C: c_display
SV: m1
C: c_display
SV: m1
C: c_display
SV: m1
显然,在C函数中修改了Scope,那么sv_display将使用这个Scope中的导出任务。
2. Pure
使用Pure的函数能够提高仿真效率。当函数的结果仅仅依赖它的输入参数时,可以使用pure修饰符,这样的函数是non_void类型的,他的参数没有output和inout类型。这样的函数不能进行任何文件操作,访问任何其余的变量。
3. 输入参数的方向。
可以是input,output,inout,不能是ref。
4. 函数的返回值
必须是简单类型。
语法:
export "DPI" [c_identifier =] function name;
export "DPI" [c_identifier =] task name;
#include
extern void abp_write(int, int);
void c_test(int base) {
int addr, data;
for(addr=base; addr
data = addr * 100;
apb_write(addr, data);
printf("C_TEST: APB_Write : addr = 0x%8x, data = 0x%8x\n",
addr, data);
}
}
// SystemVerilog side, test.sv
import "DPI" context task c_test(input int base_addr);
program top;
semaphore bus_sem = new(1);
export "DPI" task apb_write;
task apb_write(input int addr, data);
bus_sem.get(1);
#10 $display("VLOG : APB Write : Addr = %x, Data = %x ", addr, data);
bus_sem.put(1);
endtask
initial begin
fork
c_test(32'h1000);
c_test(32'h2000);
join
end
endprogram
Small value通过值传递,其他的类型通过引用传递,open array通过handle传递。在SV中定义为input的参数,在C的实现中,参数通过const修饰。
SYSTEMVERILOG TYPE |
Integer,32位有符号整数,4状态Verilog数据类型。Time,64位无符号整数,4状态Verilog数据类型。对于C中的4状态packed数组。
标量的bit,logic,reg数据类型映射C中的unaigned char。
Packed bit,logic,reg数据类型,映射C中的svBit,svLogic。
C INPUT TYPE |
C OUTPUT TYPE |
|
byte |
char |
char*
|
shortint |
short int |
short int* |
int |
int |
int* |
longint |
long int |
long int* |
real |
double |
double* |
shortreal |
float |
float* |
chandle |
const void* |
void* |
string |
const char* |
char** |
string[n] |
const char* |
char** |
bit |
svBit |
svBit* |
logic / reg |
svLogic |
svLogic* |
bit[N:0] |
const svBitVec32* |
svBitVec32* |
logic[N:0] reg[N:0] |
const svLogicVec32* |
svLogicVec32* |
open array [] |
const svOpenArrayHandle |
svOpenArrayHandle |
import "DPI" function void mydisplay(int a[2][2],logic b[4]);
void mydisplay(int a[2][2],svLogic b[4])
svLogic占用一个字节。C中的0,1,2,3分别对应Verilog中的0,1,z,x。
// SystemVerilog side, test.sv
program p1;
chandle memory;
import "DPI" function chandle int_new(int size);
import "DPI" function void put_int_data(int size, chandle memory);
initial begin
int size = 10;
$display("SV: call DPI to allocate memory for %0d int",size);
memory = int_new(size);
$display("SV: call DPI to initialize the memory for %0d int",size);
put_int_data(size,memory);
end
endprogram
#include
#include
#include
int i;
void * int_new(int size) {
int *memory;
memory = (int *)malloc(size*sizeof(int));
printf("C/C++: allocate memory for %0d int in int_new\n",size);
return memory;
}
void put_int_data(int size,void* memory) {
int *temp;
temp = (int *) memory;
for(i=0;i
temp[i]=i;
printf("C/C++: memory[%0d] is set to %0d\n",i,temp[i]);
}
}
svBitVecVal表示2状态的值。svLogicVecVal表示4状态的值。这些值按照32位的数组来组织。
// SystemVerilog side, test.sv
program p1;
logic[63:0] a;
import "DPI" function void mydisplay(logic[63:0] a);
initial begin
a[31:0] = 32'b0;
a[63:32] = 32'hffff_ffff;
mydisplay(a);
end
endprogram
#include
void mydisplay(const svLogicVec32 a[2]) {
printf("a[0]=%x\n",a[0].d);
printf("a[1]=%x\n",a[1].d);
}
// SystemVerilog side, test.sv
program p1;
integer i;
import "DPI" function void mydisplay(integer i);
initial begin
i = 32'h0000_0101;
$display("SV: %h",i);
mydisplay(i);
i = 32'h0000_zzxx;
$display("SV: %h",i);
mydisplay(i);
end
endprogram
#include
void mydisplay(svLogicVec32 *i) {
io_printf("C: i.d is %d\n",i->d);
io_printf("C: i.c is %d\n",i->c);
}
Packed Struct
// SystemVerilog side, test.sv
program p1;
typedef struct packed {bit[1:0] a; bit b; bit c;} ps;
import "DPI" function void mydisplay(ps p);
initial begin
ps val1;
val1 = 4'hb;
mydisplay(val1);
end
endprogram
#include
void mydisplay(svBitVec32 p) {
printf("p is %x\n",p);
}
开放的数组就是在SV中定义这个参数时,没有指定数组的深度,仅仅像这样子定义a[]。在C中,使用svOpenArrayHandle进行变量申明。对于Scalar变量,可以直接得到其指针,再操作数据。对于Packed变量,可以使用特定的函数进行访问。
int svLeft(const svOpenArrayHandle h, int d);
int svRight(const svOpenArrayHandle h, int d);
int svLow(const svOpenArrayHandle h, int d);
int svHigh(const svOpenArrayHandle h, int d);
int svIncrement(const svOpenArrayHandle h, int d);
int svSize(const svOpenArrayHandle h, int d);
int svDimensions(const svOpenArrayHandle h);
void *svGetArrayPtr(const svOpenArrayHandle);得到数组的指针。
int svSizeOfArray(const svOpenArrayHandle);数组的体积,按照字节计数。
void *svGetArrElemPtr(const svOpenArrayHandle, int indx1,...);
对packed array进行写操作的函数。
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...);
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1);
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2);
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,int indx1, int indx2, int indx3);
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...);
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1);
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, int indx2);
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, int indx2, int indx3);
对packed array进行读操作的函数。
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...);
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1);
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2);
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, int indx3);
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...);
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1);
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2);
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2, int indx3);
对标量开放数组的访问。
svBit svGetBitArrElem (const svOpenArrayHandle s, int indx1, ...);
svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3);
svLogic svGetLogicArrElem (const svOpenArrayHandle s, int indx1, ...);
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3);
void svPutLogicArrElem (const svOpenArrayHandle d, svLogic value, int indx1, ...);
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2);
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3);
void svPutBitArrElem (const svOpenArrayHandle d, svBit value, int indx1, ...);
void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2);
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3);
// SystemVerilog side, test.sv
program p1;
int a[6:1][8:3];
import "DPI" function void mydisplay(inout int h[][]);
initial begin
for(int i=1;i<6;i++)
for(int j=3;j<8;j++) a[i][j]= i+j;
mydisplay(a);
for(int i=1;i<6;i++)
for(int j=3;j<8;j++) $display(a[i][j]);
end
endprogram
#include
int i,j;
void mydisplay(svOpenArrayHandle h) {
int lo1 = svLow(h,1);int hi1 = svHigh(h,1);
int lo2 = svLow(h,2);int hi2 = svHigh(h,2);
int *a;
for(i=lo1;i<=hi1;i++)
for(j=lo2;j<=hi2;j++) {
a =(int*)svGetArrElemPtr2(h,i,j);
printf("[%d][%d]=%d\n",i,j,*a);
*a = i*j;
}
}
输出结果:这个例子,我有个疑问,当参数增加一个long long *p,这时的再对这个两维的数组进行访问就会出现奇怪的问题。C中维数变成1了,数组的大小还是正确的。目前不知道原因。
[1][3]=4
[1][4]=5
...
Example 26-16 Another Packed Array
// SystemVerilog side, test.sv
program p1;
import "DPI" function void mydisplay(input bit[4:2] a[]);
bit[4:2] a[8];
initial begin
for(int i=0;i<8;i++) a[i]= 15+i;
for(int i=0;i<8;i++) $display("SV: a[%0d]",i,a[i]);
mydisplay(a);
end
endprogram
#include
int i;
void mydisplay(const svOpenArrayHandle a)
{
svBitVec32 c;
int low = svLow(a,1);
int high = svHigh(a,1);
for(i=low;i<=high;i++) {
svGetBitArrElemVec32(&c,a,i);
printf("C: a[%d]=%d\n",i,c);
}
}
输出结果。
C: a[0]=7
C: a[1]=0
C: a[2]=1