计数器与分频器实验
参考设计
流水灯实验中用按键手动产生时钟信号,本实验使用系统的连续时钟,使流水灯能自动移动。由于系统时钟的频率比较高,进入到VirtualBoard模块的CLOCK信号的频率是10MHz;如果直接用它作为移位寄存器的时钟,人的肉眼将无法分辨出LED灯的移动。所以需要设计一个分频器将时钟频率降下来。
例 1给出了一个自动流水灯的参考设计。它使用二进制计数器作为分频器,将10MHz系统时钟CLOCK分频后作为移位寄存器的时钟。认真阅读并理解参考设计的代码,计算出送给移位寄存器的clk信号的周期(频率的倒数)。
logic [22:0] count;
always_ff @(posedge CLOCK or posedge reset)
begin
if(reset)
count <= 0;
else
count <= count+1;
end
assign clk = count[22];
logic [7:0]q;
always_ff @ (posedge clk or posedge reset)
if (reset)
q <= 1;
else
q <= {q[6:0], q[7]};
注:完整代码可从开源项目托管网站下载,下载方法见下载实验材料。
编译后下载到实验板上,观察流水灯的自动移动。注意需开启虚拟面板的自动刷新,如图 1所示。远程实验系统默认的自动刷新时间间隔为1000毫秒。
思考为什么观察到的流水灯移动会跳跃,如何才能观察到LED灯的匀速移动(提示:需根据clk信号的周期恰当设置刷新间隔)。
实验任务1:分频器
用HDL设计一个偶数分频器,要求写成独立模块,端口声明如下,其中参数RATIO用来声明分频数。
module ClockDivider
#(parameter RATIO = 8) // RATIO为分频数,应大于1且为偶数
(
input ClkIn,Reset,
output reg ClkOut
);
在VirtualBoard模块中实例化ClockDivider模块,代替参考设计中的二进制分频器。ClkIn连接10MHz系统时钟CLOCK,ClkOut作为移位寄存器的时钟。实例化时传递合适的RATIO参数值,使ClkOut输出频率为1Hz。最终构成1秒钟移动一位的自动流水灯,运行效果如图 2。
实验任务2:仿真
到目前为止,设计是否正确是通过加载到FPGA芯片进行验证的。对于简单的实验项目,这种验证方法是可行的,而且经过虚拟实验软件的可视化,能达到较好的学习效果。但是对于复杂的工程项目,不可能通过实验系统进行验证。仿真是一种工业界通行的验证方法,后面CPU设计实验的最后阶段也可以通过仿真查找设计错误。
(1)熟悉ModelSim仿真软件
关于ModelSim的用法请阅读ModelSim仿真入门,其中介绍了用ModelSim仿真本实验项目参考设计的过程。
(2)理解Testbench
例 2给出了仿真计数器的Testbench。
`timescale 1ns/100ps
module tb_top;
reg reset, clock;
wire [19:0]pb;
assign pb[0] = reset;
VirtualBoard UUT (.CLOCK(clock), .PB(pb)); (1)
initial begin
reset=1'b1;
clock=1'b0;
end
initial #150 reset = 1'b0;
always #50 clock = ~clock;
initial #1000000 $stop; (2)
endmodule
1 | 被仿真的设计模块是VirtualBoard。 |
2 | 运行仿真的时长为1000000ns,即1ms。 |
(3)仿真任务1设计的分频器
由于testbench中指定的仿真时长只有1ms,不足以观察分频器ClkOut的周期性变化。可以在仿真暂停后继续运行仿真;也可以修改testbench,延长停止仿真前的时长;或者临时修改设计代码,改为较小的分频数以便能观察到ClkOut的周期性变化。