1.SCFIFO
设置FIFO深度为32。
读写时钟相同,前16个时钟往FIFO写数据,后16个时钟读数据
T1时刻写第一个数据时,usedw立刻变为1,表示FIFO中的数据数量。
T2时刻,写第16个数据,usedw立刻变为16,表示FIFO中有16个数据。
T3时刻,读第一个数据,usedw立刻变为15,表示读出数据后FIFO剩余15个数据。
可以看出,在单口FIFO中,usedw可以实时表示FIFO中的数据数量。
2.DCFIFO
将IP核改为dcfifo,仿真图如下:
T1时刻,写入第一个数据,但wrusedw仍然为0,rdusedw也为0.
T2时刻,写入第二个数据,wrusedw变为1,rdusedw仍为0.
T3时刻,写入第三个数据,wrusedw变为2,rdusedw仍为0.
T4时刻,rdusedw变为1.
可以看出,wrusedw在wr_clk的上升沿改变,rdusedw在rd_clk的上升沿改变。
wrusedw相比写数据延后一个时钟周期。
在wrusedw改变后,在第3个rd_clk更新rdusedw。
为什么会这样呢?
我是这样理解的:
在写时钟域,写指针wptr指向当前数据(最新写入的数据)的下一地址。另有一指针wptr_r相比于写指针延后一个时钟周期。有wptr_r <= wptr;
将时钟域中的读指针经过两个时钟同步到写时钟域,寄存为rd_addr_rr,则有wrusedw <= wptr – rd_addr_rr;因为还没开始读,读指针一直为0。在T1时刻,wptr加1变为1,计算wrusedw时wptr仍为0,因此wrusedw为0。
在读时钟域,将wptr_r经过两个时钟同步到读时钟域,寄存为wr_addr_rr,rdusedw <= wr_addr_rr – rptr; T4时刻的wr_addr_rr为T2时刻后的wptr_r,值为1(wptr为2,wptr_r延后一个时钟),因为rptr一直为0,所以T4时刻rdusedw为1。
T1时刻,rptr仍为0,wr_addr_rr为同步过来的14(往前再数2个周期),rdusedw为14。此时刻要读数据,所以此时刻结束时rptr立刻加1,变为1.
T2时刻,rptr为1,wr_addr_rr为同步过来的14(往前数2个读时钟周期,还是14),所以rdusedw <= wr_addr_rr – rptr; 变为13。此时刻要读数据,所以rptr加1
T3时刻,wptr为16,rd_addr_rr为同步过来的0(往前数两个写时钟周期,此时还没开始读),因此wrusedw为16,但是位宽不够,数据溢出,因此显示为0。
T4时刻,rptr为2,wr_addr_rr为同步过来的15(往前数2个读时钟周期,wptr_r为15),所以rdusedw <= wr_addr_rr – rptr; 变为13。此时刻要读数据,所以rptr加1
T5时刻,rptr为3,wr_addr_rr为同步过来的15(往前数2个读时钟周期,wptr_r为15),所以rdusedw <= wr_addr_rr – rptr; 变为12。
T6时刻,wptr为16,rd_addr_rr为同步过来的0(往前数两个写时钟周期,此时还没开始读),因此wrusedw为16,但是位宽不够,数据溢出,因此显示为0。
分析wrusedw变为14的时刻,wptr为16,同步过来的读地址为T3时刻的读地址,T3时刻已经读了两个数据,rptr变为2,所以同步过来的rd_addr_rr为2,因此wrusedw为wptr – rd_addr_rr = 14;