grayCode做afifo的地址指针,有两个作用:
1.利用grayCode相邻两个数只有1bit变化,作为跨异步
2.用最高bit来表示地址wrap,可以产生空满信号,其中w/rpt_bin[msb]==w/rpt_gray[msb]
以4深度afifo为例,我们需要2bit的waddr/raddr和3bit的wpt_bin/rpt_bin,wpt_gray/rpt_gray
fifo_empty=(wpt_bin_sync[2:0] == rpt_bin[2:0])
fifo_full = (wpt_bin[2]!=rpt_bin_sync[2] && wpt_bin[1:0] == rpt_bin_sync[1:0])
编号 | w/rpt_bin | w/rpt_gray |
0 | 3'b000 | 3'b000 |
1 | 3'b001 | 3'b001 |
2 | 3'b010 | 3'b011 |
3 | 3'b011 | 3'b010 |
4 | 3'b100 | 3'b110 |
5 | 3'b101 | 3'b111 |
6 | 3'b110 | 3'b101 |
7 | 3'b111 | 3'b100 |
现在afifo深度为3,在地址从2跳到0的时候,地址发生wrap,如果w/rpt_bin继续记到3'b011,那么w/rpt_bin[2]没有翻转,不能表示这个wrap。后面在生成full或者empty就会出错。
我们仔细观察w/rpt_gray[2:0]的低两bit 发现上一半和下一半是镜像对称的。那么我们可以在w/rpt_bin[2:0]=3'b010-->w/rpt_bin[1:0]=3'b011的过程中,直接把w/rpt_gray[2:0]=3'b011跳到
w/rpt_gray[2:0]=3'b111,对应w/rpt_bin[2:0]=3'b010-->w/rpt_bin[1:0]=3'b101,人为增加了w/rpt_bin[2]的一次跳变。因为镜像对称的原因,此时从w/rpt_bin[2:0]=3'b101的位置到3'b111正好有fifo深度个地址,当下一次w/rpt_bin[2]发生跳变时,正好对应w/raddr的wrap。用图表示如下:
编号 | w/raddr | w/rpt_bin | w/rpt_gray |
0 | 0 | 3'b000 | 3'b000 |
1 | 1 | 3'b001 | 3'b001 |
2 | 2 | 3'b010 | 3'b011 |
3 | NA | 3'b011 | 3'b010 |
4 | NA | 3'b100 | 3'b110 |
5 | 0 | 3'b101 | 3'b111 |
6 | 1 | 3'b110 | 3'b101 |
7 | 2 | 3'b111 | 3'b100 |
总结一般性的规律,首先grayCode的低bit镜像对称是都满足的。设afifo深度为FIFO_DEPTH,对应的w/raddr的地址位宽为
ADDR_WID=ceil(log2(FIFO_DEPTH)),
ADDR_WID能表示的最大深度与FIFO_DEPTH深度差
DIFF_DEP=2^ADDR_WID - FIFO_DEPTH
那么当w/rpt_bin=FIFO_DEPTH-1时,下拍直接跳过2*DIFF_DEP即可,跳完之后的值为
PNT_HOP_VAL=FIFO_DEPTH+2*DIFF_DEP
assign w/rpt_bin_d = (w/rpt_bin_q == FIFO_DEPTH-1) ? PNT_HOP_VAL : (w/rpt_bin_q + 1'd1);
其中_d信号表示w/rpt_bin reg的输入;_q信号表示w/rpt_bin reg的输出。