参考博文:https://blog.csdn.net/alangaixiaoxiao/article/details/81432144
1、概述
异步FIFO设计的关键是产生“写满”和“读空”信号,这两个信号的产生需要用到读指针rptr和写指针wptr构建组合逻辑进行判断,然而读指针属于读时钟域rclk,写指针属于写时钟域wclk,因此必须进行同步化处理以消除亚稳态。异步FIFO的设计一般采用2种手段进行同步化处理:
(1)将读指针rptr打2拍到写时钟域,将写指针wptr打两拍到读时钟域,消除亚稳态;
(2)由于读写指针都是多比特信号,直接对它们进行同步化容易产生亚稳态,且用组合逻辑进行判断容易产生毛刺,因此改用格雷码进行异步时钟域的传输。
2、代码
设计思路有以下几点:
(1)在指针中添加一个额外的位(extra bit),当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2^n的FIFO,需要的 读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。如果两个指针的MSB不同,说明写指针比读指 针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。如果两个指针完全相同,为空。
(2)使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。空的判断标准仍是完全相同,满的判断标准需要满足:
■ 格雷码指针的最高位不同,因为wptr必须比rptr多折回一次。
■ wptr与rptr的次高位不相等,如下表的7(格雷码为0100)和15(格雷码为1000),转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
■ 其余位完全相同
(3)对双口RAM的寻址采用二进制码,异步时钟域的交互采用格雷码。
1 `timescale 1ns / 1ps 2 module fifo(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n); 3 parameter DSIZE = 8; parameter ASIZE = 4; 4 output [DSIZE-1:0] rdata; 5 output wfull; 6 output rempty; 7 input [DSIZE-1:0] wdata; 8 input winc, wclk, wrst_n; 9 input rinc, rclk, rrst_n; 10 reg wfull,rempty; 11 reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr; 12 reg [ASIZE:0] rbin, wbin; 13 reg [DSIZE-1:0] mem[0:(1<<ASIZE)-1]; 14 wire [ASIZE-1:0] waddr, raddr; 15 wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext; 16 wire rempty_val,wfull_val; 17 //-----------------双口RAM存储器-------------------- 18 assign rdata=mem[raddr]; 19 always@(posedge wclk) 20 if (winc && !wfull) mem[waddr] <= wdata; 21 22 //-------------在写时钟域 wclk 同步 rptr 指针------------------------- 23 always @(posedge wclk or negedge wrst_n) 24 if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0; 25 else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; 26 27 //-------------在读时钟域 rclk 同步 wptr 指针--------------------------- 28 always @(posedge rclk or negedge rrst_n) 29 if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0; 30 else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; 31 32 33 //-------------rempty产生与raddr产生------------------- 34 always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer 35 begin 36 if (!rrst_n) {rbin, rptr} <= 0; 37 else {rbin, rptr} <= {rbinnext, rgraynext}; 38 end 39 // Memory read-address pointer (okay to use binary to address memory) 40 assign raddr = rbin[ASIZE-1:0]; 41 assign rbinnext = rbin + (rinc & ~rempty); 42 assign rgraynext = (rbinnext>>1) ^ rbinnext; 43 // FIFO empty when the next rptr == synchronized wptr or on reset 44 assign rempty_val = (rgraynext == rq2_wptr); 45 always @(posedge rclk or negedge rrst_n) 46 begin 47 if (!rrst_n) rempty <= 1‘b1; 48 else rempty <= rempty_val; 49 end 50 51 52 //---------------wfull产生与waddr产生------------------------------ 53 always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer 54 if (!wrst_n) {wbin, wptr} <= 0; 55 else {wbin, wptr} <= {wbinnext, wgraynext}; 56 // Memory write-address pointer (okay to use binary to address memory) 57 assign waddr = wbin[ASIZE-1:0]; 58 assign wbinnext = wbin + (winc & ~wfull); 59 assign wgraynext = (wbinnext>>1) ^ wbinnext; 60 assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); //:ASIZE-1] 61 always @(posedge wclk or negedge wrst_n) 62 if (!wrst_n) wfull <= 1‘b0; 63 else wfull <= wfull_val; 64 65 endmodule
3、验证
留待以后……
原文:https://www.cnblogs.com/wt-seu/p/12242867.html