EDA365电子论坛网
标题:
了解一下DPI吧(续)
[打印本页]
作者:
haidaowang
时间:
2020-7-23 14:45
标题:
了解一下DPI吧(续)
3 |7 o! @( b7 Q8 c" Y: e
引言
' P# w* e; E. ^& F
2 { _& ]+ u- R. z; T
对于SV,无论是构造测试激励,还是模拟硬件的并行行为,DPI都是非常方便的。上次我们介绍了SV里面通过“import”导入并调用C函数。
) N- T" M: f. @0 \: M- E8 u9 s' P5 v/ S
" h* B9 w$ T6 \" L/ W# U6 ]
本小节,我们通过一个简单的例子来说明C语言函数如何调用SV的task和function。
2 V2 P) t2 h! o3 ^* i
4 O* Z: u9 Q: V
, R6 U6 q) Z6 S) p. X. j+ z
1,SV部分
+ c. W8 d! {* t
& n/ o. S3 ?( Z" N8 l: ?5 P% x
# i5 O# S* S" t0 b) t4 e" w
/*
* test.v Rill create for dpi test at 2014-10-20
*/
! l5 l3 s$ p6 ?2 j: D# s# V
`timescale 1ns/1ns
/ z: R6 S' s: g6 M e# t) [
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
@! X& n: c. T5 | r% x
m1 M1();
m2 M2();
endmodule // top
3 y# A2 t& Z$ u J5 M0 |$ e
module m1;
import "DPI-C" context function void c_get_m1_scope();
export "DPI" function m1_add;
/ R/ n0 q9 Z1 Q
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
) B0 m! F! f/ \0 d0 O8 `
initial begin
c_get_m1_scope();
m1_value = 8'd100;
end
endmodule // m1
6 ^9 ~& ]1 c! Z( Z$ f+ K
; r+ P! L1 v5 X& @. a
module m2;
import "DPI-C" context function void c_get_m2_scope();
export "DPI-C" task m2_add;
5 q1 o" H! n! ?, u
reg tmp;
reg [31:0] m2_value;
task m2_add(input int num,output int sum);
sum = num + m2_value;
endtask // m2_add
, G/ P+ D. p, G1 D+ V& j
initial begin
c_get_m2_scope();
m2_value = 32'd200;
end
+ [1 W* x5 W( U! T! N
endmodule // m1
. n8 p" d: r l
0 U1 ^3 f) M6 B9 M g* ^" i
: c& d7 f$ e+ i) e7 y
2,C部分
6 q5 I: Z3 R& y% j
) D6 |' T3 T/ M, a- @3 N
9 o# u" t/ C1 T# X6 H
/*
* test.c Rill create for dpi test at 2014-10-20
*/
3 \9 }- h- D9 C
#include <stdio.h>
#include <svdpi.h>
3 W; Z7 D( Z; q X; l( u
svScope tmp_scope;
svScope m1_scope;
svScope m2_scope;
' L: I3 t; ^$ W# E2 u; _
//import task/funcs from sv
extern int m1_add();
extern int m2_add();
% t9 |% s& H7 j$ s2 i, N) V v" C) ]
//==scope switch
void c_get_tmp_scope(void)
{
tmp_scope = svGetScope();
}
. ?8 D9 r0 f( `
void c_set_tmp_scope(void)
{
svSetScope(tmp_scope);
}
+ H& _1 v: R' u* W, D
void c_get_m1_scope(void)
{
m1_scope = svGetScope();
}
' `+ V& `/ ^; ^9 L+ L: D! [, x
void c_set_m1_scope(void)
{
svSetScope(m1_scope);
}
1 b; j2 t% }: O6 C) @1 d. y
void c_get_m2_scope(void)
{
m2_scope = svGetScope();
}
+ x* Y# H; e6 ~! F3 i( n! z
void c_set_m2_scope(void)
{
svSetScope(m2_scope);
}
& r: c. ^) N, z! H
//==export c funcs to sv
int c_func(int num)
{
int m1 = 0;
int m2 = 0;
+ b# p8 m- d4 N$ @* \: {: V! r
c_get_tmp_scope();
c_set_m1_scope();
m1 = m1_add(num);
c_set_tmp_scope();
printf("m1:%d\n",m1);
2 A9 i- d4 n$ p( _
c_get_tmp_scope();
c_set_m2_scope();
m2_add(num,&m2);
c_set_tmp_scope();
printf("m2:%d\n",m2);
! c9 Q% H, |3 J0 f5 B* c/ l( E
return 0;
}
' V- O1 E) u: j+ V+ m2 m6 ?
+ J% E/ V+ c7 v2 X n
2 F0 o% s5 p9 }8 U
3,脚本
6 k" d1 o$ L# ~: K6 U0 {6 z
Z" b. E$ C2 k$ E2 W( V
; c- Y) t* S3 @3 |, D+ H& D& b* v
#! /bin/bash
! b& X+ p t. R5 V+ c6 _# F0 X
#
# test.sh
# usage: ./test.sh c/w/r
# Rill create 2014-10-20
#
- q+ }5 z8 {. D' S2 q( y* T
, {! G# O: {& h# g& j3 r& m) W0 x
TOP_MODULE=tb
9 v) C1 k, w! L. O& [
tcl_file=run.tcl
n/ u$ N$ G0 c) k- Z3 b# ?1 I
CDS_INST_DIR=/home/openrisc/opt/edatools/IUS08.20
) b. C6 x8 t) l7 E9 f# o
- U4 B# e% z# Q) H' D8 v7 G
if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi
$ E2 `) i' U. H$ A6 g
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}
6 F, b/ Z0 E: A8 `& j
echo "compile dpi lib"
if [ -e libdpi.so ];then
rm libdpi.so -f
fi
) G; B# c4 j- y- N9 n' F6 y1 l
gcc -fPIC -shared -o libdpi.so test.c -I$CDS_INST_DIR/tools/inca/include
exit 0
fi
5 B: n/ l. L$ X# }; O+ a( Y
5 T8 G& V0 ~( a5 H0 h2 K
if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}
/ j `% d4 H1 g% B: [$ z- z! X& v8 m4 W
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
# z, R' L W1 d0 d o
if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fi
& R* z9 y7 w" `( m
echo "$(date) sim done!"
, C% D# Y/ r4 E M" H/ P0 C! W1 U* }
: `/ F+ s B- Y8 ]& ?' j# Z# {, ^
) O' w$ s. @5 ?: i- r% h
4,说明
9 \/ ?- [2 D% m1 q" h) i) Q6 e
仔细体会我们上面构造的例子,有几个问题需要弄清楚。
. }/ L. `. f! O1 u4 Y8 k
- g, x9 b7 J7 d. s0 F
a,scope的含义:
, d' {, I- \: ?+ z) T; j& {* |+ q
* T. O- R8 ]7 s( ]! Z' Q* ?3 \
在SV端,m1是不能直接调用m2中的task/function的,所以m1里面调用的C函数也不能直接调用m2中export出来的task/function,如果想调用,必须进行scope切换。
/ \) \; S1 j# N" [) h
% r! b* _8 j6 _& g' g: t1 E
b,SV端,有task和function的区分,但是在C端,并没有区分,一律是C函数。
( ?/ ~5 G% i% J+ Y( o" j" f
# K% D; Y5 X$ ^0 F
& B3 X5 N& H! ~' x. V
5,关于用C模拟硬件的并行行为
1 G8 V- y' A$ i5 H( A, v
. ~3 l7 b" D% M8 Y; d9 b
方式a,将流水后面的模块写在前面。
5 i7 k ^& o; k3 L/ s9 A" Z; Z
7 g5 h* J4 k4 B2 N' P
方式b,将所有并行的信号写成如下形式:
+ K {2 \2 u! a4 C
9 o4 X- N1 y% ~3 W" A
用c,n两个变量模拟reg的值。
3 e& C6 q* A K$ p# x
' T& m, u& ? h
用init和update两个函数模拟reg的行为。
3 O1 v1 J7 D+ r" t) d$ n6 w& n
: D o- ^4 b' y- K2 a! z
/*
* parallel.c Rill create for simulater test at 2014-10-20
*/
3 u5 t- N# R4 a. W: }) G
$ E `& h4 I/ p; d5 K- G- V
struct signal;
. x1 o( `' @( P5 h$ s
struct sig_ops
{
int (*init) (struct signal*);
int (*update) (struct signal*);
};
) L# C+ z- h4 U1 ? O/ s1 U2 ?
struct signal
{
unsigned int c; //current cycle value
unsigned int n; //next cycle value
char name[32];
struct sig_ops* ops;
};
/ P4 o& W' D" e5 }5 M- c M: M4 k% r
/* veritual functions
int sig_init(struct signal* signal)
{
return signal->ops->init(signal);
}
5 m6 L5 Z" C @: u
int sig_update(struct signal* signal)
{
return signal->ops->update(signal);
}
*/
. w" U4 B6 P! O7 X0 X
//actual functions
int test_init(struct signal* signal)
{
signal->c = 0;
signal->n = 0;
return 0;
}
8 c: a2 n( Y5 ^/ r5 v6 J
int test_update(struct signal* signal)
{
signal->c = signal->n;
return 0;
}
4 a) `5 K \6 |
* Q& L: \0 L- E
; h0 V) @4 Q& w
int signal_create(struct signal* signal,char * name)
{
signal->name = name;
}
& f* l& c8 M; z' n9 V7 S8 @
//============main.c====================//
//example signal
struct signal test;
struct sig_ops test_ops =
{
test_init,
test_update,
};
+ }. s" A# |' x# @
int main()
{
signal_create(&test,"test");
//when reset
test->ops->init(&test);
//per cycle
test->ops->update(&test);
return 0;
}
# c$ b2 j& c4 y* z
! Y6 J5 k+ H/ x" V4 [( V
- j, @9 S o1 l5 z1 S
& K0 R6 M: Q' |+ h
/ E `- I8 t3 v8 m, E5 a
+ U: V6 ^& x9 k$ C
% s1 b/ _. y0 ]: B6 {6 I. T
4 C/ L* }7 m$ x
! g c" e( f9 F4 \7 p* u
作者:
xiaogegepcb
时间:
2020-7-23 15:42
DPI(续)
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2