DPI-C的使用指南

第1章 CC++

文件后缀名为cVCS会使用gcc编译器;文件后缀名为cppcxxccVCS会使用g++编译器。VCSDPI接口是兼容C的,所以如果使用g++编译器,需要在c++的文件中加入如下:


#ifdef __cplusplus

extern "C" {

#endif

 // code 

 // code

#ifdef __cplusplus

}

#endif


第2章任务和函数

1.1 导入的任务和函数

语法:

import "DPI" [c_identifier =] [pure][context] function type name (args);

import "DPI" [c_identifier =] [context] task name (args);

规则说明:

1.       Context
使用context修饰的函数和任务,可以访问申明时的范围内的变量,而不仅仅局限在他的参数上。函数可以是purecontext或者其他类型的,任务只能是context或者non-context类型的。Context会导致仿真的效率变低,所以应当慎重使用。如果某个导出的函数或者任务,在C的环境中,需要通过PLIVPI访问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类型的,他的参数没有outputinout类型。这样的函数不能进行任何文件操作,访问任何其余的变量。

3.       输入参数的方向。
可以是inputoutputinout,不能是ref

4.       函数的返回值
必须是简单类型。

1.2 导出的任务和函数

语法:

export "DPI" [c_identifier =] function name;

export "DPI" [c_identifier =] task name;

1.3 示例

#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



第3章 参数的传递

1.1 参数传递方式

Small value通过值传递,其他的类型通过引用传递,open array通过handle传递。在SV中定义为input的参数,在C的实现中,参数通过const修饰。

1.2 Data Type Mapping

SYSTEMVERILOG TYPE

 

Integer32位有符号整数,4状态Verilog数据类型。Time64位无符号整数,4状态Verilog数据类型。对于C中的4状态packed数组。

标量的bitlogicreg数据类型映射C中的unaigned char

Packed bitlogicreg数据类型,映射C中的svBitsvLogic

体验新版博客

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


1.1.1 示例1

import "DPI" function void mydisplay(int a[2][2],logic b[4]);

void mydisplay(int a[2][2],svLogic b[4])

svLogic占用一个字节。C中的0123分别对应Verilog中的01zx

1.1.2 Chandle

// 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]);

  }

}

1.2 Packed Array Data Type Mapping

svBitVecVal表示2状态的值。svLogicVecVal表示4状态的值。这些值按照32位的数组来组织。

1.2.1 示例1

// 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);

}

1.2.2 示例2

// 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);

}

1.2.3 示例3

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);

}



1.1 Open Array Data Type Mapping

开放的数组就是在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);

 

1.1.1 示例1  Two-Dimensional Open Array

// 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

...

1.1.2 示例2

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


你可能感兴趣的:(systemverilog)