MATLAB与FPGA数字信号处理(数字滤波器设计)、数字IC、无线通信、图像处理、信道编码系列
实现 N 进制计数器(N小于等于100),计数器输入时钟 clk(上升沿有效),复位(Quartus使用rst_n,低电平有效;Vivado中使用rst,高电平有效),同步复位方式,复位有效时输出为0,复位无效时输出计数数据,在仿真中设置成十进制无符号数显示。
提示:可以使用parameter定义,并在TestBench传入指定的进制数。
复位的设计规则:复位会消耗大量的资源,能不用复位就不用复位,某些必须要用复位的,尽量避免使用全局复位,尽量使用“同步复位”。在复位电平设计上,由于Altera(现Intel)系列的FPGA和Xilinx的FPGA的内部器件的不同,Altera推荐低电平复位,Xilinx推荐高电平复位。
【解答】
- 代码
`timescale 1ns / 1ns
///
// Engineer: 公众号 FPGA探索者
// Description: N进制计数器,注意,传入的输出位宽要和进制数匹配!
///
module counter(
clk,
rst,
data_out
);
parameter N = 9; //进制 N
parameter DWIDTH = 4; //对应输出位宽 logN 以2为底,向上取整
input clk;
input rst;
output reg [DWIDTH-1:0] data_out;
always @ ( posedge clk )
begin
if( rst ) begin
data_out <= 'b0;
end
else if( data_out == (N-1) )begin
data_out <= 'b0;
end
else begin
data_out <= data_out + 1'b1;
end
end
endmodule
仿真代码:
`timescale 1ns / 1ns
///
// Engineer: 公众号 FPGA探索者
// Description: N进制计数器,注意,传入的输出位宽要和进制数匹配!
///
module counter_tb();
parameter N = 9; //进制 N
parameter DWIDTH = 4; //对应输出位宽 logN 以2为底,向上取整
parameter CLK_Half_Period = 5; //定义半个时钟周期为5ns,即一个时钟10ns,100MHz时钟,这里是便于修改时钟
reg clk;
reg rst;
wire [DWIDTH-1:0] data_out;
counter #( //这里先传入参数,注意格式
.N(N),
.DWIDTH(DWIDTH)
)
U1( //这里的U1是器件名,下面传入引脚
.clk(clk),
.rst(rst),
.data_out(data_out)
);
initial begin
rst = 1;
clk = 0;
$display("TestBench is start!"); //对话框显示提示信息
#15;
rst = 0;
#200;
$stop; //停止仿真
end
always #CLK_Half_Period clk = ~clk; //每隔半个时钟周期,电平翻转一次
endmodule
RTL图:
综合、布局布线:
可以看到,使用了2个LUT(Look Up Table,查找表)和4个FF(Filp-Flop,寄存器)。
打开布局布线后的原理图(Schematic):
可以看到,消耗了4个查找表,1个LUT2,一个LUT3,两个LUT4,实际上在Xilinx的7系列FPGA中综合和布局布线给出的查找表单位是LUT6,即6输入查找表,LUT1~LUT5均可以通过LUT6分割得到,总计消耗了2个LUT6。后面会再讲这部分。
打开布局布线后的器件图(Device):
可以看到,消耗了两个LUT6查找表和4个FF寄存器。
仿真:
更改传入参数
parameter N = 17; //进制 N
parameter DWIDTH = 5; //对应输出位宽 logN 以2为底,向上取整
这时候查看综合和布局布线结果与9进制的一样,这是因为仿真中传入的数据不会改变布局布线,在实际应用中,通常是在其他顶层模块中根据传入的参数例化不同的底层模块。