본문 바로가기

카테고리 없음

SystemVerilog의 DPI (2) data exchange

SystemVerilog와 C 사이의 data exchange는 DPI-C interface를 통해 이루어진다.

이번 게시글에서는 SV가 C 함수를 호출한다는 것 자체보다, SV에서 C로 함수 호출시 argument를 건네줌으로써 data를 건네줄 수 있다는 데에 초점을 맞추어서 본다!!

 

 

Data Mapping between SV and C

대부분의 SystemVerilog Data Type들은 C언어와 직접 대응되는 data type이 있는 반면, 

그렇지 않은 데이터 타입들(4 state variable이나 array)들은 DPI-C나 API에 define된 특정 type을 필요로 한다.. ( 기존의 SystemVerilog Data Type이 아니라, user-defined? DPI에서 새롭게 정의된?)

SystemVerilog Type 과 C data type 대응
SV C
byte  char
shortint short int
int int
longint long int
real double
string char*
string[n] char*
chandle char*
SystemVerilog Type 과 DPI-defined type 대응
SV C
bit svBit
bit[n:0] svBitVecVal
logic svLogic
reg svLogic
logic[n:0] svLogicVecVal*
reg[n:0] svLogicVecVal*
int[] svOpenArrayHandle
byte[] svOpenArrayHandle
shortint[] svOpenArrayHandle
longint[] svOpenArrayHandle
real[] svOpenArrayHandle

 

 

함수 호출시 argument(인자)를 전달하는 방법 두 가지.

SystemVerilog와 C에서는 함수 호출시 argument를 전달하는 방법엔 2 가지가 있다!

1. pass by value (call by value)

caller(함수 호출한 애)가 값을 전달하면, callee(호출받은 함수)는 값을 함수 내 variable에 copy하여 사용한다.

따라서 그 variable의 값을 변경시켜도, 함수 범위 밖에서의 값은 변하지 않는다. 

 

2. pass by reference (call by reference)

caller(함수 호출한 애)가 전달하려는 변수의 주소값(reference)을 전달하고 , callee(호출 받은 함수)는 값을 함수 내 포인터 variable에 그 data의 reference를 담는다. 결과적으로 함수 내 arg variable은 caller가 전달한 data에(바로 그 주소에) 직접 접근하게 된다.  따라서 함수에서 포인터 변수가 참조하는 값을 변경하면, 함수 범위 밖에서도 값이 변해있다.

 

 

SystemVerilog에서 DPI호출 시 pass by value인지, pass by reference인지는 argument direction에 의해서 결정된다.

 

 

1. pass by value (call by value)

// SV에서 call by value로 C함수 import할 때, 

function void f1(int a);                               // a는 input이지만 direction이 implicit.
function void f2(input int a);                     // explit direction mentioned

이처럼 system verilog는 argument의 direction이 input 이면, call by value이다. (값의 사본(copy)이 전달된다.)

 

// C에서 pass by value로 선언된 함수

void f1 (int a);

그냥 C 문법과 사실 별 다를 바 없음. 

 

2. pass by reference (call by reference)

// SV에서 Pass By Reference  C함수를 import할 때! 

function void f1(output int a);
// direction of a is output!!

이처럼 system verilog는 argument의 direction이 output 이면, call by reference이다. (값의 주솟값(reference)이 직접 전달된다.)

 

// C에서 Pass By Reference 함수를 선언할 때! 

void f1(int * a);

일반적인 C에서 Call by reference함수를 선언할 때와 동일하다.

a라는 pointer변수로 받은 reference를 담겠다. 

즉 caller가 전해준 변수를 직접 가리키겠다! 

 

 

 

 

백문이 불여일견 예제!

i) SV 의 int[] (int type array)를 C함수에서 svOpenArrayHandle과 맵핑하기.

// SV
import "DPI-C" function void comput_unsized_int_array ( input int i_value[], output int result[];

// C
void compute_unsized_int_array(const svOpenArrayHandle i_value, svOpenArrayHandle result);

SV에서 output 방향으로 선언된 result[] argument는 pass by reference이다.

SV에서 모든 array타입은 C에서 svOpenArrayHandle 타입(DPI-defined)와 호환된다.

c함수에서 선언된 array arg는 pass by value, pass by reference  모두 svOpenArrayHandle타입으로 선언된다. 포인터처럼 (*) 붙일 필요 X

 

ii) SV의 struct 를 C함수에서 struct 타입과 맵핑하기.

// SV
`define BIT_ARRAY_SIZE 16
typedef struct {
	byte aByte;
    int anInt;
    bit aBit;
    longint aLongInt;
    bit[`BIT_ARRAY_SIZE-1:0] aBitVector;
} dpi_c_ex_s;

import "DPI-C" function void compute_struct (
	input dpi_c_ex_s i_value,
    output dpi_c_ex_s result
);

 

// C
typedef struct dpi_c_ex_s {
	char aChar;
	int anInt;
	svBit aBit;
	long int aLongInt;
	svBitVecVal aBitVector;
} dpi_c_ex_s;

void compute_struct(
	const dpi_c_ex_s* i_value, 
    dpi_c_ex_s* output
);

아주 아주 아주 충격적인 사실은 struct type은 SV에서 output 뿐만 아니라 input으로 선언된 struct변수 (즉 call by value)에 대해서도 pointer 형태로 받는다는 사실이다. 

 

** SystemVerilog LRM (시스템베릴로그 IEEE표준 공식 문서)에 따르면...

packed data(예를 들면 struct type, 여러 변수가 하나의 변수로 표현/참조되는 것을 말함)는 DPI 함수 호출 시, 

argument로서 전달될 때, data의 reference가 전달된다.

즉, SV가 C함수를 호출하면서 struct타입을 그냥(input으로, 즉 call by value로) 넘겨줘도, 

default가 struct의 reference가 넘겨진다는 뜻.

 

나의 추측은 struct type은 변수명이 struct 변수가 위치한 시작 주소를 뜻하지않을까 싶네. 마치 C에서 array 이름이 array시작 주소를 가리키는 것처럼.