用Verilog实现glitch free时钟切换电路。
有毛刺的时钟切换电路
这个时钟切换电路是一个纯组合逻辑,输出时钟(OUT CLOCK)由选择信号(SELECT)控制,当SELECT为1时输出CLK1,反之,输出CLK0.
看似很简单,实现了时钟的切换,实则存在着很大的隐患,如下图所示:
assign outclk = (sel==1)?clk1:clk0;
相关时钟源的毛刺保护
下图显示了防止源时钟相互倍数的时钟开关输出出现毛刺的解决方案。在每个时钟源的选择路径中插入一个负边沿触发的D触发器。 在时钟的下降沿采样选择控制(SELECT),以及仅在首先使其他时钟无效后使能选择(SELECT),可以提供出色的输出保护 :
下面简单的解释下这个电路:
当SELECT为0时,明显CLK1的那部分通路到输出无效,仅仅看下半部分电路即可,在CLK0的下降沿采样SELECT(取反后)信号,与CLK0相与之后输出;当SELECT为1时,同理上半部分电路有效;
需要重点分析的是当SELECT在任意时刻切换的时候,输出会不会出现毛刺?
首先SELECT为0,也就是在CLK0的下降沿采样寄存SELECT(取反后)信号与CLK0相与,输出时钟为CLK0;
当在图中时刻SELECT由低电平变为高电平,此时未到CLK0的下降沿,寄存器的输出还将一直是高电平(SELECT之前为0,取反为1),当到达CLK0的下降沿时刻,采样到SELECT为高电平,那么!SELECT为0,也就是下半部分电路从此无效,上半部分电路有效,此时需要等到CLK1的下降沿采样SELECT值,在此之前,输出仍未CLK0,到达CLK1的下降沿后,输出变成了CLK1和SELECT的与,也就是CLK1。由图可见,输出时钟完美切换,并没有出现斩波信号以及毛刺。
在时钟的下降沿寄存选择信号(SELECT)可确保在任一时钟处于高电平时输出端不会发生变化,从而防止斩波输出时钟(意思是下降沿寄存,可以保证下降沿到来之前输出端保持不变,这样就不会斩断当前时钟了)。 从一个时钟的选择到另一个时钟的反馈使开关能够在开始传播下一个时钟之前等待取消选择当前时钟,从而避免任何毛刺(意思是即使当前SELECT突然变化了,也必须等待到当前时钟的下降沿到来才能去使当前时钟无效,这一段时间就避免了毛刺(glitch));
该电路中有三个时序路径需要特别考虑 - SELECT控制信号到两个负边沿触发触发器中的任何一个,DFF0输出到DFF1的输入,DFF1的输出到DFF0的输入。 如果这三条路径中的任何一条路径上的信号与目标触发器时钟的捕获边缘同时发生变化,则该寄存器的输出很可能变为亚稳态,这意味着它可能会进入理想的0和1两者之间的状态。
module GlitchFree(
input clk1,
input clk0,
input sel,
input rst_n,
output outclk
);
//----------------Part1-----------------//
//assign outclk = (sel==1)?clk1:clk0;
//----------------Part2-----------------// 这种情况下clk1 与 clk0 必须是倍数关系
reg out0;
reg out1;
always@(negedge clk1 or negedge rst_n) begin
if(!rst_n) begin
out1 <= 1'b0;
end
else begin
out1 <= ~out0 & sel;
end
end
always@(negedge clk0 or negedge rst_n) begin
if(!rst_n) begin
out0 <= 1'b0;
end
else begin
out0 <= ~sel & ~out1;
end
end
assign outclk = (out1 & clk1) | (out0 & clk0);
endmodule
针对无关时钟源的毛刺保护
先前避免时钟开关输出处的毛刺的方法需要两个时钟源彼此的倍数,使得用户可以避免信号与任一时钟域异步。在该实现中没有处理异步信号的机制。
这导致实现具有同步器电路的时钟开关的第二种方法,以避免由异步信号引起的潜在的亚稳态。当两个时钟源彼此完全无关时,异步行为的源可以是SELECT信号或从一个时钟域到另一个时钟域的反馈。
如图3所示,通过为每个时钟源添加一个额外级的正边沿触发触发器来提供针对亚稳态性的保护。每个选择路径中的正边沿触发触发器以及现有的负边沿触发触发器防止潜在的亚稳态性,这可能是由异步SELECT信号或从一个时钟域到另一个时钟域的异步反馈引起的。
同步器只是两级触发器,其中第一级通过锁定数据来帮助稳定数据,然后将数据传递到下一级;
再看上图时序图,在CLK0的第二个时钟上升沿,采样数据为SELECT为1,但是要等到时钟的下降沿才被输出,这时CLK0的传播到此结束;
module glitch_DFF (
input clk0,
input clk1,
input select,
input rst_n,
output clkout
);
wire B;
reg DFF3Q, DFF4Q, DFF4_Q; //DFF4Q=Q,DFF4_Q=~Q
wire A;
reg DFF1Q, DFF2Q, DFF2_Q; //DFF2Q=Q,DFF2_Q=~Q
assign A = select & DFF4_Q;
assign B = ~select & DFF2_Q;
//第一级触发器用上升沿采样,选择信号与反馈信号的与运算
always@(posedge clk1 or negedge rst_n) begin
if(~rst_n)
DFF1Q <= 0;
else
DFF1Q <= A;
end
//第二级触发器用下降沿采样
always@(negedge clk1 or negedge rst_n) begin
if(~rst_n) begin
DFF2Q <= 0;
DFF2_Q <= 1;
end
else begin
DFF2Q <= DFF1Q;
DFF2_Q <= ~DFF1Q;
end
end
//====================================================================
//第一级触发器用上升沿采样,选择信号与反馈信号的与运算
always@(posedge clk0 or negedge rst_n) begin
if(~rst_n)
DFF3Q <= 0;
else
DFF3Q <= B;
end
//第二级触发器用下降沿采样
always@(negedge clk0 or negedge rst_n) begin
if(~rst_n) begin
DFF4Q <= 0;
DFF4_Q <= 1;
end
else begin
DFF4Q <= DFF3Q;
DFF4_Q <= ~DFF3Q;
end
end
wire E, F;
assign E = clk1 & DFF2Q;
assign F = clk0 & DFF4Q;
assign clkout = E | F;
endmodule
在第三种异步时钟源切换电路中
DFF1和DFF3作用:在选择路径上插入一个上升沿触发器,用于缓存数据,将数据传递给下一级;若去掉,电路由于异步信号引起亚稳态
**DFF2和DFF4采用负沿采样原因**:SELECT与反馈输出相与,下降沿采样反馈可以保证一个时钟被完全取消选择后,输出采输出另一个式中,从而避免产生毛刺。
结论
纯组合逻辑时钟切换电路:电平相反时,切换时钟不可避免产生毛刺;
相关时钟切换:下降沿切换(反馈实现),下个上升沿切换生效,消除毛刺;
**无关时钟切换:**下降沿触发之前添加一个上升沿触发器,消除亚稳态;