参考博文:
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 的寻址采用二进制码, 异步时钟域的交互采用格雷码.
- `timescale 1ns / 1ps
- module fifo(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n);
- 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;
- reg wfull,rempty;
- reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;
- reg [ASIZE:0] rbin, wbin;
- reg [DSIZE-1:0] mem[0:(1<<ASIZE)-1];
- wire [ASIZE-1:0] waddr, raddr;
- wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext;
- wire rempty_val,wfull_val;
- //----------------- 双口 RAM 存储器 --------------------
- assign rdata=mem[raddr];
- always@(posedge wclk)
- if (winc && !wfull) mem[waddr] <= wdata;
- //------------- 在写时钟域 wclk 同步 rptr 指针 -------------------------
- always @(posedge wclk or negedge wrst_n)
- if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0;
- else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
- //------------- 在读时钟域 rclk 同步 wptr 指针 ---------------------------
- always @(posedge rclk or negedge rrst_n)
- if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0;
- else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
- //-------------rempty 产生与 raddr 产生 -------------------
- always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer
- begin
- if (!rrst_n) {rbin, rptr} <= 0;
- else {rbin, rptr} <= {rbinnext, rgraynext};
- end
- // Memory read-address pointer (okay to use binary to address memory)
- assign raddr = rbin[ASIZE-1:0];
- assign rbinnext = rbin + (rinc & ~rempty);
- assign rgraynext = (rbinnext>>1) ^ rbinnext;
- // FIFO empty when the next rptr == synchronized wptr or on reset
- assign rempty_val = (rgraynext == rq2_wptr);
- always @(posedge rclk or negedge rrst_n)
- begin
- if (!rrst_n) rempty <= 1'b1;
- else rempty <= rempty_val;
- end
- //---------------wfull 产生与 waddr 产生 ------------------------------
- always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer
- if (!wrst_n) {wbin, wptr} <= 0;
- else {wbin, wptr} <= {wbinnext, wgraynext};
- // Memory write-address pointer (okay to use binary to address memory)
- assign waddr = wbin[ASIZE-1:0];
- assign wbinnext = wbin + (winc & ~wfull);
- assign wgraynext = (wbinnext>>1) ^ wbinnext;
- assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); //:ASIZE-1]
- always @(posedge wclk or negedge wrst_n)
- if (!wrst_n) wfull <= 1'b0;
- else wfull <= wfull_val;
- endmodule
3, 验证
留待以后......
来源: http://www.bubuko.com/infodetail-3399627.html