Digital Integrated Circuit Design-15-DPI (continued)
Introduction
For SV, both constructing test incentives and simulating parallel behavior of hardware, DPI is very convenient. The last time we introduced how to import and call the C function through "import" in SV.
In this section, we use a simple example to illustrate how C functions call SV tasks and functions.
1. SV part
/** test.v Rill create for dpi test at 2014-10-20*/`timescale 1ns/1nsmodule tb; import "DPI-C" context function int c_func(input int num);// or import "DPI-C" context task c_display(input int num); reg tmp; initial begin #10 tmp = c_func(1); end m1 M1(); m2 M2(); endmodule // topmodule m1; import "DPI-C" context function void c_get_m1_scope(); export "DPI" function m1_add; reg tmp; reg [7:0] m1_value; function int m1_add(input [7:0] num); m1_add = num + m1_value; //or return (num + m1_value); endfunction // m1_add initial begin c_get_m1_scope(); m1_value = 8'd100; end endmodule // m1module m2; import "DPI-C" context function void c_get_m2_scope(); export "DPI-C" task m2_add; reg tmp; reg [31:0] m2_value; task m2_add(input int num,output int sum); sum = num + m2_value; endtask // m2_add initial begin c_get_m2_scope(); m2_value = 32'd200; endendmodule // m1
2, Part C
/** test.c Rill create for dpi test at 2014-10-20*/#include
#include
svScope tmp_scope;svScope m1_scope;svScope m2_scope;//import task/funcs from svextern int m1_add();extern int m2_add();//==scope switchvoid c_get_tmp_scope(void){ tmp_scope = svGetScope();}void c_set_tmp_scope(void){ svSetScope(tmp_scope);}void c_get_m1_scope(void){ m1_scope = svGetScope();}void c_set_m1_scope(void){ svSetScope(m1_scope);}void c_get_m2_scope(void){ m2_scope = svGetScope();}void c_set_m2_scope(void){ svSetScope(m2_scope);}//==export c funcs to svint c_func(int num){ int m1 = 0; int m2 = 0; c_get_tmp_scope(); c_set_m1_scope(); m1 = m1_add(num); c_set_tmp_scope(); printf("m1:%d\n",m1); c_get_tmp_scope(); c_set_m2_scope(); m2_add(num,&m2); c_set_tmp_scope(); printf("m2:%d\n",m2); return 0; }
3. Script
#! /bin/bash## test.sh# usage: ./test.sh c/w/r# Rill create 2014-10-20#TOP_MODULE=tbtcl_file=run.tclCDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20if [ $# != 1 ];thenecho "args must be c/w/r"exit 0fiif [ $1 == "c" ]; thenecho "compile rtl lib..."ncvlog -f ./vflist -sv -update -LINEDEBUG;ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE}echo "compile dpi lib"if [ -e libdpi.so ];thenrm libdpi.so -ffigcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/includeexit 0fiif [ -e ${tcl_file} ];thenrm ${tcl_file} -ffitouch ${tcl_file}if [ $1 == "w" ];thenecho "open wave..."echo "database -open waves -into waves.shm -default;" >> ${tcl_file}echo "probe -shm -variable -all -depth all;" >> ${tcl_file}echo "run" >> ${tcl_file}echo "exit" >> ${tcl_file}fiif [ $1 == "w" -o $1 == "r" ];thenecho "sim start..."ncsim ${TOP_MODULE} -input ${tcl_file}fiecho "$(date) sim done!"
4. Description
After carefully understanding the examples we have constructed above, several questions need to be clarified.
A, scope meaning:
At the SV end, m1 cannot directly call the task/function in m2, so the C function called in m1 cannot directly call the task/function export in m2, scope switching is required.
The B and SV ends are differentiated by tasks and functions, but they are not differentiated in the C end. All functions are C functions.
5. Use C to simulate parallel hardware Behavior
Method a: Write the module behind the flow in front. This method we have introduced before (http://blog.csdn.net/rill_zhen/article/details/8464930), and I will not repeat it here.
Method B: Write all parallel signals as follows:
Use the c and n variables to simulate the reg value.
Use the init and update functions to simulate reg behavior.
/** parallel.c Rill create for simulater test at 2014-10-20*/struct signal;struct sig_ops{int (*init) (struct signal*);int (*update) (struct signal*);};struct signal{unsigned int c; //current cycle valueunsigned int n; //next cycle valuechar name[32];struct sig_ops* ops;};/* veritual functionsint sig_init(struct signal* signal){return signal->ops->init(signal);}int sig_update(struct signal* signal){return signal->ops->update(signal);}*///actual functionsint test_init(struct signal* signal){signal->c = 0;signal->n = 0;return 0;}int test_update(struct signal* signal){signal->c = signal->n;return 0;}int signal_create(struct signal* signal,char * name){signal->name = name;}//============main.c====================////example signalstruct signal test;struct sig_ops test_ops ={test_init,test_update,};int main(){signal_create(&test,"test");//when resettest->ops->init(&test);//per cycletest->ops->update(&test);return 0;}