如何使用DPI-C嵌入Systemverilog解释器?

li9yvcax  于 2023-06-28  发布在  其他
关注(0)|答案(3)|浏览(155)

问题描述

我用SystemVerilog进行设计,并用同一种语言编写测试平台。我希望能够编译我的设计,并在模拟过程中测试不同的功能,就像您使用带有e的解释器一样。理想情况下,当模拟器遇到某行时,我会在模拟时弹出一个终端。

潜在想法

我看过DPI-C,似乎我必须“导出”项目中的所有任务,以便从解释器运行它们。但是,我不确定如何自动完成此操作,或者是否有更好的方法。此外,我不知道如何让C为我打开第二个shell来输入SystemVerilog任务(我想运行的任务)。
这是我的同事们所提出的一个问题,如果在编译一个测试平台之间不需要等待10分钟,那么生活就会少很多痛苦。

drkbr07n

drkbr07n1#

你好,我提供我的两分钱与另一个例子。
示例SV-CODE

////////////////////////////////////////////////////////////////////////
 //IMPORT FUNCTION DPI DECLARATION FROM C
 ////////////////////////////////////////////////////////////////////////            
import "DPI-C" function void python_sign_msg(string key_file_name, string msg_file_name, string signed_file_name );
import "DPI-C" function string return_string_in_c(string text, inout string output_txt);    
    

typedef class keycontrol_seq_handles;
//-----------------------
class keycontrol_predictor#(int PARAM_PLACEHOLDER = 1) extends pve_predictor#(keycontrol_seq_handles);//extends uvm_component;
………..
//////////////////////
//USE OF DPI
//////////////////////
string output_c,output2_c;
output_c = return_string_in_c("This text",output2_c); 
python_sign_msg("file.txt","bla","blo");

endclass

C-CODE

//include DPI
#include "svdpi.h"
//include the IO files
#include <stdio.h>
//include string functions
#include <string.h>
//include use of malloc
#include <stdlib.h>
//include Phyton embed lib
#include <Python.h>
 
 
//to add the ability to use printf
// same inputs as defined in SV with python path which is the defined surrounded by double quotes ""

#ifndef PYTHON_PATH
#error You must define the path to the python file in gcc compiler with -D 'PYTHON_PATH="'$PYTHON_DIR'"' or vlog with -ccflags "-I/usr/include/python2.6/ -D 'PYTHON_PATH=\"$PYTHON_DIR\"'"
#endif
 
 /* function declaration */
