Simulation and Synthesis Techniques for Asynchronous FIFO Design --- Clifford E. Cummings, Sunburst Design
1. 异步FIFO在跨时钟域传输的时候容易发生亚稳态。当在不同时钟域之间传递的多个信号时,需要用到异步FIFO。
异步FIFO的难点在于生成读写地址和空满指示位。
2. FIFO指针 2.1 同步fifo指针
对于同步FIFO而言,读写时钟相同,可以用一个计数器来表示FIFO的状态,如果只写数据,则计数增加;如果只读,则计数减少;级读又写,则计数不变。当计数到某个值,表示FIFO为满;计数为零,表示FIFO空。此时的读地址在每次读有效的时候增加就可以了,当读到最高为会回到零;写地址一样。
2.2 异步FIFO指针写指针:写指针指向下一个要写的地址。当FIFO reset之后,写指针为0。当写操作有效的时候,在下一个时钟沿出向写地址指向的位置写数据,然后写指针累加,指向下一个写地址。
读地址:读指针也要指向下一个要读的地址,FIFO reset之后,读指针也为0,此时空标志位有效,当写了一个数据后,空表示为清零。读操作有效的时候,在下一个时钟沿,向读地址指示的位置读数据,并使读地址累加。
满状态:如果写地址赶上读地址,此时读写地址相同,写地址将读地址套圈了,那么FIFO满了。
空状态:reset之后是空;当读地址赶上写地址,FIFO空。
地址上增加一位空满标志位:n位地址,最高位为标志位,低n-1位位真正的FIFO地址。除了最高位,读写地址相同,则为满;如果读写地址相同——最高位也相同,那么空。
2.3 二进制的地址问题二进制地址累加时,相邻地址经常存在多位同时跳变比如01到10,有两位同时跳变。在异步采样时可能没有采样到同时跳变后的值,可能采样到00,11的情况。
解决:用格雷码表示地址
3.格雷码计数器特点: 1.相邻码只改变1bit 2.只能用来记2的指数倍数,不能记奇数个数
如下图:
格雷码与二进制的转换:
格雷码计数器的功能:在写时钟域内,二进制地址累加,然后将二进制的写地址转换成格雷码地址,格雷码地址要传给读时钟域;在写时钟域中格雷码转换器将二进制的读地址转换成格雷码地址,格雷码地址要传给写时钟域。
3.1 第一种格雷码计数器一种格雷码编码风格如下,只需要一组地址寄存器来保存地址:
上图中上半部分表示生成n位的格雷码;下半部分红框部分将格雷码最高位与次高位异或,然后将生成的addrmsb与格雷码的低n-2位合并成一个N-1位的格雷码地址,不知有什么用??
// 上半图的n位格雷码计数器wire clk,rst_n;
wire [n-1:0] bin,bnext,gnext;
wire inc,full; // 写时钟域的格雷码转换器
reg [n-1:0] ptr; //输出的n位格雷码
integer i;
always@(ptr) begin //格雷码转二进制
bin[n-1] = ptr[n-1];
for(i=n-2;i>=0;i=i+1)
bin[i] = bin[i+1] ^ bin[i];
end
assign bnext = bnext+(inc && !full)?1:0;
assign gnext = (bnext>>1) ^ bnext; //二进制转格雷码
always @(posedge clk or negedge rst_n) begin
if(rst_n==1'b0) ptr<=0;
else begin
ptr <= bnext;
end
end
3.2 第二种格雷码计数器
用寄存器保存二进制码,去除格雷码到二进制的转换逻辑。
减小寄存器之间的组合逻辑长度,可以增加频率,特别是在FPGA中。
如下图: