Skip to content

时钟电路

Clock Rewritten
Contents

一、分频器

这一节研究的是:从一个快时钟做出一个慢时钟,分频比N是奇数时怎么做到50%的占空比。

1. 什么时候分频

分频是把时钟周期变成原来的N倍,N叫分频比。主时钟400MHz、总线只要100MHz,就是四分频:总线不需要跑主频,慢一点省时钟网络的功耗,挂在上面的模块也只按低速设计。

分频器是一个计数器:数输入时钟的沿,数够了就翻一次输出。

2. 偶数分频

N是偶数时只数上升沿:每N/2个上升沿翻一次输出。二分频就是每个上升沿翻一次。

// 二分频:每个上升沿翻一次
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n) div2 <= 1'b0;
  else        div2 <= ~div2;

// 偶数N分频:数到N/2翻一次
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n)                begin cnt <= '0;      divN <= 1'b0;  end
  else if (cnt == N/2 - 1)   begin cnt <= '0;      divN <= ~divN; end
  else                             cnt <= cnt + 1'b1;

div2的周期是输入的2倍,高一个输入周期、低一个输入周期,正好50%。

3. 奇数分频的50%问题

占空比是一个周期里高电平占的比例,50%是高一半、低一半。要50%,是因为下游两个电平都要用够长:latch型的ICG在时钟低电平开门、高电平锁住(《低功耗设计》「ICG单元」),哪一边太短,使能就来不及建立。

只数上升沿时,输出只在上升沿翻,高电平的长度只能是整数个输入周期。三分频的周期是3个输入周期,50%要高1.5个,整数给不出。

只用上升沿做出来的三分频p,高2个周期、低1个周期,占空比2/3。

4. 双沿法三分频

双沿是上升沿和下降沿都用。下降沿落在输入周期的正中间,它能提供「半个周期」:

  • p:上升沿数,高2低1
  • n:在下降沿采p,等于p推迟半个周期
  • clk_div3 = p & n:两路重叠的部分正好高1.5个周期
logic [1:0] cnt;
logic       p, n;

