CDC(Clock Domain Crossing,时钟穿越)有很多的论文都讨论过这个主题。本文主要从原理上分析一下为什么CDC是问题、常用的CDC设计思路。不能算权威总结,只是对工作几年CDC设计的经验的一个总结。
源起:建立时间和保持时间
集成电路设计专业的同学期末考试肯定考过“setup time"或者”hold time"的定义,这个也是应届毕业生面试数字集成电路设计岗位的“明牌”必面题目。
先回顾一下setup time(建立时间)和hold time (保持时间)的定义:
建立时间(tsu) 是在时钟翻转(对于正沿触发寄存器为0→1的翻转)之前数据输入(D)必须有效的时间。
维持时间(thold)是在时钟边沿之后数据输入必须仍然有效的时间。
(有教材的回去复习下:参考《数字集成电路——电路系统与设计(第二版)》P237)
对于单一时钟的电路进行时序分析,最主要是为了满足这些条件。
比如,说你的设计时序“很紧张”,往往是两级寄存器之间的组合逻辑很多,延时很长。从上一级的数据传到下一级时,无法满足下一级的建立时间。我们这个时候需要做时序修复(timing fix)。
单时钟这个问题比较好考虑,因为数据什么时候开始发送是明确的——上一个时钟沿——我们能够有很多办法去修复时序。(比如前文推送的“模板”)
但对于多时钟设计(异步电路),从一个时钟域向另一个时钟域送数据,时钟(周期)不同,在一个时钟域随时随刻都可能收到另外时钟域的数据,这自然是不能满足建立时间的。
不满足建立时间,那么数据的传输就会失败。何谓“失败”?就是我想传一个数据1过去,我可能成功的传了个1,也可能传了个0,也可能我不知道传了什么值。
不满足建立时间,简单的理解就是:目标时钟域(dest. clock) 的时钟沿和发起时钟域的数据(src. clock)来的时间很接近,而时钟沿和数据的谁先谁后错开一点,传输到下一级的数据就是完全不一样,这种不同这是不可接受的。
因为不满足建立时间,我的数据是不稳的、不可预知的、不精确的。对于单个寄存器而言,我们叫做亚稳态(Metastability)。
总结一下:在数据从一个时钟域向另一个时钟域传输时,无法满足建立时间,数据在被目标时钟域寄存器采值时,会进入亚稳态,无法准确传输数据。
我们用时钟穿越(CDC,Clock Domain Crossing)来描述我们现在处理的这种情况。把所有的这种问题都叫做时钟穿越问题(CDC issue)。
随着工艺技术的迭代,很多的公司的集成电路项目出现错误,都是出现在CDC的解决方法有问题,或者验证不够充分上。
本章节先讨论1比特的情况。(在下一章节会讨论多比特的情况。)
那如何解决“1bit的时钟穿越”问题呢?
既然根子上是亚稳态的问题,那我就破掉亚稳态。
破掉亚稳态有很多种方法,方法都是让数据来到目标时钟域的时钟沿之前稳定住。
延长源信号的方法(不推荐):
我要传输1,那我就在源时钟域对信号1持续上拉;我要传输0,那我就在源时钟域对信号0持续下拉。换句话说,就是让想传的数据1和0都维持“足够长”的时间——长到我这个时钟沿采不到,下个时钟沿肯定能采到。
这就是我们看很多年前"老代码"中很普遍的方法:延长源信号长度。比如对源信号连续打多少拍,然后“或”起来组成一个信号使用。
或者干脆不做任何处理直接穿越,前提是能够证明虽然这个信号是一个CDC信号,但是不会轻易改变(比如寄存器初始化之后的一个控制信号,只会在初始化阶段改变)。
延长源信号方法总结:
- 很多老的设计是直接CDC使用,或者打多拍然后进行传输。
- 优点:简单,逻辑比较少
- 缺点:
3.1.如果源信号的前提假设发生变化,容易出现bug。如第二代设计的时钟频率比变化,或者一个不轻易改变的配置信号(control signal)“与”上了一个经常变的控制信号。不经过仔细验证,维持原有设计,很容易出“大“问题。
3.2.逻辑虽然简单,但是设计不具有通用性。比如你需要对不同时钟频率比例的进行不同的打拍。 - 所有可以用“延长源信号”方法的地方,都可以加上同步器(syncer)逻辑,这更加保险。
- 总结:除非维护不好修改的历史代码,新代码不推荐。
同步器(synchronizer, syncer)
那破掉亚稳态还有什么办法呢?
方法很简单,就是在目标时钟域加速稳定过程。
D触发器是一个简单的加速稳定的简单结构。虽然1级D触发器,可能不满足建立时间,但是后面再跟一个D触发器,就会使不稳态要么迅速变化为传输0,要么迅速变化为传输1。
两级D触发器的串联,就是一个简单的同步器(synchronizer, 或者syncer,或者Sync2D)。
A synchronizer is a device that samples an asynchronous signal and outputs a version of the signal that has transitions synchronized to a local or sample clock."
这种稳定是概率性的,与工艺相关的。稳定下来而不是处于亚稳态的时间,有数学上的MTBF(平均失败时间)公式进行计算。在日常的设计中,一般工艺厂会告知你的一个参数公式(或者是一个查找表),输入你的输入输出频率,就能查找到在当前工艺下的MTBF,然后比对MTBF的要求决定是不是选择SYNC2D(打两拍的同步器)。
如果SYNC2D不满足MTBF的要求,那么就再接一级D触发器,组成SYNC3D(打三拍的同步器)。SYNC3D的MTBF比SYNC2D会长许多数量级。(我在前东家做一个设计,同样的时钟频率,查MTBF表SYCN2D的MTBF是10天,SYNC3D的平均失败时间是50年……)
我在过去做14nm工艺下的设计,项目主管就要求所有的SYNC2D替换为SYNC3D。
我们这里暂时用SYNC2D作为例子(SYNC3D同理)。
同步器有什么好处?
能够安全的排除亚稳态。
同步器有什么坏处或者局限?
目的时钟域会晚几个周期。
这个不算是个问题,既然是跨时钟域的,晚两三个周期没什么问题。
数据传过来,对SYNC2D而言,会delay2个周期或者3个周期。也就是说你不能确定是2个周期后还是3个周期后能传过目标数据来。对于单比特没有问题,对于多比特存在对齐的问题。 同步器只能保证数据没有亚稳态,不能保证是正确数据。
怎么理解呢?就是说,你给我同步器什么数据,我都能给你稳住。但是你若给我的是错误的值,这不能怨我。
例如,在这个周期给同步器输入端一个信号1,同步器在能给你稳到0或者1,你只要在发送端的下个周期还给同步器1就好了。经过同步器一走,给个干净的1给你。
clka __/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯
clkb _/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___
sig_a __/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
sig_b _________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
但是,如果这个周期你喂给了同步器了一个信号1,下个周期喂给了同步器个0,这种情况,同步器只能给你稳下来,并不能给你稳到一个你确定的值。因为你变了,同步器也不知道该是0还是1,这超出了同步器的能力范围。
clka __/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯\__/¯¯
clkb _/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___/¯¯¯\___
sig_a __/¯¯¯¯¯¯\_______________________________
sig_b_1 _________________________________________
sig_b_2 _________________________/¯¯¯¯¯¯¯¯\______
同步器的正确前提是,信号必须稳定足够长的时间(能够持续上拉,或者下拉)。
那么多长算长呢?前人理论已经有了研究结论了。在同步器设计理论中,叫做”1.5x规则“或者”三沿规则“:输入端的信号长度,至少是1.5倍接收时钟周期的长度,或者三个接收时钟沿的长度。(可以参考下Clifford E. Cummings 的 Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog第4.1节)
满足了这个规则,因为是三个边沿,那么肯定会有一个安全的上升沿可以采到。
这是非常重要的一个规则。只要满足了这一规则,同步器就是安全的。
使用同步器本身,可能会漏采或者多采。
其实这只是上一个要点的延伸。同步器是一个稳定单元,只能做到”稳“,你需要“稳+准”,这超出了同步器的能力范围,需要加上一些配合电路才能工作。但几乎所有的CDC电路在时钟穿越的核心逻辑,同步器都包含其中。
后续章节预告:
同步器可以直接安全传输多比特吗?
多比特传输一:四段握手与两段握手
多比特传输二——背靠背:异步FIFO简介
异步设计总体思路流程
常见异步错误与修复
对本文感兴趣的,或者很多地方不理解的,可以参考下下面的一篇论文:
Clifford E. Cummings,Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog
作者:孟祥志
来源:https://mp.weixin.qq.com/s/frYy7LA5\_QbtPuvEhV8LzA
作者微信公众号
相关文章推荐
更多IC设计技术干货请关注IC设计技术专栏。