void python_sign_msg( char *key_file_name, char *msg_file_name, char *signed_file_name ) {
 
         
          char *append_path = malloc(sizeof(char) * 1000);
          append_path = PYTHON_PATH":.";
          printf("Append to path is:\n%s\n", append_path);           
          setenv("PYTHONPATH",append_path,1);//Set PYTHONPATH TO working directory https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/setenv.htm
          char *path = Py_GetPath();
          printf("Python search path is:\n%s\n", path);
          
          int argc;
          char * argv[3];
          char *phyton_script_name = "test";//don't use the .py extension here
          
          
          argc = 3;//argument count is 3 arguments
          argv[0] = phyton_script_name;//key_file_name;//"mymod";//the argument value vector is
          argv[1] = "4";
          argv[2] = "3";
          
           Py_Initialize();// Initialize the Python Interpreter
           
           //First import python script module name
           
           PySys_SetArgv(argc, argv);//set the previous arguments as calling arguments of the import module
           //PyObject* myPmodule = PyImport_ImportModule("sign_hmac-sha256");//don't put the .py extension here
           PyObject* myPmodule = PyImport_ImportModule(phyton_script_name);//IMPORTANT THE MAIN MODULE IS EXECUTED here with the PySys_SetArgv arguments
           if(myPmodule==NULL)
           {
               printf("Not able to load&execute main phyton script:\n%s\n", phyton_script_name);
               PyErr_Print();
           }
           ///////////////////////////////
           //Extract variables through dict
           //////////////////////////////
           //retrieve all variables and functions of the module in a namespace or dict
           PyObject *module_dict   = PyModule_GetDict(myPmodule);
          
           char *function_name = malloc(sizeof(char) * 100);
           function_name = "suma";//don't use the .py extension here
           //getting the reference to the specific python function you want from the python script
           PyObject* myPfunction = PyObject_GetAttrString(myPmodule, function_name);

           if (PyCallable_Check(myPfunction))
           {
               //EXAMPLE CREATE arguments in Python 
               //PyObject* myPargs=Py_BuildValue("(z)",(char*)"something");
               //PyObject* myPargs = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
               //ok = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Two longs and a string */
               //PyObject* myPargs = Py_BuildValue("sss",key_file_name,msg_file_name,signed_file_name); /* Three strings */
               //Execute the function with arguments directly
               //PyObject* result = PyObject_CallObject(myPfunction, (char*)"something", (char*)"something", (char*)"something");/* Three strings */               
               //PyObject* myPargs = Py_BuildValue("zz","4" ,"3");
               PyObject* myPargs = Py_BuildValue("ii",4 ,3);
               PyObject* item=PyTuple_GetItem(myPargs,0);//get the item of the tuple position 0 
               printf("Python tuple: %d\n", (int)PyInt_AsSsize_t(item)); /*incase an integer*/
               //printf("Python tuple: %s\n", PyString_AsString(item));
               PyErr_Print();               
               PyObject* result = PyObject_CallObject(myPfunction, myPargs);//the myPargs must be always be a Pyobject               
               
               PyErr_Print();
               Py_DECREF(myPargs);
               Py_DECREF(item);
               Py_DECREF(result);
           } else 
           {
               printf("The function:\n%s\n", function_name);
               //Pring errors comming from Python
               PyErr_Print();
           }
           
           
           ////////////////////////////////////////
           // Clean up phase
           ////////////////////////////////////////
           Py_DECREF(myPmodule);
           Py_DECREF(myPfunction);
           
           
           
           Py_Finalize();// Finish the Python Interpreter
}
 
 /* function declaration text char stream passed as pointer value and text2 passed as pointer reference */
  char * return_string_in_c( char *text,  char **text2) {
    char *fix="This variable cannot be changed although it is a pointer, just as example";/*fix allocation and constant*/
    char dest[50]="Variable array created in a function:";/* String array max 50 chars allocated*/
    char *out = malloc(sizeof(char) * 100);/* Dynamic string max 100 chars allocated*/
    /* Concatenate input text and put in out of strcat*/
    //strcat(out, text);/* initialize out using text string*/
    snprintf(out, sizeof(char) * 100, "%s%s", out,text);
    printf("fix : |%s|,dest : |%s|,text : |%s|,out : |%s|\n", fix,dest,text,out);
    *text2=dest;/* allocate pointer value with dest*/
    *text2=out;/* allocate pointer value with out*/
    return out;
}
 
 /* main */
 void main() {
    char text[100]="from_main_text_variable";/*max 100 chars allocated*/
    char *text2;/* pointer not allocated*/
    char *point = return_string_in_c(text, &text2);/* &text2 passing by reference*/
    printf("Final destination string : |%s|\n", text2);
    printf("point output : |%s|\n", point);       
    
    printf("DEFINED PYTHON_PATH: |%s|\n", PYTHON_PATH);
    python_sign_msg("","","");
    printf("Finished python\n");
    
 }

**Python脚本-TEST.py,**删除标签非常重要!!!!!!

#!/usr/bin/python
# This program adds two numbers
import sys
 
if( len( sys.argv ) < 3 ) :
    raise( Exception( "Usage: test.py number1 number2" ) )
 
num1 = int(sys.argv[ 1 ])
print "sys.argv[ 1 ] : ",int(sys.argv[ 1 ])
num2 = int(sys.argv[ 2 ])
print "sys.argv[ 2 ] : ", int(sys.argv[ 2 ])
 
#the suma function definition
def suma( arg1, arg2 ):
    # Add both the parameters and return them."
    total = arg1 + arg2; # Here total is local variable.
    print "Inside the function local total : ", total
    return total;
 
# Display the suma
print('The sum using suma function of {0} and {1} is {2}'.format(num1, num2, suma(num1,num2)))
 
#num1 = 1.5
#num2 = 6.3
# Add two numbers
sum = float(num1) + float(num2)
# Display the sum
print('The sum of {0} and {1} is {2}'.format(num1, num2, sum))
 
 
#a dummy function definition
def multiply():
   c = 12345*6789
   print 'The result of 12345 x 6789 :', c
   return c

