[1]时钟无缝切换

本文详细介绍了时钟切换的两种方式:普通切换和无缝切换。普通切换简单且成本低,适用于非工作状态或全局复位的情况。无缝切换则确保切换过程中无毛刺,适合工作状态下的时钟源调整,如CPU频率动态调节。文章还提供了无缝切换电路的设计实例。
时钟切换分成两种方式,普通切换去毛刺无缝切换
普通切换,就是不关心切出的时钟是否存在毛刺,这种方式电路成本小。如果时钟切换时,使用此时钟的模块电路处于非工作状态,或者模块内电路被全局复位信号reset住的,即使切出毛刺也不会导致DFF误触发,这样的模块可以选择用此种切换方式。
写法很简单assign clk_o = sel_clkb ? clkb : clka ,当sel_clkb为 1 时选择clkb,否则选择clka。不过在实际设计中,建议直接调用库里的MUX单元set_dont_touch,不要采用这里的assign写法,因为这种写法最后综合得到的可能不是MUX而是复杂组合逻辑,给前后端流程的时钟约束和分析带来不便。
无缝切换,就是切换时无毛刺时钟平稳过渡。在时钟切换中,只要出现比clka或者clkb频率更高的窄脉冲,不论是窄的高电平还是窄的低电平,都叫时钟毛刺。工作在切换后时钟clk_o下的电路模块,综合约束是在max{clka,clkb}频率下的,也就是说设计最后signoff的时候,只保证电路可以稳定工作的最高频率是max{clka,clkb},如果切换中出现更高频的时钟毛刺,电路可能出现无法预知的结果而出错。无缝切换,一般用在处于工作状态的模块需要调频或者切换时钟源,比如内部系统总线,CPU等。你刚用手机打完游戏后马上关屏听音乐,这两种场景中,CPU在满足性能前提下为了控制功耗,其工作频率会动态地从很高调至较低,此时就可能是在CPU一直处于工作状态下,通过无缝切换时钟源头实现的。
在无缝切换电路中,切换信号sel_clkb可以是任意时钟域下的信号,包括但不限于clka或者clkb域,但是sel_clkb必须是一个DFF输出 信号;clka与clkb的频率大小相位关系可以任意。无缝切换需要解决两个问题:一是异步切换信号的跨时钟域同步问题,这里需要使用《Verilog基本电路设计之一》里的同步电路原理消除亚稳态;二是同步好了的切换信号与时钟信号如何做逻辑,才能实现无毛刺。

下面写出无缝切换电路的主体部分,忽略了内部信号的定义声明等。

module clk_switch (
                rst_n,
                clka,
                clkb,
                sel_clkb,
                clk_o
                );
always @ (posedge clka or negedge rst_n)
begin
    if (!rst_n) begin
        sel_clka_d0 <= 1'b0;
        sel_clka_d1 <= 1'b0;   
         end
    else begin
        sel_clka_d0 <= (~sel_clkb) & (~sel_clkb_dly3) ;
        sel_clka_d1 <= sel_clka_d0 ;
    end
end

// part2
//always @ (posedge clka_n or negedge rst_n)
always @ (posedge clka or negedge rst_n)
begin
    if (!rst_n) begin
        sel_clka_dly1 <= 1'b0;
        sel_clka_dly2 <= 1'b0;
        sel_clka_dly3 <= 1'b0;
    end
    else begin
        sel_clka_dly1 <= sel_clka_d1;
        sel_clka_dly2 <= sel_clka_dly1 ;
        sel_clka_dly3 <= sel_clka_dly2 ;
    end
end

// part3
//always @ (posedge clkb_n or negedge rst_n)
always @ (posedge clkb or negedge rst_n)
begin
    if (!rst_n) begin
        sel_clkb_d0 <= 1'b0;
        sel_clkb_d1 <= 1'b0;
    end
    else begin
        sel_clkb_d0 <= sel_clkb & (~sel_clka_dly3) ;
        sel_clkb_d1 <= sel_clkb_d0 ;
    end
end

// part4
//always @ (posedge clkb_n or negedge rst_n)
always @ (posedge clkb or negedge rst_n)
begin
    if (!rst_n) begin
        sel_clkb_dly1 <= 1'b0;
        sel_clkb_dly2 <= 1'b0;
        sel_clkb_dly3 <= 1'b0;
    end
    else begin
        sel_clkb_dly1 <= sel_clkb_d1   ;
        sel_clkb_dly2 <= sel_clkb_dly1 ;
        sel_clkb_dly3 <= sel_clkb_dly2 ;
    end
end

