1)顶层模块  module AsyncFIFO #(parameter ASIZE = 4, //地址位宽 parameter DSIZE = 8) //数据位宽 ( input [DSIZE-1:0] wdata, input winc, wclk, wrst_n, //写请求信号,写时钟,写复位 input rinc, rclk, rrst_n, //读请求信号,读时钟,读复位 output [DSIZE-1:0] rdata, output wfull, output rempty ); wire [ASIZE-1:0] waddr, raddr; wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr; /************************************************************ * In order to perform FIFO full and FIFO empty tests using * this FIFO style, the read and write pointers must be * passed to the opposite clock domain for pointer comparison *************************************************************/ /*在检测“满”或“空”状态之前,需要将指针同步到其它时钟域时,使用格雷码,可以降低同步过程中亚稳态出现的概率*/ sync_r2w I1_sync_r2w( .wq2_rptr(wq2_rptr), .rptr(rptr), .wclk(wclk), .wrst_n(wrst_n)); sync_w2r I2_sync_w2r ( .rq2_wptr(rq2_wptr), .wptr(wptr), .rclk(rclk), .rrst_n(rrst_n)); /* * DualRAM */ DualRAM #(DSIZE, ASIZE) I3_DualRAM( .rdata(rdata), .wdata(wdata), .waddr(waddr), .raddr(raddr), .wclken(winc), .wclk(wclk)); /* * 空、满比较逻辑 */ rptr_empty #(ASIZE) I4_rptr_empty( .rempty(rempty), .raddr(raddr), .rptr(rptr), .rq2_wptr(rq2_wptr), .rinc(rinc), .rclk(rclk), .rrst_n(rrst_n)); wptr_full #(ASIZE) I5_wptr_full( .wfull(wfull), .waddr(waddr), .wptr(wptr), .wq2_rptr(wq2_rptr), .winc(winc), .wclk(wclk), .wrst_n(wrst_n)); endmodule 2)DualRAM模块 module DualRAM #( parameter DATA_SIZE = 8, // 数据位宽 parameter ADDR_SIZE = 4 // 地址位宽 ) ( input wclken,wclk, input [ADDR_SIZE-1:0] raddr, //RAM read address input [ADDR_SIZE-1:0] waddr, //RAM write address input [DATA_SIZE-1:0] wdata, //data input output [DATA_SIZE-1:0] rdata //data output ); localparam RAM_DEPTH = 1 << ADDR_SIZE; //RAM深度 = 2^ADDR_WIDTH reg [DATA_SIZE-1:0] Mem[RAM_DEPTH-1:0]; always@(posedge wclk) begin if(wclken) Mem[waddr] <= wdata; end assign rdata = Mem[raddr]; endmodule 3)同步模块 module sync_r2w #(parameter ADDRSIZE = 4) ( output reg [ADDRSIZE:0] wq2_rptr, input [ADDRSIZE:0] rptr, input wclk, wrst_n ); reg [ADDRSIZE:0] wq1_rptr; always @(posedge wclk or negedge wrst_n) if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0; else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; endmodule 4)同步模块2 module sync_w2r #(parameter ADDRSIZE = 4) ( output reg [ADDRSIZE:0] rq2_wptr, input [ADDRSIZE:0] wptr, input rclk, rrst_n ); reg [ADDRSIZE:0] rq1_wptr; always @(posedge rclk or negedge rrst_n) if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0; else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; endmodule 5)空判断逻辑 module rptr_empty #(parameter ADDRSIZE = 4) ( output reg rempty, output [ADDRSIZE-1:0] raddr, output reg [ADDRSIZE :0] rptr, input [ADDRSIZE :0] rq2_wptr, input rinc, rclk, rrst_n); reg [ADDRSIZE:0] rbin; wire [ADDRSIZE:0] rgraynext, rbinnext; wire rempty_val; //------------------- // GRAYSTYLE2 pointer: gray码读地址指针 //------------------- always @(posedge rclk or negedge rrst_n) if (!rrst_n) begin rbin <= 0; rptr <= 0; end else begin rbin <= rbinnext ; rptr <= rgraynext; end // gray码计数逻辑 assign rbinnext = !rempty ? (rbin + rinc) : rbin; assign rgraynext = (rbinnext>>1) ^ rbinnext; //二进制到gray码的转换 assign raddr = rbin[ADDRSIZE-1:0]; //--------------------------------------------------------------- // FIFO empty when the next rptr == synchronized wptr or on reset //--------------------------------------------------------------- /* * 读指针是一个n位的gray码计数器,比FIFO寻址所需的位宽大一位 * 当读指针和同步过来的写指针完全相等时(包括MSB),说明二者折回次数一致,FIFO为空 * */ assign rempty_val = (rgraynext == rq2_wptr); always @(posedge rclk or negedge rrst_n) if (!rrst_n) rempty <= 1'b1; else rempty <= rempty_val; endmodule 6)满判断逻辑 module wptr_full #( parameter ADDRSIZE = 4 ) ( output reg wfull, output [ADDRSIZE-1:0] waddr, output reg [ADDRSIZE :0] wptr, input [ADDRSIZE :0] wq2_rptr, input winc, wclk, wrst_n); reg [ADDRSIZE:0] wbin; wire [ADDRSIZE:0] wgraynext, wbinnext; wire wfull_val; // GRAYSTYLE2 pointer always @(posedge wclk or negedge wrst_n) if (!wrst_n) begin wbin <= 0; wptr <= 0; end else begin wbin <= wbinnext; wptr <= wgraynext; end //gray 码计数逻辑 assign wbinnext = !wfull ? wbin + winc : wbin; assign wgraynext = (wbinnext>>1) ^ wbinnext; assign waddr = wbin[ADDRSIZE-1:0]; /*由于满标志在写时钟域产生,因此比较安全的做法是将读指针同步到写时钟域*/ /**/ //------------------------------------------------------------------ // Simplified version of the three necessary full-tests: // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) && // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) && // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0])); //------------------------------------------------------------------ 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; endmodule