最后,您必须使用供应商流程编译文件。例如:奎斯塔
1.你可以使用ccflags编译C代码,并引入你想要添加的定义。在我们的例子中,我们的C代码需要定义PYTHON_PATH
vlog $DUT_VLOG_ARGS ${TB_DIR}/your_C_code.c -ccflags“-I/usr/include/python2.6/ -D 'PYTHON_PATH="$PYTHON_DIR”“
1.在奎斯塔中,如果你有python,你必须调用vsim,包括**-ldflags '-lpython2.6'**类似于:
vsim -ldflags '-lpython2.6' -voptargs="+acc”-solvefaildebug -assertdebug -onfinish stop +UVM_TESTNAME=${TESTCASE_STRING} yourtop_tb_top \

新思VCS

1.你可以使用ccflags编译C代码,并引入你想要添加的定义。在我们的例子中,我们的C代码需要定义PYTHON_PATH

GCC在两个步骤中共享对象gcc -g -D 'PYTHON_PATH=“'$PYTHON_DIR'"' -fPIC -Wall -I${VCS_HOME}/include -I/usr/include/python2.6/ -lpython2.6 -c ${PROJECTDIR}/verification/PVE/keycontrol/tb/keycontrol_C_code_wrapper.c gcc -fPIC -shared -o keycontrol_C_code_wrapper. so keycontrol_C_code_wrapper.o

1.使用**-LDFLAGS '-lpython2.6'链接python库进行VCS细化
vcs -timescale=1ps/1ps -ntb_opts uvm -lca -kdb -full64 keycontrol_tb_top -debug_access+all+reverse -LDFLAGS '-lpython2.6'
1.运行创建的仿真文件。调用
simvincluding-sv_lib keycontrol_C_code_wrapper**导入C共享对象。

运行C代码。/simv -gui -ucli +DVE +UVM_NO_RELNOTES -l simv.log +UVM_TESTNAME=keycontrol_basic_test -do ../../verification/PVE/keycontrol/tools/keycontrol_ucli_init.synopsys -sv_lib keycontrol_C_code_wrapper

另一个工具会有另一个流程。
在python脚本中嵌入python是一种比FILE IO更有效的解决方案。
如果你的python脚本从文件中读取输入和输出,那么从Systemverilog调用python最简单的方法就是执行系统调用

$system("python yourscript.py filenamein filenameout ")

当然,您必须在systemverilog中写入输入文件,并在systemverilog中读取输出文件以进行比较。

14ifxucb

14ifxucb2#

如何去模拟器的交互式命令行终端。这不是一个典型的shell终端,比如unix。这是一个供应商指定的互动模式捆绑到模拟器。在大多数情况下,它由Verilog的$stop触发。它是特定于供应商的,所以你需要参考你的手册来了解所有的功能,有些功能允许调用Verilog/SystemVerilog中定义的任务和函数。
听起来也不需要在一个模拟中运行所有条件。在您的情况下,一次编译多次运行策略应该是可行的。SystemVerilog系统函数$test$plusargs$value$plusargs可以检测用于启动仿真的参数。参见IEEE Std 1800-2012 § 21.6 * 命令行输入 *

// ...
int testid;
// ...
initial begin
  // ...
  if(!$value$pluseargs("TESTID=%d",testid)) begin
    // code if +TESTID= is not an argument
  end
  case(testid)
  0 : run_task_test0(/*...*/);
  1 : run_task_test1(/*...*/);
  2 : run_task_test2(/*...*/);
  3 : run_task_test3(/*...*/);
  // ...
  endcase
  // ...
end

然后编译一次,并根据需要多次启动模拟。

% [compile-cmd]
% [sim-cmd] +TESTID=0
% [sim-cmd] +TESTID=3
% [sim-cmd] +TESTID=1
% [sim-cmd] +TESTID=2
hlswsv35

hlswsv353#

最好的办法是使用DPI和某种脚本语言进行测试。例如,我看到这个工作很好:Python -> Boost.Python -> C++ -> DPI -> Verilog/SystemVerilog
它确实限制了你在测试中可以做的事情(将它作为两种语言之间的TLM接口,即只在它们之间来回传递事务),但实际上这通常会迫使你使用良好的抽象实践。阅读Python中的“yield”,了解如何在Python和模拟器之间来回传递控制。

相关问题