parameter可以定义一个参数(默认是32位)。在写代码时,对于某些数字,设计者经常利用定义参数的方式进行编写,方便修改,也方便阅读。
$ M9 x8 T2 ~) S; p
在硬件电路中,使用计数器当做计时器,每记录一个数字等于过去一个时钟周期。由于本设计中采用的clk为50MHz,所以经过50_000_000(在verilog中,如果是描述数字,中间的下划线只起到分隔的作用,不影响数值的大小)个周期正好为1秒钟。由于计数器是从0开始计数,所以计数器只需要记录到50_000_000-1即可。
: W: p- g- S2 L' D4 g
为了能够记录到50_000_000-1这么大的数字,所以定义了一个26位的计数器cnt(参考附录1:设计中位宽的概念和计算位宽的小技巧)。
1 d- R# T7 S# G5 {3 @
在verilog中,“{}”( 大括号)的第一个特殊作用为位拼接。{a,b}相当于将a和b拼接为一个整体,并且是高位为a,低位为b。
9 f( h. f" g7 L% I. y% c* C3 z
当led输出为4’b0001时,第一个led点亮;经过1秒钟,输出4’b0010时,第二个led点亮;经过1秒钟,输出4’b0100时,第三个led点亮;经过1秒钟,输出4’b1000时,第四个led点亮;经过1秒钟,输出4’b0001时,第一个led点亮······按照上述的过程周而复始,就形成了流水灯。
. A4 v y3 c1 T2 X! S
不难发现,led的输出,一直为3个0,1个1。并且1的位置每1秒钟移动一次,从头到尾,然后又到头。这种现象可以利用移位的思想进行实现。即:led[3]<=led[2]; led[2]<=led[1]; led[1]<=led[0]; led[0]<=led[3];如果将被赋值的组成一个整体,那就是led,赋值的组成一个整体就是{led[2:0], led[3]}。
" c* U% i# e7 s9 E& \
- 仿真代码
. u9 H) f+ m n5 a( @, t
9 I2 D s0 D, \- p7 N
! p3 g9 }4 x7 H$ C0 W1 ~
8 T: h. r6 q6 ^9 E+ i: v' ~. g8 g" b) u( J
8 o8 z/ a8 z& j2 y, U/ `
" p/ \: {0 x" p% a0 Q5 t* h5 L5 U5 v7 d, I% G$ F
$stop是一个系统任务,功能为将Isim的仿真停止。
! R8 p( K% n8 z0 D2 b/ R
运行分析综合后,打开RTL仿真。
T/ f. m: n: V! J9 U1 m
- 波形分析
6 |* q$ n4 i# f/ Q4 Q$ b
( U. m' u: L+ H1 P
8 o7 }. @ T/ s0 t0 O( U5 o' A5 m+ e# _
在Isim中的Instances and Processes中,点开ledrun_tb,可以看到ledrun_inst,选中之后再Objects窗口中就会看到代码中的所有变量。我们选中cnt右键,选择Add to wave window。
2 v& t' ~- _! w# o4 ?7 [6 x
4 W# N! `4 R* \; \; f' ]5 e+ e; ~
) q5 X( Z* g& x% C
' Y5 i* v7 x# N0 U2 h# o
+ r' S5 X2 M, u" d" c# z* D
返回到wave窗口中,cnt信号已经添加到wave窗口中。由于新添加进来,没有数据(no data)。
6 ?8 W1 D6 q* V- R. n6 z6 @
4 Q* ~2 `! h8 a" C6 w( B1 A6 \
7 C" w$ N, z7 a* s! P# q- n. N
5 ? T' S' _* ?点击restart。
; W* \6 |& b! t# i
5 ?' }$ e7 l% v( a$ ]" G0 g0 \
$ y4 d. c3 s/ l. y1 W( ~/ `. ~& k) K U2 D/ b; P: E
5 ~$ w3 F4 Y) p5 @! q5 D5 R
restart按钮为重新运行波形,点击后,波形全部消失,wave窗口中所有的波形都处于no data 状态。点击run –all按钮,开始运行波形。
3 I& M$ E( W2 p" [' |' g
6 Z" u! S" H1 ?) j
" c! |/ Z( z( z7 b. q8 l
) e+ @" s+ \7 U/ E2 X2 v
运行后,会自动停止。停止在tb文件中的$stop处。
+ J$ W4 J, B5 A" P1 A! l7 h3 g; ^
返回wave窗口,各个信号都会有波形。
+ h% U4 _' w2 x$ J3 u: j* Q/ }7 A- S
* P1 a- m# U8 c) D6 ~
设置cnt的信号进制为无符号的十进制:右击cnt信号,选择radix中的unsigned Decimal。
( O8 @3 ]7 o; D5 ?4 `) T. ~
2 |6 k. }& n+ ]; {& R
$ m- T! o B7 G7 @5 V) |: _3 o# [. _, e0 I" i, l8 v
把光标放到复位结束时,选择放大波形。
0 Q" R- o( |; p! E
6 }. I, n& A+ K' D6 n放大按钮的右侧第二个按钮为全局缩放,功能为将所有运行波形,显示到目前的窗口里;左侧第二个为缩小。最右边的按钮是显示到光标位置。
+ g8 F, M/ k+ e' [" S
! l6 k' W! S% Z# G3 K
: ?5 m9 E [: Z1 N: m3 k8 F
+ T+ Q# f7 d7 u, [0 C2 f
可以看到,在复位结束后,cnt信号每一个时钟周期都会增加1。
, w; X3 y% f2 Q/ S) N9 y" F
由于我们设计的流水灯是每1秒钟流动一个,在上述的仿真中,led数值是不会变化的。如果仿真几秒钟的话,仿真的时间会比较长。在此不建议仿真几秒钟的时长,有可能会导致电脑卡住。
# V5 a9 ?; F/ p7 T# q( {# i4 i& H
仿真时,可以将T_1s的值,改成一个较小值。例如:5。然后在此编译仿真。
" T) i8 l; z0 Y% \3 o U
% N5 F$ ~: [2 J在ISE的编译器中,修改完后。进行综合分析,保证没有任何语法错误。点击Re-launch。
: ~3 d I3 f" ~
% z7 M8 {% m! E; G2 c/ S& Q `( v
6 q2 x6 ?9 @: O* W1 d' K8 p[color=rgba(0, 0, 0, 0.9)]能够清楚的看到,led在进行移位,并且都是5个周期移动一次。
* h6 O& S! }2 Q4 }
! j5 a5 j8 \% l$ q* G! t8 _
; u3 L1 R$ Q% E6 z3 x! p4 x1 i% Q5 a& v% A. r, M
6 a1 ]1 G) S, n
. s& O& i4 E' N: B! V& Y/ q. r( i( R( P0 p
: W9 P& [& c! {) q仿真通过后,关闭ISIM。回到ISE中,将参数修改成为50_000_000,综合分析后,分配管脚。布局布线,生成配置文件,进行下板测试。
* \6 A* L1 f6 G! f9 Y开发板上的四个LED开始做流水状点亮。
- P- b7 t8 E, W$ Q! p: w; B) D