目录
1.前言
在使用FPGA设计硬件时经常会用到计数器,虽然很简单,但是每次都要反复去写计数器,显得很麻烦而且效率低。今天就分享一个之前自己设计的计数器,可以调整位宽,以及选择是向上或向下计数。
2.设计
不含输入计数值的:
verilog
`timescale 1ns / 1ps
module counter #(parameter CNT_NUM = 4'd8,
parameter ADD = 1'b1)
(
input clk ,
input rst_n ,
input En_cnt ,
output reg [$clog2(CNT_NUM) - 1:0] cnt ,
output cnt_last
);
wire end_cnt;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= ADD ? 'd0 : CNT_NUM - 1;
end
else if(En_cnt)begin
if(end_cnt)begin
cnt <= ADD ? 'd0 : CNT_NUM - 1;
end
else begin
cnt <= ADD ? cnt + 1'b1 : cnt - 1'b1;
end
end
end
assign end_cnt = ADD ? cnt == CNT_NUM - 1 : cnt == 0;
assign cnt_last = end_cnt ? 1'b1:1'b0;
endmodule
含最大计数值输入的:
verilog
`timescale 1ns / 1ps
module counter_in #(parameter CNT_NUM = 4'd8,
parameter ADD = 1'b1)
(
input clk ,
input rst_n ,
input En_cnt ,
input [$clog2(CNT_NUM) - 1:0] cnt_din ,
output reg [$clog2(CNT_NUM) - 1:0] cnt ,
output cnt_last
);
wire end_cnt;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= ADD ? 'd0 : cnt_din;
end
else if(En_cnt)begin
if(end_cnt)begin
cnt <= ADD ? 'd0 : cnt_din;
end
else begin
cnt <= ADD ? cnt + 1'b1 : cnt - 1'b1;
end
end
end
assign end_cnt = ADD ? cnt == cnt_din : cnt == 0;
assign cnt_last = end_cnt ? 1'b1:1'b0;
endmodule
3仿真
verilog
`timescale 1ns / 1ps
module counter_tb();
parameter CNT_NUM = 4'd8;
parameter ADD = 1'b0;
parameter T = 10;
reg clk ;
reg rst_n ;
reg En_cnt ;
reg [$clog2(CNT_NUM) - 1:0] cnt_din ;
wire [$clog2(CNT_NUM) - 1:0] cnt ;
wire cnt_last ;
counter_in #(.CNT_NUM(CNT_NUM),
.ADD(ADD))
counter_test(
.clk (clk ),
.rst_n (rst_n ),
.En_cnt (En_cnt ),
.cnt_din (cnt_din ),
.cnt (cnt ),
.cnt_last (cnt_last )
);
always #(T/2) clk = ~clk;
initial begin
clk = 1'b0;
cnt_din = CNT_NUM -1;
rst_n = 1'b0;
#(10*T)
rst_n = 1'b1;
En_cnt = 1'b0;
#(10*T)
En_cnt = 1'b1;
end
endmodule