棋子 · 2021年05月20日

面试题分析 -- 时钟分频电路

老李这次又要来分析常考的面试题了,这次咱们聊聊时钟分频电路。这一类面试题很常见,难度其实不大,看了这一篇,老李保证你能够在面试中自如应付。

先说什么是时钟分频(clock divide),我们都知道现在的数字电路都是基于时钟的,因为要存储状态就需要时序逻辑,就必须要时钟clock。每个时钟就是一个在0和1之间周期变化的信号。那么我们在不同的场合可能需要不同的频率的时钟,很多时候我们可以在一个已有时钟的基础上对它进行分频操作,从而得出一个另外更低频率的时钟。我们把这样的电路叫做时钟分频电路,即clock divider。

好,先来看最简单的最常见的一个例子,2分频。假设给定输入时钟是100MHz,要求得到一个50MHz的时钟。

WeChat Image_20210520100151.png
2分频电路时序图

相信这个大家都知道该怎么做,我们把时序图画出来,即使你之前完全没有听说过clock divider,看着时序图也可以很快想出来。2分频的另外一个意思是,在clk\_out的1个周期内,clk\_in经过了2个周期(注意这个说法,之后我们还会用到,便于你理解)。在每次clk\_in的上升沿来临的时候,clk\_out翻转一下。所以电路很简单,只需要一个Flop加一个反相器即可。如果flop本身自带Q反端,那连反相器都可以省下来,如下图所示:

WeChat Image_20210520100211.png

那么有了2分频,那如果需要一个4分频电路,怎么办呢?很简单,给上面的clk\_out再接一个2分频电路呗,只要你一直2分下去,你就可以得到4分频,8分频,16分频,32分频。。。这种办法当然可以,但是里面有个隐含的缺陷,我们之后再说。

那么现在假设需求变一下,我们要求你输出一个6分频的电路,也就是在clk\_out的1个周期内,clk\_in经过了6个周期,那么你没有办法利用上面2分频级联的办法得到。那么要怎么做呢?更general的要求是,如果要求你做一个任意偶数的分频,要如何做呢?

我们还是先以4分频为例,看一下时序图

WeChat Image_20210520100250.png
4分频时序图

可以看出,要求是clk\_div4要保持2个clk\_src周期为高,2个clk\_src周期为低。自然而然,我们需要个计数器counter,counter 从0开始每个clk\_src的上升沿到来的时候加1,加到3后返回0,一直这样循环下去。然后我们clk\_div4就可以这样产生:当counter值为0,1的时候,clk\_div4为0, 当counter值为2,3的时候,clk\_div4为1。

这个可以推广到任意偶数倍2m的分频(假设m为自然数),做法就是利用一个counter从0到2m-1不停计数,当counter值为0-m-1的时候,输出0,当counter值为m到2m-1的时候,输出1。RTL code老李就不写了,留给大家自己做练习(注意,看到老李上面那样说0到m-1,千万不要用小于等于<=或者大于等于>=这类操作,最多用一个相等判断操作就行了)。

于是问题就来了,能不能做一个奇数倍分频的分频器呢?最小的奇数倍分频是3分频。这里我们要引入一个占空比(duty cycle)的概念。我们知道时钟是一段时间为1,一段时间为0,我们把为1的这段时间占整个周期时间的比叫做占空比。以我们上面看到的clk\_src为例,为1和为0的时间是相等的,也就是各占整个周期的一半,所以我们说占空比是50%。假设我们要做一个3分频,意思是clk\_out的一个周期内,clk\_src经过了3个周期。如果还要求50%占空比的话,那么clk\_out为1和为0持续的时间是clk\_src的1.5个周期,如下图clk\_div3所示:

WeChat Image_20210520100307.png
3分频时序图

可以看出,clk\_div3的一个沿对应上去是clk\_src的下降沿,不是上升沿!

那么我们还能直接用之前偶数分频的时候用counter计数来做吗?可以,但是需要一点技巧。如果我们只用上升沿触发的flop,那么我们只能得到上图中clk\_div3\_pos的波形。而要想在下降沿发生变化,我们只能用一个下降沿触发的flop,如上图的clk\_div3\_neg的波形。然后我们将两个再OR起来,就可以得到一个占空比50%的3分频了。RTL code老李这里就不放了,相信大家可以自己写出来。

讲到这里,我们可以说掌握了最基本的分频器做法,应付大多数公司的笔试题够了,但是其实分频器里面还有一些更加深入的知识点,下面才是真正的干货内容。