// part5
clk_gate_xxx clk_gate_a ( .CP(clka), .EN(sel_clka_dly3), .Q(clka_g)  .TE(1'b0) );
clk_gate_xxx clk_gate_b ( .CP(clkb), .EN(sel_clkb_dly3), .Q(clkb_g)  .TE(1'b0) );
//assign clka_g = clka & sel_clka_dly3 ;
//assign clkb_g = clkb & sel_clkb_dly3 ;
assign clk_o = clka_g | clkb_g ;
endmodule

上面是我认为比较合理的无缝切换电路,其他切换方式跟这个会有些许出入,但基本大同小异原理是一样的。
有几点说明:
  1. 抛开注释掉的电路不看,由于part5部分直接调用库里的clock gating cell,使得整个切换电路全部只需要用到时钟上升沿,无需额外定义反向时钟,精简了DC综合的时钟约束;直接调用gating cell的 另一个好处是,前后端工具会自动检查gating cell的CP信号与EN信号的setup/hold时间,使得gating后的Q时钟输出无毛刺尖峰。TE端可以根据实际需要接上scan测试模式信号。如果使用part5部分的gating cell实现,前面的part1,2,3,4全部替换成注释掉的反相时钟也是没有问题。
  2. part2和part4部分,具体需要多少级DFF,甚至完全不要也是可以的,这就回到了《Verilog基本电路设计之一》里讨论的到底多少级DFF消除亚稳态才算合理的问题。时钟频率很低可能无所谓,如果时钟频率达到GHz,这部分建议至少保留三级DFF,因为三级DFF延时也仅仅只有3ns的时间裕度。没必要为了省这么几个DFF降低电路可靠性,在复杂IP以及大型SOC系统中,你会发现多几十个DFF,面积上可以忽略,系统可靠性和稳定性才是首要的。
  3. 如果part5部分希望使用注释掉的两行“与”逻辑实现时钟gating,此时part1与part3使用正相或者反相时钟都可以,但是必须把part2和part4部分改为注释掉的反相时钟实现,目的是初步从RTL设计上避免“与”逻辑的毛刺,同时还需要后端配合,因为很多后端工具对时钟“与”逻辑的clock gating check未必会检查。用clk下降沿拍出的en信号,再跟clk做与逻辑得到的门控时钟,在RTL仿真阶段看到的一定不会有毛刺,但是布线完成后,如果clk相对en后移,那与逻辑得到的门控时钟就有毛刺了。这就是用与逻辑做门控的缺点,由于后端工具可能不会去检查这个与门的时序关系而导致出错。但直接调用库里的gating cell,工具天然就会去检查这个时序,免去人工确认的后顾之忧。









FPGA设计中,时钟切换是一项关键技术,用于实现动态时钟源选择和时钟域之间的安全转换。时钟切换技术主要关注如何避免由于异步信号引入的**亚稳态(metastability)问题**,同时确保系统在不同频率或相位的时钟之间平稳切换。 ### FPGA时钟切换的实现方法 1. **使用同步电路进行时钟切换** 为了避免异步信号导致的亚稳态,通常在时钟切换逻辑中引入同步器电路。同步器通过多级触发器对异步信号进行采样,从而降低亚稳态传播的风险。例如,在时钟选择信号(SELECT)或反馈信号来自不同时钟域的情况下,同步器可以有效抑制亚稳态[^2]。 一个典型的同步器结构如下: ```verilog module synchronizer ( input async_signal, input clk, output reg sync_signal ); reg [1:0] meta; always @(posedge clk) begin meta[0] <= async_signal; meta[1] <= meta[0]; sync_signal <= meta[1]; end endmodule ``` 2. **基于多路复用器(MUX)的时钟切换结构** FPGA中常用的时钟切换结构是使用多路复用器选择不同的时钟源。为了确保切换过程的稳定性,通常会在MUX控制信号路径上加入同步逻辑,以防止由于控制信号异步变化导致时钟切换过程中出现毛刺或竞争条件。 3. **时钟切换策略与状态机控制** 在复杂系统中,可以通过有限状态机(FSM)控制时钟切换流程,确保切换操作在特定条件下进行(如在时钟低电平期间切换),从而进一步降低毛刺和亚稳态风险。状态机可以检测当前时钟状态,并在合适的时机触发切换。 4. **使用FPGA原语(如BUFGMUX)** Xilinx等厂商提供的FPGA器件中,包含专门用于时钟切换的原语,如`BUFGMUX`。该原语支持两个时钟源之间的无缝切换,并具有内置的同步机制,适用于高可靠性场景。 ```verilog BUFGMUX my_mux ( .O(clk_out), // Clock output .I0(clk_primary), // Primary clock input .I1(clk_secondary), // Secondary clock input .S(sel_signal) // Select signal (synchronized) ); ``` 5. **时钟域交叉(CDC)处理** 当切换的两个时钟源属于不同时钟域时,除了时钟切换本身,还需处理跨时钟域的数据同步问题。通常采用异步FIFO、双触发同步器或多级握手协议来确保数据在不同域之间安全传输。 ### 设计注意事项 - **时钟源稳定性**:确保切换时钟源在切换前已稳定运行。 - **同步控制信号**:MUX的控制信号必须经过同步处理,以避免亚稳态。 - **时序约束**:在时序分析中需考虑时钟切换路径的延迟和建立/保持时间。 - **功耗优化**:非激活的时钟路径应关闭以减少动态功耗,尤其是在低功耗设计中。 ### 应用场景 - 动态频率调整(如节能模式) - 冗余时钟切换(提高系统可靠性) - 多时钟域系统中的时钟管理 - 高速接口时钟切换(如PCIe、DDR控制器)
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hyunnnnn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值