在芯片运行时经常需要切换时钟源,通常的实现方式是利用二选一MUX。
这两个时钟在频率上可能完全不相关,也可能成倍数关系。不管是哪种情况,都有可能在开关门控时产生毛刺(Glitch)。
把无毛刺时钟切换和门控时钟结合起来看
1. MUX时钟切换
如图 1-1 中的时序图所示,当 SELECT 控制信号变化时,输出 OUT CLOCK 上产生了毛刺。这类门控开关的问题在于,SELECT 开关控制信号会在时钟源的任意电平位置发生变化,从而导致输出时钟截断或者产生毛刺。
不管是不是已知多个输入时钟源之间的频率或者相位关系,都不能这些时钟源的高电平状态下进行切换(任一个高电平都不行,即对图 1,必须在 2 个输入时钟源均为低电平的时候进行切换)
2. 相关时钟的无缝切换
Glitch protection for related clock sources
为了让SELECT控制信号只在时钟低电平时切换时钟,插入一个下降沿有效的 D 触发器。
一个时钟的选择反馈到了另一个时钟(两个 QN),这种反馈机制使得门控开关在选择输出下一个时钟之前,必须先取消当前时钟的输出选择,这样避免了任何可能出现的毛刺 Glitch。
SELECT=0,输出CLK0
SELECT变为1,Q0保持1,继续输出CLK0
直到原时钟源CLK0的下降沿到来时,Q0=0,CLK0被释放,DFF1的输入变1
直到CLK1的下降沿来临,Q1=1,开始输出CLK1
在这个电路中有 3 条时序路径需要特别考虑:
(1)SELECT 控制信号到任意一个下降沿有效的触发器 ;
(2)DFF0 的输出到 DFF1 的输入;
(3)DFF1 的输出到 DFF0 的输入。
如果这三条路径中的任一路径上的信号在目的寄存器时钟的捕获沿时发生变化,则寄存器的输出有一定的机会会进入亚稳态
因此,这就要求两个寄存器捕获沿和 对 SELECT 信号的发起沿分开,以避免任何可能的异步接口。由于两个时钟源的时序关系是已知的,所以上述可以通过使用恰当的多周期约束(multi-cylce hold)或者最小延时(minimun delay)约束来实现。(怎么约束?)
实现了无毛刺。可以通过时序约束避免同源时钟的亚稳态。
3. 不相关时钟的无缝切换
Glitch protection for unrelated clock sources
在前一种避免输出毛刺的门控选择方式中,要求两个输入时钟源的频率有倍数关系,这样使用者可以通过使用恰当的时序约束避免信号与任何一个时钟域异步。这种实现方式没有处理异步信号的机制。
当两个时钟源完全不相关时,异步行为可能来自 SELECT,也可能来自另一个时钟域的异步的反馈信号
如图 3-所示,对每个时钟源路径上,各增加一个该时钟源上升沿驱动的触发器来避免亚稳态。
input clk0,clk1,
input sel,
output clk_out
);
wire d0,d1;
reg l0,l1;//latch
reg q0,q1;
wire true_sel0,true_sel0;
assign d1 = sel & ln0;
assign d0 = ~sel & ln1;
always@(posedge clk0 or negedge rst_n) begin
if(!rst_n) q0 <= 'd0;
else q0 <= d0;
end
always@(posedge clk1 or negedge rst_n) begin
if(!rst_n) q1 <= 'd0;
else q1 <= d1;
end
always@(*) begin
if(!rst_n) begin l0<=0; ln0<=1; end
else if(!clk0) begin l0<=q0; ln0<=~q0; end
end
always@(*) begin
if(!rst_n) begin l1<=0; ln1<=1;end
else if(!clk1) begin l1<=q1; ln1<=~q1; end
end
assign true_sel0 = clk0 & l0;
assign true_sel1 = clk1 & l1;
assign clk_out = true_sel0 | true_sel1;