はじめに
Xilinx ZynqMP SoC VIP の中を調べる(その12)
今回は、xelab コマンドへの --dpiheader オプションによって生成された dpi.h をみてみます。
dpi.h
--dpiheader dpi.h にて生成された dpi.h は、次のようになっています。4つの関数のプロトタイプ宣言になります。SystemVerilog 側の export task は戻り値の型が int になっています。
- DPI_LINKER_DECL DPI_DLLESPEC int dpi_main();
- DPI_LINKER_DECL int vip_nop( int count );
- DPI_LINKER_DECL int vip_write32( unsigned int addr, unsigned int data );
- DPI_LINKER_DECL int vip_read32( unsigned int addr, unsigned int* data );
/**********************************************************************/ /* ____ ____ */ /* / /\/ / */ /* /___/ \ / */ /* \ \ \/ */ /* \ \ Copyright (c) 2003-2020 Xilinx, Inc. */ /* / / All Right Reserved. */ /* /---/ /\ */ /* \ \ / \ */ /* \___\/\___\ */ /**********************************************************************/ /* NOTE: DO NOT EDIT. AUTOMATICALLY GENERATED FILE. CHANGES WILL BE LOST. */ #ifndef DPI_H #define DPI_H #ifdef __cplusplus #define DPI_LINKER_DECL extern "C" #else #define DPI_LINKER_DECL #endif #include "svdpi.h" /* Imported (by SV) task */ DPI_LINKER_DECL DPI_DLLESPEC int dpi_main( ); /* Exported (from SV) task*/ DPI_LINKER_DECL int vip_nop( int count ); /* Exported (from SV) task*/ DPI_LINKER_DECL int vip_write32( unsigned int addr, unsigned int data ); /* Exported (from SV) task*/ DPI_LINKER_DECL int vip_read32( unsigned int addr, unsigned int* data ); #endif
上記の4つの関数の内、dpi_main 関数は、テストプログラム内で定義します。それ以外の3つの関数はどこで定義されているんでしょうか?
DPI export task はどこで定義されている?
これら3つのファイルは、xsim.dir/tb_behv/obj/xsim_27.c の中で定義されています。
extern "C" { extern "C" { DPI_DLLESPEC int vip_nop(int arg0) { int result ; DPIVerifyScope(); int functionToCall = staticScopeCheck("vip_nop") ; switch(functionToCall) { case 0: {
DPI_DLLESPEC int vip_write32(unsigned int arg0, unsigned int arg1) { int result ; DPIVerifyScope(); int functionToCall = staticScopeCheck("vip_write32") ; switch(functionToCall) { case 1: {
DPI_DLLESPEC int vip_read32(unsigned int arg0, unsigned int* arg1) { int result ; DPIVerifyScope(); int functionToCall = staticScopeCheck("vip_read32") ; switch(functionToCall) { switch(functionToCall) { case 2: {
3つの関数の最初は、ほぼ同じです。staticScopeCheck 関数の引数の文字列が各関数名になっているだけです。staticScopeCheck 関数の戻り値の使い方がちょっと違うようで、vip_nop が 0、vip_write32 が 1、vip_read32 が 2 になっているので、各関数の番号がそうなっているんでしょうね。
int result ; DPIVerifyScope(); int functionToCall = staticScopeCheck("vip_XXX") ; switch(functionToCall) { case 1: {
それ以降のコードでは、だいたい同じでDPIInitialzeTask からDPIInvokeTask までが違うようです。
{ DPIFlushAll(); int staticIndex = 0 ; char* IP = NULL ; staticIndex = svGetScopeStaticId() ; IP = svGetScopeIP(); int callingProcessOffset = DPIGetTaskCaller() ; char* SP ; void* oldSPcontext = DPIGetCurrentContext(); // この部分が違う DPIYieldCurrentContext() ; DPIDeleteTaskInvocation(SP) ; *((char**)(IP + callingProcessOffset + 80)) = oldSP ; DPISetCurrentContext(oldSPcontext); DPIFlushAll(); if (*(unsigned int*)(SP + 155) == 1) { result = 1 ; } else { result = 0 ; } }
おわりに
今回は、xelab コマンドが生成した、dpi.h と DPI-C export task に対応する Cの関数 (vip_nop, vip_read32, vip_write32) の中身をみてみました。
次回は、シミュレーションの実行について、説明します。