根据格雷码的特性,写时钟域与的格雷码写地址与同步过来的格雷码读地址相比,最高两位都不同,其他位相同,说明满了。
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]});always @(posedge wclk or negedge wrst_n)
if (!wrst_n) wfull <= 1'b0;
else wfull <= wfull_val; 5.3 不同时钟频率的考虑
问题一:快时钟是慢时钟的两倍,那么快域地址变化两次,慢时钟域采样一次,前后采样值变化了两次,会产生多位同步的问题吗?
不会。快时钟域第一次改变一位,比如从A到B,慢时钟域没有采样,当快时钟域改变第二次B到C之后,慢时钟域才采样,虽然这期间快时钟域的地址从A到C变了两次,但是慢时钟域只看到第二次B到C,只跳变了一位,因此不会产生多位同步问题。
问题二:快时钟域是否会引起full+1的情况——写溢出,或者empty+1——读溢出?
不会。对于满是在写时钟域产生,如果写时钟比读时钟快,如果waddr追上raddr,那么full有效,此时不能再写了,也就不会产生full+1情况。对于空是在写时钟域产生,如果读时钟比写时钟快,如果raddr赶上waddr,那么就不能再读,也就不会产生empty+1.
5.4 空满标志位取消空满的set是立即生效的。比如读时钟域中,将采样到的写时钟域的格雷码写地址 与当前的读地址比较,如果相等,则立马使empty有效;full类似。但是读写标志位clear是有延迟的。
当empty有效的时候,读时钟域采样的写地址与读地址相同,如果此时写入数据,那么在写时钟域里写地址是增加的,但是这个增加了的写地址需要两个读时钟的同步才能让读时钟域里的地址比较器看到,所以empty的clear有两个读时钟周期的延迟;同样full的clear有两个写时钟周期的延迟。
但这不会使FIFO发生功能错误,可忽略。
5.5 reset时候地址多位跳变没影响,因为reset就表明FIFO里的数据是无效的,此时不对FIFO进行读写。
6. 代码这些代码是Cummings论文中给的。
6.1 顶层 module fifo1 #(parameter DSIZE = 8,parameter ASIZE = 4)
(output [DSIZE-1:0] rdata,
output wfull,
output rempty,
input [DSIZE-1:0] wdata,
input winc, wclk, wrst_n,
input rinc, rclk, rrst_n);
wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
sync_r2w sync_r2w (.wq2_rptr(wq2_rptr), .rptr(rptr),
.wclk(wclk), .wrst_n(wrst_n));
sync_w2r sync_w2r (.rq2_wptr(rq2_wptr), .wptr(wptr),
.rclk(rclk), .rrst_n(rrst_n));
fifomem #(DSIZE, ASIZE) fifomem
(.rdata(rdata), .wdata(wdata),
.waddr(waddr), .raddr(raddr),
.wclken(winc), .wfull(wfull),
.wclk(wclk));
rptr_empty #(ASIZE) rptr_empty
(.rempty(rempty),
.raddr(raddr),
.rptr(rptr), .rq2_wptr(rq2_wptr),
.rinc(rinc), .rclk(rclk),
.rrst_n(rrst_n));
wptr_full #(ASIZE) wptr_full
(.wfull(wfull), .waddr(waddr),
.wptr(wptr), .wq2_rptr(wq2_rptr),
.winc(winc), .wclk(wclk),
.wrst_n(wrst_n));
endmodule 6.2 内存读写模块