异步FIFO
这个是基于RAM的异步FIFO代码,个人认为代码结构简单易懂,非常适合于考试中填写。与同步fifo相比增加了读写控制信号的跨时钟域的同步。此外,判空与判满的也稍有不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
module fifo #( parameter DSIZE = 8, ASIZE = 4 ) ( input [DSIZE-1:0] wdata, input winc, wclk, wrst_n, input rinc, rclk, rrst_n, output [DSIZE-1:0] rdata, output reg wfull, output reg 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; //-------------同步rptr 指针------------------------- always @( posedge wclk or negedge wrst_n) if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0; else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; //-------------同步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 |