always_ff @(posedge clk or negedge rst_n)          // 0 1 2 循环
  if (!rst_n) cnt <= 2'd0;
  else        cnt <= (cnt == 2'd2) ? 2'd0 : cnt + 2'd1;

always_ff @(posedge clk or negedge rst_n)          // 上升沿那路:cnt为0、1时高,为2时低
  if (!rst_n) p <= 1'b0;
  else        p <= (cnt != 2'd2);

always_ff @(negedge clk or negedge rst_n)          // 下降沿那路:p推迟半拍
  if (!rst_n) n <= 1'b0;
  else        n <= p;

assign clk_div3 = p & n;

clk_div3高1.5个周期、低1.5个周期,占空比50%。

Important

奇数分频要50%,高电平是x.5个周期,只有下降沿能给出那0.5,所以要双沿。偶数分频只数上升沿就够。

5. 分频器怎么验

时钟当数据:用一个比输入还快的参考时钟采样clk和clk_div3,在参考时钟上数沿。分频比对,就是clk_div3相邻两个上升沿之间clk恰好3个上升沿;占空比对,就是clk_div3高电平和低电平各持续同样多的参考拍。写法见《Formal Verification》「时钟当数据」。

二、无毛刺时钟切换

这一节研究的是:在两个时钟之间切换,输出时钟怎么保证没有glitch。

1. 直接用MUX切的问题

两个时钟clk_a、clk_b异步,用一个MUX按sel选一个输出:

assign out = sel ? clk_b : clk_a;   // 有glitch的写法

sel变化的时刻跟两个时钟都没有关系,可能正落在clk_a的高电平中间,这个高电平被截短,out上多出一个窄脉冲,也就是时钟上的glitch,下游寄存器会多采一次。

sel在clk_a的一个高电平中间切到b,out上那个高电平只剩四分之一个周期。

2. 电路

每个时钟一条支路,输出是两条支路相或:

  • 每条支路一个使能触发器,在自己时钟的下降沿触发,输出en_a、en_b
  • 每条支路一个AND:clk_a & en_a、clk_b & en_b;两个AND进一个OR,就是clk_out
  • 交叉:en_a的D端条件是「sel选a,并且en_b同步到a域后为0」,en_b对称;对方的使能在本域过两级同步器
module clk_mux_glitch_free (
  input  logic clk_a, clk_b,
  input  logic rst_n,
  input  logic sel,          // 0选a,1选b
  output logic clk_out
);
  logic       en_a, en_b;    // 两路使能,各在自己时钟的下降沿翻
  logic [1:0] sync_a, sync_b; // 对方的使能同步到本域,两级

  // en_b同步到a域。复位值跟en_b的复位值一致(0)
  always_ff @(posedge clk_a or negedge rst_n)
    if (!rst_n) sync_a <= 2'b00;
    else        sync_a <= {sync_a[0], en_b};

  // en_a同步到b域。复位值跟en_a的复位值一致(1)
  always_ff @(posedge clk_b or negedge rst_n)
    if (!rst_n) sync_b <= 2'b11;
    else        sync_b <= {sync_b[0], en_a};

  // 使能在下降沿翻:选中本路、且对方已经关了,才打开
  always_ff @(negedge clk_a or negedge rst_n)
    if (!rst_n) en_a <= 1'b1;                 // 复位后默认走a
    else        en_a <= ~sel & ~sync_a[1];

  always_ff @(negedge clk_b or negedge rst_n)
    if (!rst_n) en_b <= 1'b0;
    else        en_b <= sel & ~sync_b[1];

  assign clk_out = (clk_a & en_a) | (clk_b & en_b);
endmodule

在下降沿翻使能,和ICG用latch是同一个道理:使能只在那一路时钟为低的时候变,AND不会截断高电平。交叉是让两条支路互相把对方关闭当作自己打开的条件,任何时刻最多一路打开。

同步器的复位值要跟被同步的信号一致

en_a复位后是1,sync_b就要复位成11;否则复位刚释放时sync_b还是00,en_b以为a已经关了,两路同时打开。

3. 切换过程

从a切到b:

  • sel变成1,en_a的D端条件不成立,在clk_a的下一个下降沿en_a变0,a支路输出停在低电平
  • en_a为0过两拍同步到b域,sync_b变成00
  • en_b的D端条件成立,在clk_b的下一个下降沿en_b变1,b支路开始输出

中间有一段两路都关、clk_out为低的空档,这是正常的;代价是一次切换要花新旧时钟各几个周期。

4. 前提:两个时钟都在跑

切换时新旧时钟都得在跑。旧时钟要是停在高电平,它的下降沿不再来,使能关不掉,输出卡在高电平。有的设计用新时钟数一个超时,判定旧时钟停了以后,再异步地把旧支路的使能清掉。

三、PLL与上电顺序

这一节研究的是:主时钟从哪来,上电时时钟和复位按什么顺序起来。

PLL把参考时钟倍频成主时钟,例如50MHz的晶振倍到400MHz。从上电到输出频率稳定要一段锁定时间,用lock信号表示,锁定之前输出不能送给下游。lock是模拟电路出来的异步信号,进数字逻辑前要过两级同步器,再去抖。

上电顺序:

  • 复位先拉住
  • 配PLL,等lock
  • lock之前下游的时钟门控住,或者先走旁路的参考时钟
  • 时钟稳定地跑够若干周期再撤复位,因为复位同步器要靠时钟沿才能释放
  • 各时钟域按依赖顺序出复位:总线先出,挂在总线上的模块后出,避免一方在发请求、另一方还在复位里

这些顺序写成assertion就能查,例如lock之前门控使能必须为0:

assert property (@(posedge ref_clk) !pll_lock |-> !clk_en);

用formal证的时候要从上电的任意初值开始,不能让工具先用复位把寄存器清干净,否则「复位生效之前」那段状态就被跳过了。

四、Jitter与Skew

这一节研究的是:时钟沿在时间上的两种误差,各从哪来、各吃掉多少时序余量。

  • skew:同一个时钟沿到达不同寄存器的时间差,来自时钟树上各条路径的长度和负载不一样。它是确定的,CTS(clock tree synthesis,时钟树综合)能平衡
  • jitter:同一个时钟沿自己在时间上的随机抖动,来自PLL和电源噪声,每个周期都不一样,只能当余量扣掉
1GHz的时钟

周期1ns,skew 50ps、jitter 30ps,留给两个寄存器之间组合逻辑的只剩约920ps。

两者对时序检查的影响不同:

  • skew影响setup和hold两头:目的寄存器的时钟比源寄存器晚到,setup多出一段余量,hold少一段
  • jitter直接从周期里减,决定主频能跑多高

RTL仿真和formal都看不到这两个量,它们归STA和后端。前端能保证的是结构:门控使能只在时钟为低时变,跨时钟域的信号不依赖固定相位。

五、门控

时钟门控(ICG、直接AND的glitch、latch怎么挡)在《低功耗设计》「Clock Gating」,调压调频时时钟怎么处理在《低功耗设计》「DVFS」。

参考

Discussion

Loading comments…

Checking sign-in…