Problem Description:
I design in SystemVerilog and write the testbenches in the same language. I want to be able to compile my design and test different functions during simulation in the way you would using an interpreter with e. Ideally, I would have a terminal pop-up upon simulation when the simulator hit some line.
Potential Ideas:
I've looked at the DPI-C and it seems like I would have to "export" all tasks in my project in order to run them from the interpreter. However, I'm not sure how to do this automatically or if there's a better way. Furthermore, I have no idea how I would get C to open up a second shell for me to type the SystemVerilog tasks in (that I would want to run).
This is a problem echoes by my colleagues and it would make life a lot less painful to not have to wait 10 minutes between compiling just a testbench.
Hi i provide my two cents with another example.
EXAMPLE 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[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, very important to remove TABS!!!!!!
#!/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
Lastly, you have to compile the files using your vendor flow. For example, Questa 1) You compile the C code using ccflags and introducing the defines you want to add. In our case our C code need the define PYTHON_PATH
vlog $DUT_VLOG_ARGS ${TB_DIR}/your_C_code.c -ccflags "-I/usr/include/python2.6/ -D 'PYTHON_PATH=\"$PYTHON_DIR\"'"
2) In Questa if you have python you have to call vsim including -ldflags '-lpython2.6' Something like:
vsim -ldflags '-lpython2.6' -voptargs="+acc" -solvefaildebug -assertdebug -onfinish stop +UVM_TESTNAME=${TESTCASE_STRING} yourtop_tb_top \
Synopsys VCS 1) You compile the C code using ccflags and introducing the defines you want to add. In our case our C code need the define 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) You do the VCS elaboration linking the python lybrary with -LDFLAGS '-lpython2.6'
vcs -timescale=1ps/1ps -ntb_opts uvm -lca -kdb -full64 keycontrol_tb_top -debug_access+all+reverse -LDFLAGS '-lpython2.6'
3) You run the created simulation file. You call simv including -sv_lib keycontrol_C_code_wrapper to import the C shared object.
#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
Another tools would have another flow.
Embedding python is a solution that is [b]more efficient[/b] than FILE IO in your python script.
If your python script reads inputs and outputs from files, then the easiest way to call python from Systemverilog is just by doing a system call.
$system("python yourscript.py filenamein filenameout ")
You have of course to write in systemverilog your input file and read in systemverilog the output file for comparison.
How about going to the simulator's interactive command line terminal. This is not a typical shell terminal such as from unix. It is an vendor specif interactive mode tied into the simulator. In most cases it is triggered with Verilog's $stop
. It is vendor specific so you will need to refer to your manual for all the features, some do allow calling tasks and functions defined in Verilog/SystemVerilog.
It also sounds like you do not need to run all your conditions in one simulation. A compile once and run many strategy should work in your situation. The SystemVerilog system-functions $test$plusargs
and $value$plusargs
can detect the arguments used to start your simulation. See IEEE Std 1800-2012 § 21.6 Command line input
// ...
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
Then compile once and start the simulation as many times as needed.
% [compile-cmd]
% [sim-cmd] +TESTID=0
% [sim-cmd] +TESTID=3
% [sim-cmd] +TESTID=1
% [sim-cmd] +TESTID=2
Best bet is likely using DPI with some kind of scripting language for your tests. For example I have seen this work well: Python -> Boost.Python -> C++ -> DPI -> Verilog/SystemVerilog
It does limit what you can do in your test (approach it as a TLM interface between the two language, ie only pass transactions back and forth between them), but actually that usually forces you to use good abstraction practices anyway. Read up on "yield" in Python to understand how you pass control back and forth between the python and the simulator.
来源:https://stackoverflow.com/questions/29781428/how-to-embed-systemverilog-interpreter-using-dpi-c