Как встроить интерпретатор Systemverilog с помощью DPI-C?
Описание проблемы:
Я проектирую в SystemVerilog и пишу испытательные стенды на одном языке. Я хочу иметь возможность компилировать мой дизайн и тестировать различные функции во время симуляции так же, как если бы вы использовали интерпретатор с e. В идеале, я должен иметь всплывающее окно терминала при симуляции, когда симулятор достигнет какой-то линии.
Потенциальные идеи:
Я посмотрел на DPI-C, и мне кажется, что мне нужно "экспортировать" все задачи в моем проекте, чтобы запустить их из интерпретатора. Однако я не уверен, как это сделать автоматически или есть ли лучший способ. Кроме того, я понятия не имею, как заставить C открыть вторую оболочку для ввода задач SystemVerilog (которые я хотел бы запустить).
Это проблема, которую повторяют мои коллеги, и это сделало бы жизнь намного менее болезненной, если бы не пришлось ждать 10 минут между компиляцией только тестового стенда.
3 ответа
Привет, я приведу свои два цента с другим примером.
ПРИМЕР СВ-КОДА
////////////////////////////////////////////////////////////////////////
//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
С-КОД
//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[2];
char *phyton_script_name = malloc(sizeof(char) * 100);
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 SCRIPT - 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
Наконец, вы должны скомпилировать файлы, используя поток вашего поставщика. Например, Questa 1) Вы компилируете код C, используя ccflags и вводя определения, которые хотите добавить. В нашем случае нашему C-коду нужно определить PYTHON_PATH
vlog $DUT_VLOG_ARGS ${TB_DIR}/your_C_code.c -ccflags "-I/usr/include/python2.6/ -D 'PYTHON_PATH=\"$PYTHON_DIR\"'"
2) В Questa, если у вас есть python, вы должны вызывать vsim, включая -ldflags '-lpython2.6' Что - то вроде:
vsim -ldflags '-lpython2.6' -voptargs="+acc" -solvefaildebug -assertdebug -onfinish stop +UVM_TESTNAME=${TESTCASE_STRING} yourtop_tb_top \
Synopsys VCS 1) Вы компилируете код C, используя ccflags и вводя определения, которые хотите добавить. В нашем случае нашему C-коду нужно определить PYTHON_PATH
#GCC in two steps for shared object
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
2) Вы выполняете разработку VCS, связывающую библиотеку python с -LDFLAGS '-lpython2.6'
vcs -timescale=1ps/1ps -ntb_opts uvm -lca -kdb -full64 keycontrol_tb_top -debug_access+all+reverse -LDFLAGS '-lpython2.6'
3) Вы запускаете созданный файл симуляции. Вы вызываете simv, включая -sv_lib keycontrol_C_code_wrapper, чтобы импортировать общий объект C.
#RUN C CODE
./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 - это решение, которое [b] более эффективно [/b], чем FILE IO в вашем скрипте python.
Если ваш скрипт Python читает входные и выходные данные из файлов, то самый простой способ вызвать Python из Systemverilog - это просто выполнить системный вызов.
$system("python yourscript.py filenamein filenameout ")
Вы, конечно, должны написать в systemverilog ваш входной файл и прочитать в systemverilog выходной файл для сравнения.
Как насчет того, чтобы пойти в интерактивный терминал командной строки симулятора? Это не типичный терминал оболочки, такой как из unix. Это интерактивный режим, указанный поставщиком, связанный с симулятором. В большинстве случаев это вызвано Verilog's $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
Лучшая ставка, вероятно, использует DPI с каким-то языком сценариев для ваших тестов. Например, я видел эту работу хорошо: Python -> Boost.Python -> C++ -> DPI -> Verilog/SystemVerilog
Это ограничивает то, что вы можете делать в своем тесте (подходите к нему как к интерфейсу TLM между двумя языками, то есть только для передачи транзакций между ними), но на самом деле это обычно вынуждает вас в любом случае использовать хорошие методы абстракции. Прочтите раздел "yield" в Python, чтобы понять, как вы передаете контроль между питоном и симулятором.