一、分频器
这一节研究的是:从一个快时钟做出一个慢时钟,分频比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%。
奇数分频要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和电源噪声,每个周期都不一样,只能当余量扣掉
周期1ns,skew 50ps、jitter 30ps,留给两个寄存器之间组合逻辑的只剩约920ps。
两者对时序检查的影响不同:
- skew影响setup和hold两头:目的寄存器的时钟比源寄存器晚到,setup多出一段余量,hold少一段
- jitter直接从周期里减,决定主频能跑多高
RTL仿真和formal都看不到这两个量,它们归STA和后端。前端能保证的是结构:门控使能只在时钟为低时变,跨时钟域的信号不依赖固定相位。
五、门控
时钟门控(ICG、直接AND的glitch、latch怎么挡)在《低功耗设计》「Clock Gating」,调压调频时时钟怎么处理在《低功耗设计》「DVFS」。
参考
- Wikipedia, Frequency divider
- Wikipedia, Duty cycle
- Rajesh Mahapatra, Techniques to make clock switching glitch free, EE Times, 2003
- Wikipedia, Phase-locked loop
- Wikipedia, Clock skew
- Wikipedia, Jitter
Discussion
Loading comments…
Checking sign-in…