问题:
在多时钟设计中可能需要进行时钟的切换。由于时钟之间可能存在相位、频率等差异,直接切换时钟可能导致产生glitch。
组合逻辑实现时钟切换:
HDL代码:
module clock_mux( input clk0, clk1, input select, output out_clock ); assign out_clock = selsect ? clk1: clk0; endmodule
电路图:
波形图:
问题:
使用上述电路进行时钟切换会导致在控制信号sel附近出现glitch。其原因在于控制信号可以在任意时刻进行时钟切换,切换信号相对于两个时钟都是异步信号。
解决方法:
使用寄存器使得控制信号仅在时钟边沿作用,避免在任何时钟都为高电平是进行时钟切换。
适用于倍频时钟切换的时序逻辑电路
HDL代码:
module clock_mux( input clk0, clk1, input select, output out_clock ); reg q1; reg q0; always @(negedge clk1) q1 <= !q0 && selected always @(negedge clk0) q0 <= !q1 && ~select; assign out_clock = (clk1 && q1) || (clk0 && q0); endmodule
电路图:
波形图:
功能:
当切换的时钟存在倍频关系时,分别插入一个下降沿触发的触发器以确保控制信号仅在时钟低电平时起作用。
问题:
当DFF1输入的变化非常接近CLK1的下降沿时,可能会导致DFF1的亚稳态问题;DFF0同理。
为什么可以用于倍频时钟之间的切换?
异步时钟切换的时序电路
HDL代码:
module clock_mux( input clk0, clk1, input rst_n, input select, output out_clock ); reg inter0_p, inter0_n; reg inter1_p, inter1_n; always @(posedge clk0 or negedge rst_n) if(!rst_n) inter0_p <= 0; else inter0_p <= (select && !inter1_n); always @(negedge clk0 or negedge rst_n) if(!rst_n) inter0_n <= 0; else inter0_n <= inter0_p; always @(posedge clk1 or negedge rst_n) if(!rst_n) inter1_p <= 0; else inter1_p <= (select && !inter0_n); always @(negedge clk1 or negedge rst_n) if(!rst_n) inter1_n <= 0; else inter1_n <= inter1_p; assign out_clock = (clk0 && inter0_n) || (clk1 && inter1_n); endmodule
电路图:
波形图:
功能:
通过为每个时钟源添加一个额外级的正边沿触发触发器来提供针对亚稳态性的保护,CLK0的上升沿采样到信号到下降沿传递至CLK1的正边沿触发器,并在CLK0下降沿后CLK1第一个上升沿之后的下降沿输出。(不是很理解)