ディジタル集積回路設計-15-DPI(続き)
5098 ワード
引用する
SVの場合、DPIは、テスト励起を構築しても、ハードウェアの並列動作をシミュレートしても、非常に便利である.前回はSVで「import」でC関数をインポートして呼び出すことを紹介しました.
このセクションでは、C言語関数がSVのtaskとfunctionをどのように呼び出すかを簡単な例で説明します.
1,SV部 /*
* test.v Rill create for dpi test at 2014-10-20
*/
`timescale 1ns/1ns
module 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 // top
module 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 // m1
module 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;
end
endmodule // m1
2,C部 /*
* test.c Rill create for dpi test at 2014-10-20
*/
#include <stdio.h>
#include <svdpi.h>
svScope tmp_scope;
svScope m1_scope;
svScope m2_scope;
//import task/funcs from sv
extern int m1_add();
extern int m2_add();
//==scope switch
void 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 sv
int 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
",m1);
c_get_tmp_scope();
c_set_m2_scope();
m2_add(num,&m2);
c_set_tmp_scope();
printf("m2:%d
",m2);
return 0;
}
3、スクリプト #! /bin/bash
#
# test.sh
# usage: ./test.sh c/w/r
# Rill create 2014-10-20
#
TOP_MODULE=tb
tcl_file=run.tcl
CDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20
if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi
if [ $1 == "c" ]; then
echo "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 ];then
rm libdpi.so -f
fi
gcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/include
exit 0
fi
if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}
if [ $1 == "w" ];then
echo "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}
fi
if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fi
echo "$(date) sim done!"
4、説明
私たちの上の構造の例をよく理解するには、いくつかの問題を明らかにする必要があります.
a,scopeの意味:
SV側ではm 1はm 2のtask/functionを直接呼び出すことはできないので、m 1で呼び出されたC関数もm 2のexportから出てくるtask/functionを直接呼び出すことはできません.呼び出すにはscope切り替えが必要です.
b,SV端はtaskとfunctionの区別があるが,C端では区別がなく,一律にC関数である.
5,Cでハードウェアの並列動作をシミュレートすることについて
方式aは、流水の後ろのモジュールを前に書きます.この方法は前に紹介したように(http://blog.csdn.net/rill_zhen/article/details/8464930)、ここではこれ以上述べない.
方式bは、すべての並列信号を以下の形式に書く.
regの値をc,nの2つの変数でシミュレートした.
regの挙動をinitとupdateの2つの関数でシミュレートした./*
* 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 value
unsigned int n; //next cycle value
char name[32];
struct sig_ops* ops;
};
/* veritual functions
int sig_init(struct signal* signal)
{
return signal->ops->init(signal);
}
int sig_update(struct signal* signal)
{
return signal->ops->update(signal);
}
*/
//actual functions
int 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 signal
struct signal test;
struct sig_ops test_ops =
{
test_init,
test_update,
};
int main()
{
signal_create(&test,"test");
//when reset
test->ops->init(&test);
//per cycle
test->ops->update(&test);
return 0;
}
/*
* test.v Rill create for dpi test at 2014-10-20
*/
`timescale 1ns/1ns
module 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 // top
module 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 // m1
module 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;
end
endmodule // m1
2,C部 /*
* test.c Rill create for dpi test at 2014-10-20
*/
#include <stdio.h>
#include <svdpi.h>
svScope tmp_scope;
svScope m1_scope;
svScope m2_scope;
//import task/funcs from sv
extern int m1_add();
extern int m2_add();
//==scope switch
void 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 sv
int 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
",m1);
c_get_tmp_scope();
c_set_m2_scope();
m2_add(num,&m2);
c_set_tmp_scope();
printf("m2:%d
",m2);
return 0;
}
3、スクリプト #! /bin/bash
#
# test.sh
# usage: ./test.sh c/w/r
# Rill create 2014-10-20
#
TOP_MODULE=tb
tcl_file=run.tcl
CDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20
if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi
if [ $1 == "c" ]; then
echo "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 ];then
rm libdpi.so -f
fi
gcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/include
exit 0
fi
if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}
if [ $1 == "w" ];then
echo "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}
fi
if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fi
echo "$(date) sim done!"
4、説明
私たちの上の構造の例をよく理解するには、いくつかの問題を明らかにする必要があります.
a,scopeの意味:
SV側ではm 1はm 2のtask/functionを直接呼び出すことはできないので、m 1で呼び出されたC関数もm 2のexportから出てくるtask/functionを直接呼び出すことはできません.呼び出すにはscope切り替えが必要です.
b,SV端はtaskとfunctionの区別があるが,C端では区別がなく,一律にC関数である.
5,Cでハードウェアの並列動作をシミュレートすることについて
方式aは、流水の後ろのモジュールを前に書きます.この方法は前に紹介したように(http://blog.csdn.net/rill_zhen/article/details/8464930)、ここではこれ以上述べない.
方式bは、すべての並列信号を以下の形式に書く.
regの値をc,nの2つの変数でシミュレートした.
regの挙動をinitとupdateの2つの関数でシミュレートした./*
* 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 value
unsigned int n; //next cycle value
char name[32];
struct sig_ops* ops;
};
/* veritual functions
int sig_init(struct signal* signal)
{
return signal->ops->init(signal);
}
int sig_update(struct signal* signal)
{
return signal->ops->update(signal);
}
*/
//actual functions
int 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 signal
struct signal test;
struct sig_ops test_ops =
{
test_init,
test_update,
};
int main()
{
signal_create(&test,"test");
//when reset
test->ops->init(&test);
//per cycle
test->ops->update(&test);
return 0;
}
/*
* test.c Rill create for dpi test at 2014-10-20
*/
#include <stdio.h>
#include <svdpi.h>
svScope tmp_scope;
svScope m1_scope;
svScope m2_scope;
//import task/funcs from sv
extern int m1_add();
extern int m2_add();
//==scope switch
void 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 sv
int 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
",m1);
c_get_tmp_scope();
c_set_m2_scope();
m2_add(num,&m2);
c_set_tmp_scope();
printf("m2:%d
",m2);
return 0;
}
#! /bin/bash
#
# test.sh
# usage: ./test.sh c/w/r
# Rill create 2014-10-20
#
TOP_MODULE=tb
tcl_file=run.tcl
CDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20
if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi
if [ $1 == "c" ]; then
echo "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 ];then
rm libdpi.so -f
fi
gcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/include
exit 0
fi
if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}
if [ $1 == "w" ];then
echo "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}
fi
if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fi
echo "$(date) sim done!"
4、説明
私たちの上の構造の例をよく理解するには、いくつかの問題を明らかにする必要があります.
a,scopeの意味:
SV側ではm 1はm 2のtask/functionを直接呼び出すことはできないので、m 1で呼び出されたC関数もm 2のexportから出てくるtask/functionを直接呼び出すことはできません.呼び出すにはscope切り替えが必要です.
b,SV端はtaskとfunctionの区別があるが,C端では区別がなく,一律にC関数である.
5,Cでハードウェアの並列動作をシミュレートすることについて
方式aは、流水の後ろのモジュールを前に書きます.この方法は前に紹介したように(http://blog.csdn.net/rill_zhen/article/details/8464930)、ここではこれ以上述べない.
方式bは、すべての並列信号を以下の形式に書く.
regの値をc,nの2つの変数でシミュレートした.
regの挙動をinitとupdateの2つの関数でシミュレートした./*
* 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 value
unsigned int n; //next cycle value
char name[32];
struct sig_ops* ops;
};
/* veritual functions
int sig_init(struct signal* signal)
{
return signal->ops->init(signal);
}
int sig_update(struct signal* signal)
{
return signal->ops->update(signal);
}
*/
//actual functions
int 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 signal
struct signal test;
struct sig_ops test_ops =
{
test_init,
test_update,
};
int main()
{
signal_create(&test,"test");
//when reset
test->ops->init(&test);
//per cycle
test->ops->update(&test);
return 0;
}
方式aは、流水の後ろのモジュールを前に書きます.この方法は前に紹介したように(http://blog.csdn.net/rill_zhen/article/details/8464930)、ここではこれ以上述べない.
方式bは、すべての並列信号を以下の形式に書く.
regの値をc,nの2つの変数でシミュレートした.
regの挙動をinitとupdateの2つの関数でシミュレートした.
/*
* 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 value
unsigned int n; //next cycle value
char name[32];
struct sig_ops* ops;
};
/* veritual functions
int sig_init(struct signal* signal)
{
return signal->ops->init(signal);
}
int sig_update(struct signal* signal)
{
return signal->ops->update(signal);
}
*/
//actual functions
int 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 signal
struct signal test;
struct sig_ops test_ops =
{
test_init,
test_update,
};
int main()
{
signal_create(&test,"test");
//when reset
test->ops->init(&test);
//per cycle
test->ops->update(&test);
return 0;
}