D触发器、同步与异步复位、脉冲边沿检测 HDLBits链接
D触发器 定义:
D触发器是一个具有记忆功能的,具有两个稳定状态的信息存储器件,触发器具有两个稳定状态,即”0”和”1”,在一定的外界信号作用下,可以从一个稳定状态翻转到另一个稳定状态。在这里解释边沿触发的D触发器,D触发器在时钟脉冲CP的前沿(正跳变0→1)发生翻转,触发器的次态(下一个状态)取决于CP的脉冲上升沿到来之前D端的状态,即次态Q=D。因此,它具有置0、置1两种功能。由于在CP=1期间电路具有维持阻塞作用(即触发器的输出不变),所以在CP=1期间,D端的数据状态变化,不会影响触发器的输出状态,故边沿D触发器受干扰的可能性就降低了。
功能表:
D
CLK
Q
QN
0
时钟上升沿
0
1
1
时钟上升沿
1
0
×
0
last Q
last QN
×
1
last Q
last QN
同步复位与异步复位 同步复位:
顾名思义,同步复位就是指复位信号只有在时钟上升沿到来时,才能有效。否则,无法完成对系统的复位工作。用Verilog描述如下:
1 2 3 4 always @ (posedge clk) begin if (!Rst_n) ... end
异步复位:
指无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。用Verilog描述如下:
1 2 3 4 always @ (posedge clk or negedge Rst_n) begin if (!Rst_n) ... end
D触发器巩固练习 题目描述1 :
创建一个D触发器。
Solution1 :
1 2 3 4 5 6 7 8 9 10 module top_module ( input clk, input d, output reg q ); always @(posedge clk) begin q <= d; end endmodule
tips:时序的always块使用非阻塞赋值。
题目描述2 :
创建8个D触发器,每个都由时钟的上升沿触发。
Solution2 :
1 2 3 4 5 6 7 8 9 10 11 module top_module ( input clk, input [7 :0 ] d, output [7 :0 ] q ); always @(posedge clk) begin q <= d; end endmodule
题目描述3 :
创建8个d触发器与主动高同步复位。所有D触发器由clk的上升沿触发。
Solution3 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module top_module ( input clk, input reset, input [7 :0 ] d, output [7 :0 ] q ); always @(posedge clk) begin if (reset) q <=8'd0 ; else q <= d; end endmodule
题目描述4 :
创建8个D触发器与主动高同步复位。触发器必须被重置为0x34,而不是0。所有D触发器应由clk的下降沿触发。
Solution4:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module top_module ( input clk, input reset, input [7 :0 ] d, output [7 :0 ] q ); always @(negedge clk) begin if (reset) q <= 8'h0x34 ; else q <= d; end endmodule
题目描述5 :
创建8个D触发器与主动高异步复位。所有D触发器应由clk的上升沿触发。
Solution5 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 module top_module ( input clk, input areset, input [7 :0 ] d, output [7 :0 ] q ); always @(posedge clk or posedge areset) begin if (areset) begin q <= 8'd0 ; end else begin q <= d; end end endmodule
tips:使用posedge areset
时,只能使用if(areset)
首先进行判断而不能用if(!areset)
,否则会报错。
题目描述6 :
创建一个16D触发器,有时我们仅需要修改部分触发器中的值。字节使能信号控制当前时钟周期中16个寄存器中哪个字节需被修改。byteena[1]
控制高字节d[15:8]
,而byteena[0]
控制低字节d[7:0]。
resetn
是一个同步,低复位信号。
所有的D触发器由时钟的上升沿触发。
Solution6 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 module top_module ( input clk, input resetn, input [1 :0 ] byteena, input [15 :0 ] d, output [15 :0 ] q ); always @(posedge clk) begin if (!resetn) begin q <= 16'd0 ; end else begin if (byteena[1 ]) q[15 :8 ] <= d[15 :8 ]; if (byteena[0 ]) q[7 :0 ] <= d[7 :0 ]; end end endmodule
题目描述7:
实现下面的电路(锁存器)
Solution7 :
1 2 3 4 5 6 7 8 9 10 11 12 module top_module ( input d, input ena, output q); always @(*)begin if (ena)begin q = d; end end endmodule
题目描述8:
实现下面的电路
Solution8 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module top_module ( input clk, input d, input ar, output q); always @(posedge clk or posedge ar) begin if (ar) begin q<=1'b0 ; end else begin q<=d; end end endmodule
题目描述9:
实现下面的电路
Solution9:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module top_module ( input clk, input d, input r, output q); always @(posedge clk) begin if (r) begin q<=1'b0 ; end else begin q<=d; end end endmodule
题目描述10:
实现下面的电路
Solution10:
1 2 3 4 5 6 7 8 9 10 module top_module ( input clk, input in, output out); always @(posedge clk) begin out <= (in ^ out); end endmodule
题目描述11:
考虑下图的电路:
假设要为这个电路实现分层的Verilog代码,使用一个子模块的三个实例,该子模块中有一个触发器和多路选择器。为这个子模块编写一个名为top_module的Verilog模块(包含一个触发器和多路选择器)
Solution11 :
1 2 3 4 5 6 7 8 9 10 11 12 module top_module ( input clk, input L, input r_in, input q_in, output reg Q); always @(posedge clk) begin Q <= L ? r_in : q_in; end endmodule
题目描述12:
考虑下图的n-bit移位寄存器
为该电路的一个阶段编写一个Verilog模块顶层模块,包括触发器和多路选择器。
Solution12:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module top_module ( input clk, input w, R, E, L, output Q ); always @(posedge clk) begin case ({E,L}) 2'b00 :Q<=Q; 2'b01 :Q<=R; 2'b10 :Q<=w; 2'b11 :Q<=R; endcase end endmodule
题目描述13:
给定如图所示的有限状态机电路,假设D触发器在机器开始之前被初始重置为零
Solution13:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module top_module ( input clk, input x, output z ); reg Q1,Q2,Q3; always @(posedge clk) begin Q1 <= (x ^ Q1); Q2 <= (x & ~Q2); Q3 <= (x | ~Q3); end assign z = ~(Q1|Q2|Q3); endmodule
题目描述14:
JK触发器有下面的真值表。只使用D触发器和逻辑门实现JK触发器。注:Qold是时钟上升沿前的D触发器的输出。
J
K
Q
0
0
Qold
0
1
0
1
0
1
1
1
~Qold
Solution14:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module top_module ( input clk, input j, input k, output Q); always @(posedge clk) begin case ({j,k}) 2'b00 :Q<=Q; 2'b01 :Q<=1'b0 ; 2'b10 :Q<=1'b1 ; 2'b11 :Q<=~Q; endcase end endmodule
脉冲边沿检测 原理:
脉冲边沿的特性:两侧电平发生了变化 。
若检测的是下降沿,那就是高电平变低电平。
若检测的是上升沿,那就是低电平变高电平。
若检测脉冲边沿,只需将前后进来的信号做异或运算,即两个电平不相同则是发生边沿。
思路:
设计寄存器用来接收被检测的信号;若{先进reg,后进reg}=2'b10
,则是下降沿;
若{先进reg,后进reg}=2'b01
,则为上升沿。
注:使用多个寄存器可以更好的检测边沿,防止干扰脉冲。具体看下例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin rs232_rx0 <= 1'b0 ; rs232_rx1 <= 1'b0 ; rs232_rx2 <= 1'b0 ; rs232_rx3 <= 1'b0 ; end else begin rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2; end end assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;
易分析,信号rs232_rx0
,rs232_rx1
,必须都为0,且信号rs232_rx3
,rs232_rx2
都必须为1,neg_rs232_rx
才会为1。此时判断为下降沿。
边沿检测巩固练习 题目描述1:
对于8位向量中的每一位,检测输入信号何时从一个时钟周期的0变化到下一个时钟周期的1(正边缘检测)。输出位应该在发生0到1转换后的周期,如下示意图所示:
Solution1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 module top_module ( input clk, input [7 :0 ] in, output [7 :0 ] pedge ); reg [7 :0 ] temp_in; always @(posedge clk) begin temp_in <= in; pedge <= ~temp_in & in; end endmodule
题目描述2:
对于8位向量中的每一位,检测输入信号何时从一个时钟周期变化到下一个时钟周期(检测脉冲边沿)。输出位应该在发生转换后的周期。
Solution2:
1 2 3 4 5 6 7 8 9 10 11 12 13 module top_module ( input clk, input [7 :0 ] in, output [7 :0 ] anyedge ); reg [7 :0 ] temp_in; always @(posedge clk) begin temp_in <= in; anyedge <= temp_in ^ in; end endmodule
题目描述3:
对于32位向量中的每一位,当输入信号从一个时钟周期的1变化到下一个时钟周期的0时捕获(捕捉下降沿),“捕获”意味着输出将保持1直到被reset(同步重置)。
每个输出位的行为就像一个SR触发器:输出位应该在发生1到0转换后的周期被设置(为1)。当复位为高时,输出位应该在正时钟边缘复位(为0)。如果上述两个事件同时发生,则reset具有优先级。
在下面示例波形的最后4个周期中,“reset”事件比“set”事件早一个周期发生,因此这里不存在冲突。
Solution3(1):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 module top_module ( input clk, input reset, input [31 :0 ] in, output [31 :0 ] out ); reg [31 :0 ] temp_in; reg [31 :0 ] state; integer i; always @(posedge clk) begin temp_in <= in; for (i=0 ;i<32 ;i++) begin case ({temp_in[i] & ~in[i],reset}) 2'b10 :out[i]<=1'b1 ; 2'b11 :out[i]<=1'b0 ; 2'b01 :out[i]<=1'b0 ; default :out[i]<=out[i]; endcase end end endmodule
Solution3(2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 module top_module ( input clk, input reset, input [31 :0 ] in, output [31 :0 ] out ); reg [31 :0 ] temp_in; always @(posedge clk) begin temp_in <= in; end always @(posedge clk) begin if (reset)begin out<=32'b0 ; end else begin out<=temp_in & ~in | out; end end endmodule
题目描述4:
时钟双沿触发器
always @(posedge clk or negedge clk)
Solution4(1):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 module top_module ( input clk, input d, output q ); reg q1,q2; always @(posedge clk) begin q1<=d; end always @(negedge clk) begin q2<=d; end assign q = clk?q1:q2; endmodule
Solution4(2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 module top_module ( input clk, input d, output q ); reg q1,q2; always @(posedge clk) begin q1<= d ^ q2; end always @(negedge clk) begin q2<= d ^ q1; end assign q = q1 ^ q2; endmodule
我们知道任何一个数异或一个数再异或同一个数,将得到本身。这就是最简单的加密与解密原理。
Solution2相较于Solution1少了使用clk信号进行选择,可以避免产生毛刺 。推荐使用Solution2进行双边检测。
总结
学习了D触发器与同步异步复位的概念
学会了实际工程中常用的边沿检测电路