parameter可以定义一个参数(默认是32位)。在写代码时,对于某些数字,设计者经常利用定义参数的方式进行编写,方便修改,也方便阅读。
6 P3 {0 x/ l# \( o% {
在硬件电路中,使用计数器当做计时器,每记录一个数字等于过去一个时钟周期。由于本设计中采用的clk为50MHz,所以经过50_000_000(在verilog中,如果是描述数字,中间的下划线只起到分隔的作用,不影响数值的大小)个周期正好为1秒钟。由于计数器是从0开始计数,所以计数器只需要记录到50_000_000-1即可。
3 x3 e$ `; `3 a, `
为了能够记录到50_000_000-1这么大的数字,所以定义了一个26位的计数器cnt(参考附录1:设计中位宽的概念和计算位宽的小技巧)。
% r/ C0 r- g$ S' C
在verilog中,“{}”( 大括号)的第一个特殊作用为位拼接。{a,b}相当于将a和b拼接为一个整体,并且是高位为a,低位为b。
% |9 ]3 ~4 @7 K. V
当led输出为4’b0001时,第一个led点亮;经过1秒钟,输出4’b0010时,第二个led点亮;经过1秒钟,输出4’b0100时,第三个led点亮;经过1秒钟,输出4’b1000时,第四个led点亮;经过1秒钟,输出4’b0001时,第一个led点亮······按照上述的过程周而复始,就形成了流水灯。
* z* u/ b% A5 P! Q
不难发现,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]}。
, ], I2 A. R( e
- 仿真代码6 T# Y( w, r: ^8 [: k7 {
" n0 Q& m, N5 s( q
, p* B7 ]/ f6 K6 G5 Q
1 t9 {( ^$ f! Y! a% [2 @. h( C# v+ R& B# c
2 R3 w; O/ R) e w
; P, p: h$ p+ F* M. ^8 `* v# l; C2 p4 L f; ]2 H) b
$stop是一个系统任务,功能为将Isim的仿真停止。
& U5 L( x5 j3 I, c* k/ R. D, T
运行分析综合后,打开RTL仿真。
6 j! c0 h5 F; Y* g- y) f8 _( D
- 波形分析
! P3 R8 p) Z( F }3 s o8 C* p( E- v) O8 L
+ _3 Z0 c0 L+ H6 |
3 ?8 Q. b c( f在Isim中的Instances and Processes中,点开ledrun_tb,可以看到ledrun_inst,选中之后再Objects窗口中就会看到代码中的所有变量。我们选中cnt右键,选择Add to wave window。
9 \1 M6 D" w7 P$ P$ v, {
O( P- {) m5 y; r$ e4 [
5 a( g" A' o/ u" F% ~2 K0 }& {
, l! S2 R+ X% j( R, H
0 B1 ]& ~# }8 c" L) H
返回到wave窗口中,cnt信号已经添加到wave窗口中。由于新添加进来,没有数据(no data)。
1 S# D( l1 E- c9 Q. o1 V& F
$ e1 D1 |9 g& I2 F
U. U$ f* B( [4 p8 g6 V2 z+ c- @* {! n; Z) G( _
点击restart。
0 ] l$ c3 F' g6 ]0 K/ u8 D
+ V5 M5 t, V4 D, u
. a7 h& {5 v, Q9 B5 q1 \! Q. H* L: ? r
1 p/ ?- K. }2 _2 X5 v0 q
restart按钮为重新运行波形,点击后,波形全部消失,wave窗口中所有的波形都处于no data 状态。点击run –all按钮,开始运行波形。
% I1 Q9 |- e$ t- v3 k
, \# P$ h/ r: U K a" h# m
7 ?/ g# m; F w- ]
# A% P: r' j8 j$ o' K
运行后,会自动停止。停止在tb文件中的$stop处。
! R+ S* G, r n: e
返回wave窗口,各个信号都会有波形。
; l2 [% }1 F+ f3 V
& H* d$ u% X6 o3 _- u# {- o- m
设置cnt的信号进制为无符号的十进制:右击cnt信号,选择radix中的unsigned Decimal。
# y! k$ `- o7 B% j+ t* H' ?6 ~% j
' O' N' {: N( J7 l# \ I5 |
+ e6 R" o! F2 e, e8 U; R8 C4 m5 ^' z
, C. s4 |( ?6 |$ \0 S5 W
把光标放到复位结束时,选择放大波形。
* n$ w1 {( T( [2 B7 n6 C; ?$ b
) ?/ M H9 M. `# j放大按钮的右侧第二个按钮为全局缩放,功能为将所有运行波形,显示到目前的窗口里;左侧第二个为缩小。最右边的按钮是显示到光标位置。
( G3 L- |6 A z" u. o
) I2 A$ t# u4 d. k8 I
% t4 A6 F4 {: ^8 `0 ~5 K8 g
6 B* G9 N& w$ @0 j; k
可以看到,在复位结束后,cnt信号每一个时钟周期都会增加1。
7 \4 e: o% c' t, f' X6 k6 Y
由于我们设计的流水灯是每1秒钟流动一个,在上述的仿真中,led数值是不会变化的。如果仿真几秒钟的话,仿真的时间会比较长。在此不建议仿真几秒钟的时长,有可能会导致电脑卡住。
5 a$ k' ~$ j- q
仿真时,可以将T_1s的值,改成一个较小值。例如:5。然后在此编译仿真。
1 s; O* u2 k9 i* F4 |: W& T
$ `. ~7 v. L( p% F7 C) i在ISE的编译器中,修改完后。进行综合分析,保证没有任何语法错误。点击Re-launch。
; E3 `. {2 v7 ?1 J2 z# | j
~8 L1 T1 K* o2 h) _% l8 }
9 C9 w7 y, W" X[color=rgba(0, 0, 0, 0.9)]能够清楚的看到,led在进行移位,并且都是5个周期移动一次。
& F9 y! f! v. y& S/ K5 m
1 R* H _2 Z; k* E+ t4 Z1 J& n1 X4 W
; u3 e. T3 A. J" y: s
3 g ^! t0 N& j, R$ X H- Q0 f2 U6 p; V
- t5 I1 x0 b7 j( I3 @) {# B& j! G( `/ |- h- o/ n9 ?1 ]
# l8 X6 Y7 n- }1 i+ f仿真通过后,关闭ISIM。回到ISE中,将参数修改成为50_000_000,综合分析后,分配管脚。布局布线,生成配置文件,进行下板测试。
0 U: q" |% c c% C* z" A开发板上的四个LED开始做流水状点亮。
/ `9 w8 g/ b5 M( ~6 L7 F" H