首先,我们上面提到的分频器都是基于flop的,也就是说输出clock是直接来自于flop的Q(偶数分频)或者来自于两个flop的Q之后再加一个OR门(奇数分频)。这样做分频的优缺点是什么呢?优点很明显,就是50%的占空比。但是由此带来的一些问题:

  1. 因为驱动clk\_out的flop是由clk\_src作为时钟的,那么这个flop的Q端变化相比于clk\_src有一个必不可少的clk-to-q延时

WeChat Image_20210520100322.jpg
clk-to-q延时

这个clk-to-q延时根据不同的工艺,值会不同。这个clk-to-q delay在做时钟树综合的时候是要考虑进去的。特别是如果你还期望clk\_src和clk\_out是同步的时钟,沿要对齐的话,在做clock tree的时候要给clk\_src的tree加一些buffer来弥补这个clk-to-q。而如果你是用了好几个分频器级联产生更低频率,那么每一级的分频器都会贡献一个clk-to-q延时,那么你需要平衡时钟的时候就需要插入更多的buffer,这部分buffer又占面积,又耗功耗,甚至可能导致时钟无法平衡。所以这是需要大家在设计的时候考虑进去的。

2. 奇数分频需要在两个flop之后再加一个组合逻辑门,这个组合逻辑门又会增加clk的delay,同时设计的时候要非常小心,否则可能出现毛刺。

那么有没有办法解决上面的问题呢?这个时候大家要思考一个问题:我们为什么需要50%占空比的时钟?我们真的需要50%占空比的时钟吗?

回顾一下我们的设计,对于绝大多数的flop,我们只需要用到时钟的上升沿触发,而并不会用到下降沿,甚至有的工艺库里面就不提供下降沿触发的flop。大家如果不信,可以看看你的设计,是不是几乎都是always\_ff @(posedge clk)。在这种情况下,只有上升沿和时钟频率有关系,什么时候来下降沿不重要!如果你能保证你的模块当中不存在下降沿触发的flop,那么50%的占空比不是必须的。这种情况下我们可以利用clock gater 来帮我们实现分频。

关于clock gating的基本介绍,大家可以看我之前的一篇推送。Clock Gating 技术解析 (一), 对于一个clock gater来说,都有一个时钟的使能端enable,当enable为1的时候,clock gater 是通的,会放过一个clk\_src的pulse。所以,利用clock gater来分频的思路其实也很简单,如果要N分频,就是在N个clk\_src周期内,只要使得clock gater使能1个周期即可。以3分频为例,时序图如下

WeChat Image_20210520100346.png

利用clock gating的3分频

我们依然需要一个counter,从0计数到N-1, 当counter值等于N-1(其实等于0到N-1的任意一个值都行)的时候,enable clock gater,enable只持续一个周期,这样就会产生一个pulse,pulse的宽度为clk\_src的半周期。电路图也非常简单,如下图所示

WeChat Image_20210520100406.png

利用clock gater的分频电路图

好处当然是不需要区分奇数分频还是偶数分频,counter始终都是在clk\_src的上升沿跳变的。

那么基于clock gater的分频器有什么好处呢?首先解决的问题就是上面flop based分频器clk-to-q延时大的问题。我们知道,clock gater里面是有一个latch,而latch是在下降沿被enable的,所以一个clock gater传递那个pusle的延时只是里面的那个AND门,这个delay通常要比clk-to-q要小很多。在时钟树上有一个clock gater对于时钟树综合(CTS)通常不是什么问题。

更大的好处是分频器的级联,我们可以把分频器设计成带有输入enable和输出enable的模块,如下图所示

WeChat Image_20210520100503.png

带有enable的clk divider

比如说我们已经有了一个2分频的clock divider,那么如果我们需要个4分频,可以再级联一个,如下图所示

WeChat Image_20210520100705.png
两级clock divider级联

这样做的好处在于clk\_src到clk\_div4依然只有一个clock gater的delay,其实不管你级联多少个,只要利用enable来级联,只有最后一级的clock divider会引入一个clock gater延时,而不是累计的,而且每一级的输出分频clock 都各自对clk\_src只有一个clock gater delay,也就是说它们彼此之间几乎是已经balance的,这对时钟树综合大有帮助。还有一个好处就是clock gater的输出可以保证没有glitch。

好,那么我们再进阶继续问下去,我们前面讨论的都是整数倍的分频,也就是2,3,4....这样分频下去,那么如果我想从一个3MHz的时钟得到一个2MHz的时钟,即1.5倍分频,要怎么做呢?

首先我们来看1.5倍分频长什么样,时序图如下

WeChat Image_20210520100736.png

