目录
对于多bit而言,跨时钟域解决方法与异步时钟亚稳态 的解决方案——单bit信号是类似的,可以对照学习。
跨时钟域处理方法总结–最终详尽版跨时钟域处理–最终详尽版
FPGA 设计之 跨时钟域(三 - 多比特小结)
FPGA 设计之 跨时钟域(四 - 格雷码)
FPGA 设计之 跨时钟域(六 - 握手)
同步valid&ready握手 与 异步valid&ack握手
《Clock Domain Crossing》 翻译与理解(5)多信号跨时钟域传输
推荐】数字芯片跨时钟域设计经典论文
多bit信号跨时钟域怎么办? – CDC的那些事(4)
菜鸟教程:4.2 Verilog 跨时钟域传输:慢到快
1. 亚稳态问题——电平同步
1.1. 时钟偏斜 导致的采样中间值问题
● 时钟偏斜skew:时钟沿信号到达各触发器CK端的时间不同
这会导致多bit信号的每个触发器值变化不是同时的,有的变得快有的变得慢,如果每个bit都没变完,就被异步时钟采样了,就会出现中间值。
单bit信号电平也好,脉冲也好跨时钟域,采样到了就算有点延迟也没关系,最终产生一个脉冲就行。
但是多bit信号要求整个变化过程都是恒定的,中间出现了第三个值就可能对功能产生影响。
看图
红线处adata由000变为111,因为时钟偏斜,该信号每个bit真正开始拉高的时刻不一样。如果异步时钟bclk在不同的时刻采样会对应不同时刻的值,3条绿线分别对应采样到001、101、111。
1.2. “3个沿”+允许skew——电平同步
是的,多bit信号也可以进行电平同步。
如果满足“3个沿”条件,说明最终一定可以采样到正确的数据。但由于time skew的存在,可能第一次采样到中间值、第二次采到正确值。
所以如果允许出现中间值,可以直接打两拍。即要求 1.5 T b c l k < T a s i g 1.5T_{bclk} < T_{asig} 1.5Tbclk<Tasig
2.1. “>8个沿”+不允许skew——valid信号D+MUX选通
如果数据信号带有valid,且占据目的时钟8个沿甚至更久,可以对valid作CDC,然后用valid去采稳定后的源数据信号。
方法与单bit边沿检测是相同的,为多bit信号配一个1bit有效标志valid,使用valid作边沿检测
如下图所示
avalid拉低表示传输结束,adata没变是用于省电,常见手法
上代码
reg bvalid_cdc_to, bvalid_d2, bvalid_d3;
wire bvalid_d2_rise = bvalid_d2 && (!bvalid_d3);
always@(posedge bclk) begin
bvalid_cdc_to <= avalid;
bvalid_d2 <= bvalid_cdc_to ;
bvalid_d3 <= bvalid_d2;
bvalid <= bvalid_d2_rise ;
end
always@(posedge bclk) begin
if(bvalid_d2_rise)
bdata <= adata;
end
2. 漏采样——展宽
如果不满足“3个沿”出现漏采样,或者“3个沿”不允许time skew,就只能通过展宽解决。
仍然借用DMUX的思路,将valid作展宽处理,采样稳定的data即可
2.1. valid延迟展宽
对valid打拍取或,在目的时钟用沿采样data即可。前提是保证展宽后数据保持不变
reg [3:0] avalid_dly; // aclk
reg bvalid_dly_cdc_to; // bclk
reg bvalid_dly_d1; // bclk
reg bvalid_dly_d2; // bclk
always@(posedge aclk) begin
avalid_dly <= {avalid_dly[2:0], avalid};
end
wire bvalid_dly_d1_rise = bvalid_dly_d1 && (!bvalid_dly_d2);
always@(posedge bclk) begin
bvalid_dly_cdc_to <= (|avalid_dly);
bvalid_dly_d1 <= bvalid_dly_cdc_to;
bvalid_dly_d2 <= bvalid_dly_d1;
bvalid <= bvalid_dly_d1_rise; // bclk
end
always@(posedge bclk) begin
if(bvalid_dly_d1_rise)
bdata <= adata;
end
2.2. valid 异或展宽
对valid也可做异或展宽,与单bit区别就是增加了在bclk有效时采样adata,直接上代码
reg avalid_dly = 1'd0; // aclk
reg avalid_xor; // bclk
always@(posedge aclk) begin
avalid_xor <= avalid_dly ^ avalid;
end
reg bvalid_xor_cdc_to; // bclk
reg bvalid_d2; // bclk
reg bvalid_d3; // bclk
reg bvalid; // bclk
wire bvalid_xor = (bvalid_d2 != bvalid_d3);
always@(posedge bclk) begin
bvalid_xor_cdc_to <= avalid_xor;
bvalid_d2 <= bvalid_xor_cdc_to;
bvalid_d3 <= bvalid_d2;
bvalid <= bvalid_d2;
end
always@(posedge bclk) begin
if(bvalid_xor)
bdata <= adata;
end
3. 高频变化/缓存——异步FIFO
如果满足1.5倍频DMUX方案中bvalid采样的是下一个adata,怎么办?
如果异或展宽中两个adata离得太近导致bclk无法拆成两个bpulse,怎么办?
如上这种源时钟数据变化太快的问题,都可以用异步FIFO解决。但是异步FIFO实际上并未解决数据信号跨时钟域问题,而是把问题转化成多bit读写指针的跨时钟域问题了。
对于读写指针而言,属于递增计数器,需要电平同步 + Grey码的方式进行处理,同时读写逻辑也并不关注读写指针的变化过程,因此快采慢的多采样问题和慢采快的漏数问题都不会产生影响。
因此,full和empty标志并不能实时反应当前时刻FIFO的真实状态,但这种错误并不会造成满写和空读的问题。
详情见异步FIFO设计