异步FIFO结构
module asyn_fifo
#(
parameter DSIZE = 10,
parameter ASIZE = 4
)
(
input wire wclk ,
input wire wrst_n ,
input wire winc ,
input wire [DSIZE-1:0] wdata ,
input wire rclk ,
input wire rrst_n ,
input wire rinc ,
output wire [DSIZE-1:0] rdata ,
output reg wfull ,
output reg rempty
);
localparam DEPTH = 1<<ASIZE;
reg [DSIZE-1:0] mem[0:DEPTH-1] ;
wire [ASIZE-1:0] waddr ;
wire [ASIZE-1:0] raddr ;
wire [ASIZE:0] rgraynext ;
wire [ASIZE:0] rbinnext ;
wire repty_val ;
wire [ASIZE:0] wgraynext ;
wire [ASIZE:0] wbinnext ;
wire wfull_val ;
reg [ASIZE:0] wq1_rptr ;
reg [ASIZE:0] wq2_rptr ;
reg [ASIZE:0] rq1_wptr ;
reg [ASIZE:0] rq2_wptr ;
reg [ASIZE:0] wptr ;
reg [ASIZE:0] wbin ;
reg [ASIZE:0] rptr ;
reg [ASIZE:0] rbin ;
//--------------------------------------------------------
// synchronize the read pointer into the write-clock domain
//--------------------------------------------------------
always @(posedge wclk or negedge wrst_n)begin
if(wrst_n == 1'b0)begin
wq1_rptr <= {(ASIZE+1){1'b0}};
wq2_rptr <= {(ASIZE+1){1'b0}};
end
else begin
wq1_rptr <= rptr;
wq2_rptr <= wq1_rptr;
end
end
//--------------------------------------------------------
// synchronize the write pointer into the read-clock domain
//--------------------------------------------------------
always @(posedge rclk or negedge rrst_n)begin
if(rrst_n == 1'b0)begin
rq1_wptr <= {(ASIZE+1){1'b0}};
rq2_wptr <= {(ASIZE+1){1'b0}};
end
else begin
rq1_wptr <= wptr;
rq2_wptr <= rq1_wptr;
end
end
//--------------------------------------------------------
// This is the FIFO memory buffer that is accessed by both the write and read clock domains.
// This buffer is most likely an instantisted,synchronous dual-port RAM.
// Other memory styles can be adapted to function as the FIFO buffer.
//--------------------------------------------------------
assign rdata = mem[raddr];
always @(posedge wclk)
if(winc == 1'b1 && wfull == 1'b0)
mem[waddr] <= wdata;
//--------------------------------------------------------
// this part is completely synchronous to the read_clock domain and contains
// the FIFO read pointer and empty-flag logic.
//--------------------------------------------------------
always @(posedge rclk or negedge rrst_n)begin
if(rrst_n == 1'b0)begin
rbin <= {(ASIZE+1){1'b0}};
rptr <= {(ASIZE+1){1'b0}};
end
else begin
rbin <= rbinnext;
rptr <= rgraynext;
end
end
//Memory read-address pointer (okay to use binary to address memory)
assign raddr = rbin[ASIZE-1:0];
assign rbinnext = (rinc & ~rempty) ? rbin + {{ASIZE{1'b0}},{1'b1}}:rbin;
assign rgraynext = (rbinnext>>1) ^ rbinnext;
// FIFO empty when the next rptr == synchronized wptr or on reset
assign repty_val = (rgraynext == rq2_wptr);
always @(posedge rclk or negedge rrst_n)begin
if(rrst_n == 1'b0)
rempty <= 1'b1;
else
rempty <= repty_val;
end
//--------------------------------------------------------
//This part is completely synchronous to the write-clock domain and contains
//the FIFO writepointer and full_flag logic
//--------------------------------------------------------
always @(posedge wclk or negedge wrst_n)begin
if(wrst_n == 1'b0)begin
wbin <= {(ASIZE+1){1'b0}};
wptr <= {(ASIZE+1){1'b0}};
end
else begin
wbin <= wbinnext;
wptr <= wgraynext;
end
end
// Memory write-address pointer(okay to use binary to address memory)
assign waddr = wbin[ASIZE-1:0];
assign wbinnext = (winc & ~wfull) ? wbin + {{ASIZE{1'b0}},{1'b1}} : wbin;
assign wgraynext = (wbinnext>>1) ^ wbinnext;
assign wfull_val = (wgraynext == {~wq2_rptr[ASIZE:ASIZE-1],wq2_rptr[ASIZE-2:0]});
always @(posedge wclk or negedge wrst_n)begin
if(wrst_n == 1'b0)
wfull <= 1'b0;
else
wfull <= wfull_val;
end
endmodule