EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 Zedd 于 2019-4-17 09:26 编辑
1 a* U4 F* b, v/ a) ]3 q# {1 x; e; [( _/ O
转——玩转FPGA之:Testbench学习 TestBench基本概念:
+ E3 Y0 Z* n& Z% `' [: [( E# v" q7 b测试激励->待测设计->观察比对波形/在终端打印或生产文本/自动对比输出结果 TestBench编写三步曲
+ o( c: P5 x: {- y4 D: I1:对被测试设计的顶层接口进行例化
5 |+ z7 h6 i& U! Q& ?2:给被测试设计的输入接口添加激励! i+ x1 J4 Z3 x# J2 P; o7 L; Y: {
3:判断被测试设计的输出想要是否满足设计要求 TestBench内容主要分为
- H! y3 h7 Z: N4 P: N0 u" P1:时钟的产生
* H9 d4 K) @# K2:复位的产生5 q$ k& k2 k+ z( S
3:其他激励信号的产生(用户自定义 ) 第一种时钟产生方式
" C' C9 l' b. q r/ Y( _//时钟产生
6 @$ |, N) n: y7 y" k( i3 i- Q6 [! i//定义时钟周期为20ns,已经定义'timescale 1ns/1ps 单位/精度" ~, N! U) V7 k$ R) e0 x3 t
parameter PERIOD = 20;
% c- F M$ j7 J; N9 H; [0 K0 ginitial 2 J5 ]1 A0 Q3 G6 J8 X+ U
begin
0 `: x0 @9 F8 H w1 n clk = 0;
2 }7 F6 D& J9 m$ N- s$ O forever
5 Z) p3 `7 j8 K+ c' S' t. O #(PERIOD/2) clk = ~clk;
F5 P( |3 A5 u4 {$ J5 B end parameter是参数的意思类似于#define
4 F) X( k4 A. k. a: o# d+ b) H5 Y( ?; c$ binitial是初始化
: w3 a. C5 W* A9 N( Pbegin end类似于括号的作用
& T2 }! y g* Uclk =0 ;初始化时钟为低电平& A/ I. `- S5 ] `9 H3 C
forever是程序一直执行的意思4 `5 P1 p z8 v) T! |
#10 表示每间隔10ns执行一次clk=~clk;clk取反一次 第二种时钟产生方式
0 k, b8 o' I i/ U f& F7 I& |+ Y//时钟产生) x. _% P( [: X1 Q" ]' \! ^
//定义时钟周期为20ns,已经定义'timescale 1ns/1ps 单位/精度4 o9 J( j, A! N6 V: @3 @
parameter PERIOD = 20;
8 ?6 H8 ]5 N& V) falways 2 E6 C5 S: l) l
begin * a4 E: J2 b! `1 W s5 G& Q
#(PERIOD/2) clk = 0;% E6 K) `" H3 p
#(PERIOD/2) clk = 1;
# h; W5 K" I# o4 S9 X) m end
9 S2 D, p' o) S# V8 q: Salways是从第一条语句执行到最后一条语句,再从第一条语句执行 ! ]7 z. L. j2 a/ I7 q
复位信号的产生7 M. [8 Z7 S2 U
//复位产生 initial + P0 i5 K/ Q" S
begin
, s* n* Q/ V- C' e8 Y //复位低电平有效 已经定义了'timescale 1ns/1ps4 X' l, T) b2 c* X* u4 y+ D
rst_n = 0;//复位状态4 O) m4 G$ D! z
#100;//100ns延时
/ `1 Q: q6 _5 ~$ W4 Q rst_n = 1; //撤销复位
6 _9 }/ W( p0 v* j$ c6 d) k0 J. _ end, y" z, {6 L/ L5 p# r& `3 \
% S1 Y! k3 H3 e. ]' d' g1 n `" x
//例子:
. P' A' R! ]# K' J9 ]! v( v( Tinitial + G4 B3 @5 l* R0 S) l( ~
begin
2 C# _$ I. @2 g reset_task(100);//复位100ns,已经定义了'timescale 1ns/1ps
i b) M! d: _2 O end
+ m* X- r6 ?( n1 }2 d//任务的写法, \" j4 f* t/ Y0 {
task reset_task;
' Y+ f' p. a2 L4 g1 ~( _2 W' hinput[15:0] reset_time;//复位事件% @/ g4 K) z$ _5 z; K* u. S2 p
begin1 k5 j$ |% R) ? ^4 G
reset=0;
5 U7 ?+ o3 M2 U. I/ ~$ R, m. x #reset_time;
: o' k! }: r, z reset=1;
- v' P5 Z6 X$ Y* ?, B' f! pend
$ K4 a( y k/ o7 E2 ^endtask
6 B8 z5 h0 d jtask 是任务名
% J1 K" K2 O* M; ]之后是输入输出' y/ G" q3 H7 J: E
再紧跟是begin end 5 W6 k( l* E! w. }) U0 c2 Q) f
实例解说
7 _5 r( |1 _7 w9 Z( M/ n//自己定义
& `* W$ Y- T" Q3 Z+ g; V`timescale 1 ps/ 1 ps //verilog模块名4 w( R7 M. f! w2 ]8 @3 P- L
module verilog_ex2_vlg_tst(); reg clk;//数据类型与顶层文件的数据类型不同
& T ]! S! }9 D i% h7 Qreg rst_n; # n: ]1 {7 R3 M3 J A
wire clk_div; //verilog_ex2是被测试设计的顶层模块名,顶层模块例化为i1,也可以为i2 i3 i4" z" N" [' g$ y4 Z/ I9 U
//括号中是接口
( r" b- ]1 N1 v2 @4 z//.clk .clk_div .rst_n这3个.后面的引脚必须和顶层文件中的引脚名一致. }9 F; h" K! b2 z
//clk是对应得,接口引脚都是对应的
% q3 T& O C* Gverilog_ex2 i1 (
3 I. {% @6 t3 V; E; E$ ^" K// port map - connection between master ports and signals/registers
4 |) b( v( K7 s0 {0 ~5 `.clk(clk),
+ C) q: r; J5 q# i. t.clk_div(clk_div),6 l5 S( b( L9 A0 W, p
.rst_n(rst_n)
5 l( l" Q$ c" j) I3 x9 x);" [, S; s! o: G; G; L
initial
+ g* R. ?' J7 Y$ Nbegin
5 e, b. `6 W, ~/ J9 h// code that executes only once
3 U6 P- k% O7 Y( l4 X// insert code here --> begin
2 ^+ p6 A$ @: d; {/ h6 G clk = 0;* L; u& D7 d. r4 K
forever4 y2 [" B, }1 _- e* ]1 ^
#10 clk = ~clk;) n( K3 n* A! W& K1 j& N7 ~
// --> end
/ H5 p1 s" F! b $display("Running testbench");
8 F2 s3 o/ O9 ] P; `' Z; @+ Rend 3 L m5 L/ K. P" L
initial
$ ^" ]6 h$ R; g' N5 a9 j Kbegin j( S/ f, k# l1 W) b. g
rst_n = 0;$ g# V+ [' F; d4 t% j
#1000;6 e0 Y% I, V3 N# s' P9 V5 o. F( M
rst_n = 1;3 F( \9 f$ E$ d# Q7 w
#5_000;//delay 5us9 _; x3 R( h3 t
$stop;
6 `' l( V$ O, s9 C) i5 Pend
$ ]' T+ U4 {+ @: N, Z5 h//i1中的的.clk 后面的是clk也可以改为clk0实例代码如下:
/ s* l( J7 S! @`timescale 1 ps/ 1 ps
1 O5 ?# ^: L/ X% G' nmodule verilog_ex2_vlg_tst();' _2 S" _, `' N D
reg clk0;//clk0
|8 Z2 l; |% F- Q. @2 Zreg rst_n; # p& Y3 ?. X$ T. p$ J- M/ n& U
wire clk_div;
( L9 c/ ~" Q+ Y& S& a ! M" c1 g& q2 o$ d
verilog_ex2 i1 ( ; K9 k; \; A) h: o$ e
.clk(clk0),//clk0# y0 _, @% ^0 ^3 ^8 B$ _
.clk_div(clk_div),8 F& T& m! J. r8 `7 W
.rst_n(rst_n)
, Y m* N9 }' h, F* Q7 X);
/ `% c4 h1 | u* n9 Dinitial
( ?% J5 b8 _9 f/ Hbegin
( C8 @/ v: s: I, k+ D ' G. |+ o4 U/ a2 X
clk0 = 0;* Z3 V$ J. {6 R7 M) g* _9 ^
forever. e: l) z* l9 }+ x; ], o
#10 clk0 = ~clk0; " L, Z& H3 A, s1 l- A* V! R8 F
end
{8 N: Y$ u* c2 o6 H+ {initial8 |2 n& b$ H) k
begin) o* O q+ `9 p# b
rst_n = 0;
L3 r7 d' i: S+ l9 @6 t( n% ^/ Y #1000;- V: a0 y9 g' `; |0 K( O, K. }/ P a
rst_n = 1;. y b& |' d' d- o1 O7 l7 n& N
#5_000;//delay 5us' t1 D4 f" @' ]2 Y8 ~2 W; y; T5 b# Y
$stop;
3 K! G6 Y6 F9 p8 h* m/ m- A1 Eend7 V6 b) j! T- k& Q9 Z
9 h. s9 p' `8 Q* J/ {; z. O
7 l- E, a' O2 s# @: ~! t7 j! o7 i3 ~在顶层文件verilog_ex2.v 中
$ ?2 D+ C8 J) O2 C Nclk是输入引脚,是测试脚本的输出
F! K' }* A' E* P( ^clk_div是输出引脚,是测试脚本的输入: m; I. B' H1 ]. A8 d, O
rst_n是输入引脚,是测试脚本的输出 #10 clk0 = ~clk0; 表示每间隔10ns时间clk取反一次
% L$ e2 A0 R7 W W+ R8 U1 \#1000;表示延时1000ns
- L# w) I; V5 P- Z4 q# n1 a$stop;表示测试时间结束 编写完之后设置
/ D( y2 V7 I1 g' E编写完之后Tools->EDA RTL Simulation就可以ModelSim仿真了 好书推荐:
; E% x+ J R; B+ |: s( d吴继华,王诚《设计与验证Verilog HDL》# ~# b4 a" B: N5 `
Janick Bergeron 《Writing Testbench》! ]7 |7 D! ^/ U5 ~$ L% T3 Q U
张春,陈新凯,李晓雯 《编写测试平台》
: V5 o9 _! P- f+ A u6 e$ kTestbench 应用实例:
3 H8 g* E5 a: A; e8 H9 q7 N先新建一个Quartu工程
* v& |) {0 n6 s* g w工程文件夹verilog_EX2是文件夹名;/ H% m. q) o4 E" C- [; Z
工程名为verilog_ex2;& K3 t% t# M; b( o- B ?. j3 y
工程设置为仿真工具为ModelSim,而不是ModelSim-Altera,& I8 U4 M: V1 n( N1 J2 {
我使用的是ModelSim6.5 SE版本。
r8 N' r/ X6 F* _3 n3 u新建一个verilog HDL文件1 q$ E/ i: B6 d6 ^: t {$ Y
输入以下代码:
. J" S1 k+ g6 P/////////////////////////////////////////////////////////////////////////////1 C/ {) K: {( Q
module verilog_ex2(
' o- j/ J- A3 @ clk," }0 n3 l2 f Y5 \% |' ^* ^$ _$ o
rst_n," I v! [1 {5 I% ?* ]8 h/ N
clk_div& x' a+ W8 F6 n- V/ y
);
input clk;//20MHz时钟输入信号/ s- K7 A3 i$ a# N9 a
input rst_n;//低电平复位信号
7 X8 S4 t$ s% T# m* qoutput clk_div;//分频输出信号,连接到蜂鸣器
( N) a% _6 Q Z5 O8 D1 q//---------------------------------------------------------& h6 v5 J i' @7 K4 v
reg cnt; always @(posedge clk or negedge rst_n)
; m5 m m2 @" p% Z* q X if(!rst_n)- D# M3 Q9 v4 A* r
cnt <= 1'd0; //异步复位4 M' j8 D, Z( J3 R9 p
else! |0 j1 g* z3 r0 I
cnt <= ~cnt ; assign clk_div = cnt; endmodule5 ~8 T0 ]. I9 L$ ?! H( X j$ V
////////////////////////////////////////////////////////////////////////////////////
* d6 I5 Z/ D' Y保存为verilog_ex2.v文件4 d( N' a" V+ }- m T
编译Quartus工程。
5 j: w% j6 {4 |0 {, g编译之后有警告:
% c9 a# e' B6 A再把不用的引脚设置为三态输入,配置3个信号的引脚。 在使用TestBench之前就要设置ModelSim,
: B1 g8 k. [; y; D$ X* P' STools -> Options-> General -> EDA Tool Options界面下的ModelSim路径设置为D:\modeltech_6.5\win323 s+ r% B* q1 n, G' E
(我的ModelSim6.5 SE安装路径是D:\modeltech_6.5\win32,关于ModelSim安装和破解的问题,网上有许多的教程) 在一个工程中新建一个TestBench的步骤:- @" U( R6 g% H' |
由于新建一个工程之后,并没有TestBench文件,因此要建立一个Testbench文件
) g& M& ]# \; T' BProcessing->Start->Start Test Bench Template Writer
+ Y9 D. L2 Q' G2 v% u新建一个TestBench模板,会提示Test Bench Template Writer was successful,成功新建模板
+ ]1 m& S' ?1 |# H" N接下来要打开新建的模板 _* r* r4 R* ^
File->Open->simulation文件夹/modelsim文件夹/verilog_ex2.vt5 `4 ~+ m4 e a& u3 S7 D$ t: p
选择的时候注意把文件类型选择为 :All Files7 A8 G. V4 w0 w1 p' w2 Z
打开verilog_ex2.vt文件后,删除原有代码写入:
8 q6 W# O6 b0 m' N) W& o//////////////////////////////////////////////////////////////////////////////////////////# s! P2 n0 G* A4 w g( e
`timescale 1 ns/ 1 ps; W$ g; i1 U$ S) k" G8 |3 Q
module verilog_ex2_vlg_tst(); reg clk;
+ \: s+ j3 p3 i8 [' r6 l5 f. @reg rst_n; : y9 v. h- x0 _/ n0 _1 l. m
wire clk_div; 6 p9 r; X' X( o; }% ^ }1 S' T8 Y
verilog_ex2 i1 ( 8 a2 w/ K) v! b4 z5 S* Z
.clk(clk),
" F6 }- A& L5 m1 G) Y.clk_div(clk_div),
2 t6 d) B. }; O1 D! x: O1 H.rst_n(rst_n): c3 Q9 j+ n0 H* Z; Y9 L
);7 M6 X- H9 k" e
initial : O2 ]$ h: O+ C. }& H7 \
begin 4 _8 F- u) L! @1 }7 v& O
clk = 0;) @8 r9 z- w$ O' O% l% _) j
forever0 X' Y. V; D% w5 K
#10 clk = ~clk;
& ^$ c" {9 G! i% {4 y( { c) S5 u" _ end
0 S! W$ s' m! Binitial
3 Z; x: ^6 K( v# T5 V5 F3 P+ Y/ S2 Ubegin
5 e; [# q! n4 ]- R7 d1 s$ F rst_n = 0;0 G0 c- u: Y3 L \! p! ~8 L
#1000;
: C4 f a1 ]/ P/ j0 C; V rst_n = 1;
; x' c9 p' h' a6 i* X #5_000;//delay 5us. H# z3 f4 @3 I1 A7 [8 P
$stop;7 U6 f6 B" d3 {0 n5 A
end
2 m. S e4 o3 S1 qendmodule " P4 ]5 p) m. K' R' q
////////////////////////////////////////////////////////////////////////////////////////// T! b* v# _- h" ~. U% s5 z
保存文件
5 G; D7 ~' [3 [% K; D; r* L' ^编译Quartus工程% i" q: Q& R$ b) u2 ^
以上只是新建了一个TestBench# m- j9 O- A7 Q9 q5 M* b$ [
之后就要向工程中添加Test脚本的内容
2 u1 }4 L- ^* I3 b+ l0 NAssignment->Settings->EDA Tool Setting->Simulation
9 J. U6 u9 i) f1 v. T! z界面中Tool name选择Modelsim,
. u s7 Z% \, s* }! {在NativeLink Settings中勾选Compile test bench:
' |; x7 N% \0 H I/ P% ?单击后面的TestBenches,之后单击New,
+ ?( T9 P+ Y( O/ t+ P出现一个New Test Bench Settings界面中2 g: B: y9 G# l1 i9 h, Y; v
Test bench name(测试凳名称)中输入:verilog_ex25 r3 N2 l. `2 c8 b b v
Top Level module in test bench (测试凳中的顶层模块名):verilog_ex2_vlg_tst f7 S* d) ] I( v) o( |( @
Top Level module in test bench (测试凳中的顶层模块名)的输入查找方式是在Testbench中查找module后面的内容有:
1 Z* w% { T; O9 z! nmodule verilog_ex2_vlg_tst();就可以找到了。* X1 Z" X. b4 {! J7 `
Design instance name in testbench:实例化的模块名:i1也可以在testbench中找到* \$ g: `) B/ j4 z+ z
在下面的Test bench Files中的File name中单击按钮,选择打开verilog_ex2.vt,再单击Add按钮加入testbench 文件
/ p2 _- n: C1 ]6 s$ \依次单击OK,退出设置界面。$ h8 X4 I, }7 }$ e
再次重新编译Quartus工程文件 想查看Testbench 的结果就在Quartus工具中:6 P4 ~ |& `3 Y6 U+ \1 `6 k
Tools->Run EDA Simulation tool->EDA RTL Simulation
: V2 i3 x, E X3 Y& o3 R进行RTL级仿真就可以看到Modelsim仿真的波形了 / T& A! ?$ V( |! G% @
仿真完之后需要做一个时序约束:
: E1 r: |* ]1 V, p1 T+ BTools->TimeQuest Timing Analyzer
1 `$ M1 ?* `( Z' d' p# {初次打开时会提示:+ h2 s0 }% o6 [* A5 W; Z8 B9 _( P9 O
No SDC files were found in the Quartus Settings File and verilog_ex2.sdc doesn't exist.
1 c) O" w- T. t( jWould you like to generator an SDC file from the Quartus Settings file?4 m0 t6 b( [0 ]* h$ W" S% _
单击是按钮
& n- N% o: W( e- G+ b# a双击Create Timing Netlist/ _/ E/ c. J& F& w: }* K# R& }: k& K
双击Read SDC File8 P& h- [9 v. F- b
在TimeQuest Timing Analyzer 界面中的工具栏中 r) y. M# P! V+ }3 S
Constraints->Create Clock
1 C& q+ b8 B# _ e5 D7 pClock name时钟名称输入:sys_clk
$ D( t2 L; A& Q; ?Period周期是:50ns(时钟晶振是 20MHz)6 L) a% ^" B2 V* P
单击Targets后面的按钮:
' D3 U/ j% R& [4 M; Y8 p单击list选择clk,单击,选择OK按钮,单击Run。6 `. p) Z3 d+ o: S
双击Update Timing Netlist
8 s% ^2 q1 H, M双击Write SDC file,- }) s# A3 C" B- h
打开SDC文件就可以看到5 d4 a* L9 z# W" R- N$ e |
create_clock -name {sys_clk} -period 50.000 -waveform { 0.000 25.000 } [get_ports *]
0 G2 }9 s6 x! A" g. B周期是50ns, 再重新编译Quartus工程,编译之后,工程就会有新的布局布线。
) L0 r# E U) q* Z如果没有达到实序约束就会在Cirtical Waring中产生警告。" e0 G/ J+ M( Q( S5 a, l. |
编译之后再到TimeQuest中查看一下。
5 Y5 `8 O ^1 b' `/ P双击Create Timing Netlist
" u; C* c1 ]- U& c; q双击Read SDC File. a- J9 B% }* S9 G2 @
在Datasheet中Report Fmax Summary最大值的报告(主频最高)3 I1 L# c; E9 A
再看一下具体的时序约束的路径;
' C+ e8 H1 u) ?9 A0 FMacros->Report All Core Timings3 O& m+ s6 s# M/ V" M
可以看到Core clock setup和Core clock hold的两条报告 查看RTL Viewer 和Technolgy Map Viewer3 B, Z( B) A7 ~7 c. A
在Fitter中查看Chip Planner。 / ]1 p1 z5 P% N% v+ F$ B
|