以下是自己看完之后的一些心得;
-
两次平均出现亚稳态的间隔时间大于使用寿命;
-
采样频率、数据变化速率越快,MTBF(mean time between failure,两次失效之间的平均时间)越小;
-
打两拍已经大大减少了亚稳态出现的概率,但由于工艺等的不确定,最多打三拍,目前设计中还不需要使用到打四拍(没必要);
-
时钟信号间用打拍进行同步,需要确保传输信号能被采样时钟正确采样,主要是目的钟踩不到问题,或多次踩问题;
-
ack/req握手机制;
-
信号传输不可以组合逻辑输出,要寄存器输出,防止组合逻辑的毛刺信号影响打三拍或打两拍的效果;或者说可能使得打两拍变成打一拍,打三拍变打两拍的极端效果;
-
pluse信号的传输一般是拿来去set或clr寄存器或计数器的使能信号;
-
pluse信号一般传输的话希望传输到目的钟后,该信号也是个一个时钟周期的脉冲;
- 解决方法一般是,源时钟将该脉冲进行展宽传输,目的中接收到该信号后,进行取沿;
-
进行多bit信号同步之前可以思考下是否真的需要将多bit信号进行同步,可不可以将该多bit信号在源时钟下进行组合逻辑之后,只进行1bit信号的同步;(因为同步过程中信号到达目的钟的时刻不确定可能导致多bit信号的很多意料之外的组合,单bit同步没有这么多问题);
-
多bit信号同步使用dmux方法;
-
多bit信号传输也可以在dst钟进行判断,若信号在3拍内没有变化则认为数据稳定了,但要求是src数据不可频繁变动;(3拍是个可变值);
-
gray码;1.每相邻两位只有1位不同;2.当第N位从0变到1的时候,之后的数的N-1位会关于前半段轴对称,而比N位高的位是相同的。
-
gray码确定了src到dst后,dst获取到的都是稳定的;(要么是变化前的值,要么是变化后的值,不存在二进制传输导致意外的状态)
-
gray码用作fifo空满判断是有规律的,可以不用转二进制判断,具体规则可需要再查;
-
gray码进行同步的一个问题;慢时钟域同步快时钟域格雷码时候,在慢时钟域的一个周期中,经历了两次或多次快时钟域的上升沿,那么对应的格雷码就会有两个或多个bits发生变化,这个不会产生多个bits同步的问题吗? 答:该多bit变化是针对src钟的,dst钟每次最多也就只能看到1bit变化;
-
异步fifo由于写地址,读写地址的传递会有延时,会导致 假满,空满 情况;
-
CDC流程如下:
- 多bit信号进行同步,在目的钟进行逻辑运算需考虑全面,因为信号同步过程可能出现意外组合;如在src钟下,a=0,b=0同时跳变到11;目的钟同步过程可能出现2’b10,2’b01情况,最后才会变到2’b11;
- CDC若A到B进行了同步,A到C也进行了同步,但其实B与C是同步模块,那其实有个同步就是多余的;(害,有时候不同步不行,同步多了也不行),多次同步一个是浪费资源,另外一个是同步的随机性可能导致同步到B和C的时机点不对应;
- 进行同步信号必须是src时钟域的寄存器输出,若是组合逻辑输出则可能出现毛刺的问题;
CDC工程心得
设计前三思:确实需要跨时钟域吗?
我们在设计之前,其实要问自己,这一个功能我能不能不跨时钟域就实现呢?或者仔细想一想能不能将逻辑简化呢?比如可以将多bit信号简化为单bit信号再同步来省下一些synchronizer, 还要注意看是不是在别的地方已经对相关的信号进行了同步来避免coherency的问题。提前想好为什么要跨时钟域并进行恰当的设计,要远比在设计后期来一个一个去修CDC的问题要有价值的多。
-
一个module包含一个clock domain
在设计时,尽量把相同时钟域的逻辑放在同一个module内,这样对这个module可以认为是synchronous的设计。老李比较喜欢把所有的synchronization logic放在一个单独的module里,这样做的好处就是CDC的分界很清晰,以后debug以及修cdc的问题就只需要改这一个module了。
-
同步时不能根据source clock的频率和destination clock的频率关系来同步,而是要假定它们之间的关系是任意的。这样才能保证设计的健壮性和鲁棒性。
-
要例化已经验证过的CDC synchronizer library,比如2flop synchronizer, pulse synchronizer, async FIFO等等,成熟有一定积累的设计公司都已经有这些模块,在你的设计里直接例化它们,千万不要自己在RTL去造轮子。使用这些library对于其他flow来说也有帮助,比如说STA检查中可以直接将synchronizer上的path设为timing的false path,这个时候可以直接利用synchronizer的module name把这些cell找出来,非常方便。
-
所有的IP的output必须来自一个register,禁止将组合逻辑的输出当做IP的输出。
-
一个信号同步到另外一个时钟域只能同步一次,禁止同步多次,否则会有coherency的问题。
-
将要跨时钟域的信号标记上clk,要选择个统一的naming style。比如req_aclk, req_pclk分别表示req信号在aclk和在pclk,这样可以使得code清晰可读。
-
在功能仿真验证中,test bench要对2flop synchronizer来deposit随机的值,来模拟flop在产生metasability之后可能稳定在0,也可能稳定在1,用这种方法能够发现一些隐藏得很深的bug。
-
对于异步的时钟,在testbench里要使它们的沿要错开,而不要让他们的沿对齐。特别是有的时候两个clock的频率相同,但是如果它们是异步的,更要让沿错开,或者说要随机化它们之间的相位差。
-
在Spyglass CDC的check中
-
要首先fix所有的setup error,之后再看CDC violation。因为很可能CDC的violation是由于设置不正确造成的。
-
当有大量的相似的CDC error出现时,要考虑是不是setup没有设置正确,比如clock定义错误,quasi_static没有define等等。
-
能从设计上修改最好,尽量减少cdc的waiver。
-
不要相信tool给你找的qualifier,要么你自己指定qualifier,要么把tool帮你找到的qualifier从而认为path没有问题当做是有问题来进行分析。
-
不要waive Ac_unsync01/02的violation,一定要从design上来fix。
-
如果不打算fix design,那么也不要用waiver,考虑下面几种办法
-
set_case_analysis: 这样tool就只分析当这个信号固定在0或1的情形,通常我们会把MUX的选择端固定在某个值来去反映实际运行时的情况。
-
quasi_static: 这样tool就会认为这个信号是不会toggle的
-
qualifier: tool可以利用这个quailifer来去看multi-bit的signal是不是被这个qualifier来控制住从而不产生metastable。
-
cdc_false_path: 如果并不存在这样的functional path,比如一个信号去了DFT的逻辑但没有被synchronize。
-
当然要慎重使用quasi_static, cdc_false_path, set_case_analysis,除非你有充足的理由。
-
对于较大的SoC,如果直接对整个design来跑CDC可能需要很长时间,而且最后产生的violation太多,非常不便于debug,这个时候可以考虑利用hierarchical flow。
-
对一些小一些的模块先进行spyglass cdc check,把violation都清干净之后产生出一个abstract model。abstract model其实就是一个sgdc file,它描述了这个模块的CDC相关的所有信息,比如所有的input output port是在哪个clock domain上的,是combo的输出还是flop的输出等等。Abstract model还包含了这个模块的waiver。
-
在上层模块run cdc的时候读入下层的abstract model,好处就是可以节省run time,同时下层模块内部的violation也不会报出来,这样可以使得最终的report可读性比较好。
-
当然abstract model也不是万能的,有的时候甚至会掩盖掉一些真正的问题,所以使用abstract model时要谨慎。
以下事我看的文章,学习到很多,每次看都会有不同的收获;
干货大放送之CDC工程经验总结–CDC的那些事(7)完结篇 - 知乎 (zhihu.com) 这篇更注重实际操作;
面试必杀技:异步FIFO(下)-- CDC的那些事(6) - 知乎 (zhihu.com)
面试必杀技:异步FIFO(上) – CDC的那些事(5) - 知乎 (zhihu.com)
多bit信号跨时钟域怎么办? – CDC的那些事(4) - 知乎 (zhihu.com)
常见数电面试题Pulse Synchronizer – CDC的那些事(3) - 知乎 (zhihu.com)