一、题目
用verilog实现两个串联的异步复位的T触发器的逻辑,结构如图:
![](https://i-blog.csdnimg.cn/blog_migrate/2f8d94db0354c0bdc781fe2e35b0ceb9.png)
波形示意图
![](https://i-blog.csdnimg.cn/blog_migrate/6578896cd89e5f78e4a67ac454fc1d7d.png)
输入描述:
输入信号 data, clk, rst (类型 wire)
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出描述:
输出信号 q
类型 reg
二、思路
T触发器的特性方程
Qn+1 = T Qn ' +T ' Qn = T⊕Qn (T是上一时刻的输入 Qn是上一时刻输出 )
Q过程为第一个触发器的输出(即下面的q1),Q输出为第二个触发器的输出(q)
设n为有效时钟沿,Q过程取决于n-1的T, Q输出取决于n-1的Q过程
n | T | Q过程(q1) | Q输出(q) |
0(复位状态) | 0 | 0 | 0 |
1(第n+1) | 1 | 0 | 0 |
2(第n+2状态) | 1 | 1 | 0 |
3 | 1 | 0 | 1 |
4 | 1 | 1 | 1 |
5 | 1 | 0 | 0 |
6 | 0 | 1 | 0 |
7 | 0 | 1 | 1 |
8 | 0 | 1 | 0 |
9 | 0 | 1 | 1 |
总结:第n+1的T生成n+2时候的Q1
三、设计文件
`timescale 1ns/1ns
module Tff_2 (
input wire data, clk, rst,
output reg q
);
reg q1;
always @ ( posedge clk or negedge rst)
if (~rst) begin
q1 <= 1'b0;
q <= 1'b0;
end
else begin
if (data) begin
q1 <= !q1;
end
if (q1) begin //非阻塞赋值 块结束后才完成赋值操作 所以q1还是等于原来的值,即qn
q <= !q;
end
end
endmodule
四、仿真结果
![](https://i-blog.csdnimg.cn/blog_migrate/c98f06848a6c6b9dcbfb6ea35f585eb0.png)
随意选取一个clk上升沿,向下画,得到的T是此时的T,得到的Q是新产生的次态。
五、总结与扩展
- T触发器简介 (Qn为现态 Qn+1为次态)
T触发器是一种边沿敏感的存储单元。只有一个信号输入端T,在时钟有效边沿到来时,T端输入有效信号,则触发器翻转,否则触发器保持不变。因此T触发器能够实现有效的计数功能,常用于实现数字计数器。T触发器逻辑功能为:当T=0时,触发器状态不变Qn+1=Qn;而当T=1时,在脉冲有效边沿到来时翻转。触发器的特性表如表所示:
![](https://i-blog.csdnimg.cn/blog_migrate/56517a5459b7938d6874fee07609da7c.png)
特性方程:
![](https://i-blog.csdnimg.cn/blog_migrate/308ea5d4dec4cdd15247c1dc50da80cf.png)
状态转换图:
![](https://i-blog.csdnimg.cn/blog_migrate/9506caf6f2325ae9ac1ac415d84653fe.png)
veirlog实现T触发器
module t(clk,rst,T,Q);
input clk,rst,T;
output Q;
reg Q;
always@(posedge clk or posedge rst)
begin
if (rst==1'b1) Q<=1'b0;
else if (T==1'b1) Q=~Q;
else Q=Q;
end
endmodule
- JK触发器
J-K触发器是时钟边沿敏感的基本存储单元。逻辑电路和逻辑符号如下图所示:
JK触发器电路结构:
![](https://i-blog.csdnimg.cn/blog_migrate/472d6c7a35cc49e87df0dd03b2eb4de8.png)
JK触发器逻辑符号
![](https://i-blog.csdnimg.cn/blog_migrate/5a4be819e48cc1d7508af37bb84e1b55.png)
工作原理:
在有效时钟的脉冲边沿没到达时,即clk=0,或者clk=1,或者clk由高电平跳转到低电平,与非门G3和G4将J与K端的输入信号屏蔽,触发器状态不受输入信号的影响,维持不变。
在时钟上升沿信号到来时,触发器的状态将会随着J与K的输入产生相应的变化。当J=0,K=0时,触发器的状态维持不变,Qn=Qn+1.当J=0,K=1时,触发器被置成0状态,当J=1,K=0时,触发器被置成1状态,当J=1,K=1时,触发器翻转。由此可以得到触发器的特性表:
表2-1上升沿触发触发器特性表
![](https://i-blog.csdnimg.cn/blog_migrate/e4cf8362b59fd3d50d43ac7d2a1d1a38.png)
特性方程
![](https://i-blog.csdnimg.cn/blog_migrate/e9334aeddb09792e57bf7ea51eb77167.png)
状态转换图
![](https://i-blog.csdnimg.cn/blog_migrate/d4b5eac48c55e108b8b37d5e0cdd78b6.png)
veirlog实现J 触发器
module JK_Tri (j,k,clk,Q,Q1);
input j,k,clk;
output Q,Q1;
reg Q;
always@(posedge clk)
begin
case({j,k})
2'b00:Q<=Q;
2'b01:Q<=2'b0;
2'b10:Q<=2'b1;
2'b11:Q<=~Q;
default:Q<=Q;
endcase
end
assign Q1=~Q;
endmodule
- 同步和异步的概念
同步,异步,复位,置位D触发器的Verilog描述
置位就是通过外部强制改变输入,从而把输入映射到输出的一种方式;复位就是通过程序把输入的值变为通电时候的初始状态。
简单来说,在功能上,置位就是使得输出为1,复位就是使得输出为0。比如开始没有输出,置位后输出1,再复位后就又变为0了。
(1)异步置位D触发器
关键在于使用信号preset的下降沿,作为always的触发,这样,无论时钟clk处于何种状态,都会对输出q进行置位操作(即:不管你clk是不是上升沿都可以进行置位操作),美其名曰:异步置位
module dff_async_pre (
input data, clk, preset,
output q
);
parameter UDLY = 1;
reg q;
always @ (posedge clk or negedge preset) begin
if ( ~preset )
q <= #UDLY 1'b1; //如果是置位 强制输出为高电平
else
q <= #UDLY data;//每一个上升沿来了
end
endmodule
延时 U_DLY 时间后,执行q <= 1'b0 ;
U_DLY目前设置的是1,这种写法只能用于仿真,实际在FPGA芯片中这些延时会被去掉,
当这样写的时候,在文件开头应该有类似 `timescale 1 ns/1 ns 这样的时间刻度定义,这时候 parameter U_DLY =1;#U_DLY;代表的就是延时1 ns
![](https://i-blog.csdnimg.cn/blog_migrate/e32c28a3cd9b058bf85cf7b8f2ee2195.png)
(2)同步复位D触发器
仅由clk上升沿事件作为always的触发,所以复位动作,需要与clk同步才能完成,美其名曰:同步复位;
module dff_sync_rst (
input data, clk, reset,
output q
);
parameter UDLY = 1;
reg q;
always @ (posedge clk) begin
if ( !reset ) begin
q <= #UDLY 1'b0;
end else begin
q <= #UDLY data;
end
end
endmodule
![](https://i-blog.csdnimg.cn/blog_migrate/7ea9a40d92a3f08b955e4127371bb71f.png)
(3)异步复位和异步置位D触发器
module dff_async (
input data, clk, reset, preset,
output q
);
parameter UDLY = 1;
reg q;
always @ (posedge clk or negedge reset or negedge preset) begin
if ( ~reset) begin
q <= #UDLY 1'b0;
end else if ( ~preset) begin
q <= #UDLY 1'b1;
end else begin
q <= #UDLY data;
end
end
endmodule
![](https://i-blog.csdnimg.cn/blog_migrate/c9f1f1178de76beb8b2fcca9f7ccc817.png)
- 补充一个T触发器的实现
module t(clk,rst,T,Q);
input clk,rst,T;
output Q;
reg Q;
always@(posedge clk or posedge rst)
begin
if (rst==1'b1) Q<=1'b0;
else if (T==1'b1) Q=~Q;
else Q=Q;
end
endmodule
testbench
module t_t;
reg clk,rst,T;
wire Q;
initial
begin
clk=1'b0;
forever #10 clk=~clk;
end
initial
begin
rst=1'b0;T=1'b0;
#10 rst=1'b1;T=1'b1;
#10 rst=1'b0;T=1'b1;
#20 T=1'b1;
#20 T=1'b0;
#20 T=1'b1;
end
t u1(.clk(clk),.rst(rst),.T(T),.Q(Q));
endmodule
![](https://i-blog.csdnimg.cn/blog_migrate/e9db96b117b333ed92d95be508d3f7fa.png)
仿真波形
T的值更新了Q, 新的Q就是次态Qn+1
是由clk上升沿的T值更新了Q,(即得到了次态Qn+1),所以在看仿真波形时,在某一个上升沿处:
T是此时的输入,Q是新产生的次态