1.5倍分频50% duty cycle 的时序图

那么大家思考一下,只用数字电路里面基本的这些逻辑门和flop,我们能够做到上面的时序吗?

答案是做不到,注意红圈标出来的地方,clk\_div1p5要发生变化,但是clk\_src那一时刻既没有上升沿,也没有下降沿,而我们数字电路是基于时钟沿触发的,在没有时钟沿的地方我们就无能为力了(如果我们非要达到50%的占空比,需要借助锁相环PLL的帮助了)。

那么如果我们把条件放宽一些,如果不要求50%的占空比,我们可以做到吗?答案是可以,1.5倍分频,换句话说,就是3个clk\_src周期内,有2个clk\_div1p5周期,如果基于clock gater做,无非就是在3个clk\_src周期里,让clock gater enable 2个周期,放过去2个pulse就行了。时序图如下

WeChat Image_20210520100748.png
利用clock gater 1.5分频

看起来很简单吧,但是这里面有几个需要注意的点:

  1. 如果上面clk\_src是3MHz, 我们其实并没有做出严格意义上的2MHz 的clock。注意上面图中前两个上升沿,它们之间的时间间隔是1个clk\_src周期,而不是1.5个clk\_src周期!所以在STA分析的时候,clk\_div1p5的cycle还是要按照3MHz来。
  2. 我们虽然可以看到似乎整体上是3个clk\_src周期里,有两个clk\_div1p5的2个pulse,但是并不是任意3个连续的clk\_src周期里,你都能看到2个pulse,比如红圈里面的3个周期,你其实只能看到1个clk\_div1p5的pulse。这在整数分频里是不存在这个问题的。

上面两个注意的点就会引出我们接下来要思考的问题,假设这次以2.5倍分频为例,即5个周期里产生2个pulse,那么我们要在哪两个周期里面产生pulse呢?有下面几种方式

WeChat Image_20210520101604.png
2.5倍分频时序图

分别对应

clk\_1: counter在4和0的时候enable clock gater

clk\_2: counter在4和1的时候enable clock gater

clk\_3: counter在4和2的时候enable clock gater

clk\_4: counter在4和3的时候enable clock gater

这几种方式都实现了5个周期里产生2个pulse,那么请问大家,以上哪一个你觉得对时钟来说更好呢?

老李觉得是clk\_2和clk\_3要比另外两个好。为什么呢?因为pulse的间隔比较均匀,clk\_1和clk\_4中最近的两个pulse其实是挨着的,那么STA里面虽然进行了2.5分频,但是你还是要按照分频前的周期来进行约束。而clk\_2和clk\_3,它们最近的两个pulse至少间隔了2个周期,这样你可以按照clk\_src周期的两倍来进行约束,timing要容易close一些。

所以对于非整数的分频,我们其实要找这么一种解决办法,就是要让输出时钟的pulse间隔尽可能均匀,这才是时钟分频器里最难的考点。

我们知道,任何有理数都可以表示为一个分数,分子分母都为整数。那么我们把问题扩展为:设计一个M/N的分频器,M, N互质,要求是在N个clk\_src周期内产生M个pulse,且这M个pulse尽可能均匀分布。为什么要求互质?因为不互质你就可以约分为互质的M/N。

回到上面的例子,我们设计一个2.5倍分频器,即M=2,N=5, 如何做呢?思路是counter不能再在每个时钟沿加1了,而是要按照一个巧妙的方式进行加,并循环。如下图所示

WeChat Image_20210520102112.png

均匀分布2.5分频

这里counter加的办法是,每次加2,如果counter值+2后大于等于5,那么就减掉5,之后再每次加2。这样counter值就是上面的0,2,4,1,3进行循环。在什么时候enable clock gater呢,就是在每次要减5的那个周期,就是在counter等于4和3的周期enable,这样我们就可以得到相对均匀的clock。

推广一下,对于M/N分频,假设counter初始值为0,counter的变化规则为

  1. 如果counter当前值加M大于等于N,则下个周期counter值为当前值+M-N
  2. 否则,counter值加M。

在当counter当前值加M大于等于N的周期enable clock,输出pulse。

大家可以自己验算一下,比如以2/7为例,看是否达到了均匀pulse的效果。

作者:硅谷老李
来源:https://mp.weixin.qq.com/s/WMInkw2fXjL9WQVcb1kkng

相关文章推荐

更多IC设计技术干货请关注IC设计技术专栏。
推荐阅读
关注数
20648
内容数
1316
主要交流IC以及SoC设计流程相关的技术和知识
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息