跨时钟域问题(转载)
首先是看了PARADIGM WORKS的一篇名为《Crossing the Abyss——Asynchronous Signals in a Synchronous World》的paper吧应该是
其实之前华老师很大篇幅的论文都是翻译的这篇文章里面的内容 国内的博客也有很多说的堂而皇之的话是翻译这篇文章的
说的都是一些很实在的跨时钟域的基本知识 感觉看过之后有种醍醐灌顶之感
首先就是基本的同步器就是两个DFF,这两个DFF在版图的时候一定要被放的非常近,以保证非常小的clock skew,再有就是第一个DFF对毛刺非常敏感 所以从原时钟域同步到新时钟域的时候 原时钟域的DFF与这个第一级的同步DFF中间不允许有任何的组合逻辑 因为组合逻辑非常容易产生毛刺 对这个第一级采样DFF影响非常之大 如果出现了一个glitch在这个DFF的sample window内 那么一个错误的值就将直接影响后面电路的工作
接下来简单的总结一下简单的单bit同步器分为level synchronizer/edge-detect synchronizer/pulse synchronizer
于是就有了下面这张表
重点是什么呢,以前只知道同步就是用dff打两拍 但是其实还是有限制的 用的最多的应该就是level的和edge-detect了,level的要求待同步信号要在欲同步域内至少保持两个时钟周期的不变化,其实这里我想说的是,最小值应该是小于这个safest period的(就是两个cycle),我觉得最小值应该是一个欲同步时钟域的setup time 加上hold time再加上一个欲同步时钟域的时钟周期 这个是最小值,稍微想一下worst case 就不难理解了,就能保证这个原时钟域的一个level可以被正确的采到新的时钟域,同样的对edge-detect也有着这样的问题 不知道对不对 但是paper里面说edge-detect同步器的前级电路最小维持不变时间为一个新时钟域的cycle加上一个hold time我不是很理解。
下面pulse synchronizer的要求就是要输入的pulse间隔至少要为两个新时钟域的cycle。其实快时钟到慢时钟用的时候非常方便 但是慢时钟到快时钟的时候我觉得不如用edge-detect来做同步 就可以把需要的时间变短 使得同步效率更高
,其实pulse synchronizer 的电路非常简单 就是下面这几行代码
always @(posedge f_clk or negedge f_rst_n) begin if(~f_rst_n) f_tog <= 1'b0 ; else if(f_pulse) f_tog <= ~f_tog ; end always @(posedge s_clk or negedge s_rst_n) begin if(~s_rst_n) s_syn <= 3'b0 ; else s_syn <= {s_syn[1:0], f_tog} ; end assign s_pulse = s_syn[2] ^ s_syn[1];
f_pulse 是快时钟域内的一个pulse信号,s_pulse是同步到慢时钟域内的一个pulse信号
简单的一个同步器其实里面学问还是蛮多的,接着这paper就讲了一些关于握手和fifo的老生常谈的东西 包括全握手,部分握手之类的东西 全握手还是比较好理解的 我觉得部分握手不够robust 用的地方还是看需求吧基本上 如果有条件 仔细考虑可能部分握手可以达到效率高 同时也很robust的地步
至此就总结这篇paper至此 还真是不错的作品 致谢作者