关于异步FIFO的知识点--二进制转格雷码和两级同步
相比于同步FIFO,异步主要区别在与读写时钟的不同,其中异步FIFO的full信号将在写时钟域内确定,empty信号将在读时钟域内确定。针对跨时钟域信号传输需要对信号进行编码格式转换及进行两级同步处理,编码格式转换即将二进制数转换成格雷码表示,这是因为相邻两个格雷码只有一位数据发生变化:
十进制 | 二进制 | 格雷码 |
0 | 000 | 000 |
1 | 001 | 001 |
2 | 010 | 011 |
3 | 011 | 010 |
4 | 100 | 110 |
5 | 101 | 111 |
6 | 110 | 101 |
即二进制码转换成格雷码:从最低位开始,相邻两位异或结果为格雷码最低位
其对应的程序代码
always @(*)
for(i=0;i<WIDTH_D;i=i+1)//此时WIDTH_D=3
gray_c_d[i]<=bin_c[i]^bin_c[i+1];
assign gray_c={h_b,gray_c_d};
反之格雷码转换成二进制码:格雷码中所有位异或结果为二进制码最低位,格雷码中除最低位之外的所有异或为二进制次低位,以此类推
其对应程序代码:
bin[0] = gray[3]^gray[2]^gray[1]^gray[0];
bin[1] = gray[3]^gray[2]^gray[1];
bin[2] = gray[3]^gray[2];
bin[3] = gray[3];
将二进制码转换成格雷码的目的:二进制码不适合做FIFO的空满判断,二进制码在增减时,多bit位发生变化,如011-100,三个bit位全部发生变化。又因为读写时钟的不同步,异步的写时钟很可能在状态不稳定的中间某个状态进行采样,这就会得到错误的数据,进而产生错误的判断。其次也是为了减少亚稳态对电路的影响。
异步FIFO中,不同时钟域之间的信号传递需要进行两级同步处理,尽可能的防止亚稳态的传播。
为什么会产生亚稳态?---因为读写时钟的不同,在读,写时钟采样有效沿到来时,数据仍处于不稳定状态,不满足建立保持时间要求,就会产生亚稳态。且只要电路中有异步,亚稳态是无法避免的,只能减少它对电路产生的影响。
常见消除亚稳态的方法:进行两级同步,即打两拍。
always @(posedge w_r_clk or negedge rst_n)
begin
if(!rst_n)
begin
syn_1<='h0;
syn_2<='h0;
end
else
begin
syn_1<=w_r_gaddr; //进行两级同步操作
syn_2<=_syn_1;
end
end
assign w_r_gaddr_syn=syn_2;
补充:为什么多bit数据,例如地址位用格雷码表示可以进行两级同步操作?
因为当多bit数据为二进制表示时,在同一时钟有效沿可能会有多位发生翻转,则在另一时钟域采到的时候由于寄存器需要1到2个周期,所以可能会出现错误的值。但是如果使用格雷码进行两级同步,在同一时钟有效沿只有一bit位发生翻转,其他位皆保持稳定,这样通过两级同步后,输出的数据其他位皆保持,翻转的bit位要么保持,要么更新为翻转后的值,不会出现其他不该出现的值。
慢时钟域的格雷码同步到快时钟域时,如果慢时钟域的一个周期内,快时钟出现2个及以上时钟周期,为什么不会产生多bit同步问题?
因为格雷码的翻转是出现在慢时钟域,且每次只发生一bit位翻转,其余皆保持稳定。那么当快时钟域进行同步采样时,最多可以采到1bit位发生翻转,这个翻转可能会给快时钟域的第一级输出带来亚稳态问题,但是最终的同步输出要么保持要么更新1bit的数据,不会出现不该出现的问题。即虽然慢时钟域同步过来的多bit位跟之前的多bit位相比发生变化,但是这些不同bit位的翻转不是同时进行的。