前言
本文主要介绍使用下降沿敏感JK触发器设计一个16位脉动计数器。该设计使用了16个JK触发器,该计数器为异步计数器,并且该计数器可以进行异步复位,可以自行设定初始值进行计数。在初始值基础上进行计数的操作由一个16位全加器模块完成。
一. 异步计数器
异步二进制计数器的工作原理和结构均较简单,但各触发器不是在同一时钟沿作用下同时翻转,而是逐级脉动翻转实现计数进位的,故也称之为纹波计数器
二. 实现代码
1.计数器代码
// +FHDR----------------------------------------------------------------------------
//
//
// ---------------------------------------------------------------------------------
// Filename : ripple_carry_counter.v
// Author : xibei
// Created On : 2024-03-08 22:00
// Last Modified : 2024-03-12 23:30
// ---------------------------------------------------------------------------------
// Description : 下降沿敏感JK触发器实现异步复位16位脉动计数器,可以自定义初始值,在计数值不溢出情况下
// J=1,K=1时进行计数,当aerset=1时进行复位,当有使能信号set_enable=1时,可自行
// 行设定初始值,初始值由输入端set_num进行设置,通过初始值于计数值相加的方法,
// 该过程由一个16位全加器组成。
// -FHDR----------------------------------------------------------------------------
module ripple_carry_counter(
output [15:0] Q,
input set_enable,
input [15:0] set_num,
input J,
input K,
input clk,
input areset
);
wire [15:0] j;
wire [15:0] k;
wire cin,cout;
wire [15:0] q;
reg [15:0] Q_all;
wire [15:0] sum_all;
assign cin = 1'b0;
assign j[15:0] = {16{J}};
assign k[15:0] = {16{K}};
adder in(.sum(sum_all),.a(set_num),.b(q),.cin(cin),.cout()); //全加器模块例化,没用输出可以悬空
//genvar-for实现16个JK触发器模块例化
generate
genvar i;
for (i=0;i<16;i=i+1) begin:JK
if(i==0) begin
JK_FF jkff_in (.q(q[0]),.J(j[0]),.K(k[0]),.clk(clk),.areset(areset));
end
else begin
JK_FF jkff_in (.q(q[i]),.J(j[i]),.K(k[i]),.clk(q[i-1]),.areset(areset));
end
end
endgenerate
always @(negedge clk or posedge areset) begin
if(areset) Q_all<=16'h0;
else if(set_enable==1) Q_all<=sum_all;
else Q_all<=q;
end
assign Q=Q_all;
endmodule
// JK触发器模块
module JK_FF(
output reg q,
input clk,
input areset,
input J,
input K
);
always @(negedge clk or posedge areset) begin
if(areset) q<=1'b0;
else q<=(J&~q) | (~K&q);
end
endmodule
//全加器模块
module adder(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
assign {cout,sum}= a+b+cin;
endmodule
2.testbench(激励文件)
// +FHDR----------------------------------------------------------------------------
//
//
// ---------------------------------------------------------------------------------
// Filename : ripple_carry_counter_tb.v
// Author : xibei
// Created On : 2024-03-09 15:00
// Last Modified : 2024-03-09 17:30
// ---------------------------------------------------------------------------------
// Description : testbench文件
// 设定J=1,K=1,set_enable=1,set_num=16'h000A
// 测试从10开始计数,55ns后进行计数,955ns复位
// -FHDR----------------------------------------------------------------------------
`timescale 1ns/1ps
module ripple_carry_counter_tb;
reg clk;
reg areset;
reg J,K;
reg [15:0] set_num;
reg set_enable;
wire [15:0] Q;
ripple_carry_counter tb(.Q(Q),.clk(clk),.areset(areset),.J(J),.K(K),.set_enable(set_enable),.set_num(set_num));
initial clk=1'b0;
always begin
#5 clk=~clk;
end
initial areset=1'b1;
initial begin
#55 areset=1'b0;
#900 areset=1'b1;
#10 areset=1'b0;
#50 $finish;
end
initial begin
J=1'b1;K=1'b1;
end
initial begin
set_enable=1'b1;
#965 set_enable=1'b0;
end
initial begin
set_num=16'h000A;
end
initial begin
$monitor($time, " Q= %d",Q[15:0]);
end
/*
initial begin
$dumpfile("ripple_carry_counter_tb.vcd");
$dumpvars(0,ripple_carry_counter_tb);
end
*/
//使用iverilog和Gtkwave需要添加
endmodule
三. 模拟仿真
1.RTL view
2.波形图
四 .总结
本文只介绍了简单加法异步计数器,额外置位功能大概率不太完善,可能会有bug,本人水平有限只能进行简单实现,本来还想添加加法减法模式切换功能但没有找到简单切入点,只能暂时实现这些简单功能。