1.有毛刺的时钟切换电路
assign outclk = (clk1 & select) | (~select & clk0);
这个时钟切换电路是一个纯组合逻辑,输出时钟(OUT CLOCK)由选择信号(SELECT)控制,当SELECT为1时输出CLK1,反之,输出CLK0.
2.相关时钟源的毛刺保护
下图显示了防止
源时钟相互倍数的时钟
开关输出出现毛刺的解决方案。在每个时钟源的选择路径中插入一个
负边沿触发的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两者之间的状态。
reg out1;
reg out0;
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= ~out0 & select;
end
end
always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= ~select & ~out1;
end
end
assign outclk = (out1 & clk1) | (out0 & clk0);
3.
针对无关时钟源的毛刺保护
先前避免时钟开关输出处的毛刺的方法需要两个时钟源彼此的倍数,使得用户可以避免信号与任一时钟域异步。在该实现中没有处理异步信号的机制。
这导致实现具有同步器电路的时钟开关的第二种方法,以避免由异步信号引起的潜在的亚稳态。当两个时钟源彼此完全无关时,异步行为的源可以是SELECT信号或从一个时钟域到另一个时钟域的反馈。
如图所示,
通过为每个时钟源添加一个额外级的正边沿触发触发器来提供针对亚稳态性的保护
。每个选择路径中的正边沿触发触发器以及现有的负边沿触发触发器防止潜在的亚稳态性,这可能是由异步SELECT信号或从一个时钟域到另一个时钟域的异步反馈引起的。
同步器只是
两级触发器
,其中第一级通过锁定数据来帮助稳定数据,然后将数据传递到下一级;
再看上图时序图,在CLK0的第二个时钟上升沿,采样数据为SELECT为1,但是要等到时钟的下降沿才被输出,这时CLK0的传播到此结束;
reg out_r1;
reg out1;
reg out_r0;
reg out0;
always @(posedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r1 <= 0;
end
else begin
out_r1 <= ~out0 & select;
end
end
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= out_r1;
end
end
always @(posedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out_r0 <= 0;
end
else begin
out_r0 <= ~select & ~out1;
end
end
always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= out_r0;
end
end
assign outclk = (out1 & clk1) | (out0 & clk0);