异步FIFO设计笔记

异步FIFO设计笔记:

1.  首先确定输入输出接口,异步FIFO在一个时钟域中进行写数据操作,而在另一个时钟域中进行读数据操作,所以在写数据模块,需要有写数据wdata,写时钟wclk,写复位wrst_n,写请求wreq,写满标志wfull;在读数据模块,需要有读数据rdata,读时钟rclk,读复位rrst_n,读请求rreq,读空标志rempty。其中rdata,rempty,wfull为输出信号,其余为输入信号。

2.  考虑如何产生满标志和空标志位,当读写地址相同时表示当前FIFO已经被读空了或者被写满了,此时读指针rptr和写指针wptr地址相同。

n         本实验采用象限比较法,先确定当前读写状态是快接近满了,还是快要接近空了。取读指针rptr和写指针wptr的最高两位,按其次序分为4个象限,显然当写指针滞后一个象限,并且当写使能,即复位信号wrst_n为1时,FIFO快要满了,在程序中用close_full_n表示,当写指针超前一个象限时,FIFO快要空了,在程序中用close_empty_n表示。

n         用一个寄存器direction来寄存当前是否接近满空的状态,快接近满了则令direction=1;快接近空了则令direction=0;由于空/满标志产生的原则为:写满而不溢出,能读空而不多读,所以在其它情况下令direction=1,这样保证满标志不会出错,不会在快满时误以为未满而继续向FIFO写数据造成有效数据被覆盖。最后再由读写指针是否相同和direction一起来判断当前状态是满afull_n还是空aempty_n。

n         整个满空标志位的判断过程都使用组合逻辑,这样虽然读写时钟不一样,但是在读写指针发生变化时可以马上判断当前满空状态,之后再在读写时钟下清除写满wfull和读空rempty标志位。

 3.  写满wfull要同步到写时钟域,而读空rempty要同步到读时钟域。

n         写满wfull在afull_n变低时有效为1,在afull_n变高后的下一个时钟清除为0。

n         读空rempty在aempty_n变低时有效为1,在afull_n变高后的下一个时钟清除为0。

 4.  读写地址指针用Gray码来表示,这样有利于跨时钟域的同步,因为如果用二进制则当地址位加一时,该二进制代码的每一位都有可能变化,而用格雷码只会有一位发生变化,这样出错的概率比较小。

1 附注:异步FIFO程序。
2
3  module async_fifo_entire(wclk,wdata,wrst_n,wreq,wfull,
4 rclk,rdata,rrst_n,rreq,rempty);
5 parameter DATA_WIDTH = 8;
6 parameter ADDR_WIDTH = 4;
7
8 output [DATA_WIDTH-1:0] rdata;
9 output wfull;
10 output rempty;
11
12 input [DATA_WIDTH-1:0] wdata;
13 input wclk;
14 input wrst_n;
15 input wreq;
16 input rclk;
17 input rrst_n;
18 input rreq;
19
20 reg [ADDR_WIDTH-1:0] wptr;
21 reg [ADDR_WIDTH-1:0] rptr;
22 wire [ADDR_WIDTH-1:0] waddr;
23 wire [ADDR_WIDTH-1:0] raddr;
24 reg rempty,rempty2;
25 reg[ADDR_WIDTH-1:0] rbin;
26 wire[ADDR_WIDTH-1:0] rbnext,rgnext;
27 reg wfull,wfull2;
28 reg [ADDR_WIDTH-1:0] wbin;
29 wire [ADDR_WIDTH-1:0] wbnext,wgnext;
30
31 //compare wptr with rptr to determine the direction
32
33 wire aempty_n ;
34 wire afull_n ;
35 reg direction;
36 wire close_full_direction_n;
37 wire close_empty_direction_n;
38 parameter N = ADDR_WIDTH - 1;
39 assign close_full_direction_n = ~ (((wptr[N] ^ rptr[N-1]) &
40 ~ (wptr[N-1] ^ rptr[N])));
41 assign close_empty_direction_n = ~ (((~ (wptr[N] ^ rptr[N-1])) &
42 (wptr[N-1] ^ rptr[N])) | ~ wrst_n);
43
44 always @(negedge close_full_direction_n or negedge
45 close_empty_direction_n)
46 begin
47 if(!close_full_direction_n) direction <= 1'b1;
48 else if(!close_empty_direction_n) direction <= 1'b0;
49 else direction <= 1'b1;
50 end
51
52 assign afull_n = ~ ((wptr == rptr) && (direction == 1'b1));
53 assign aempty_n = ~ ((wptr == rptr) && (direction == 1'b0));
54
55 //wptr and wfull
56
57 always @(posedge wclk or negedge wrst_n)
58 begin
59 if(!wrst_n)
60 begin
61 wbin <= 0;
62 wptr <= 0;
63 end
64 else
65 begin
66 wbin <= wbnext;
67 wptr <= wgnext;
68 end
69 end
70
71 assign wbnext = !wfull ? wbin + wreq : wbin;
72 assign wgnext = (wbnext>>1) ^ wbnext;
73
74 always @(posedge wclk or negedge wrst_n or negedge afull_n)
75 begin
76 if(!wrst_n)
77 {wfull,wfull2} <= 2'b00;
78 else if(!afull_n)
79 {wfull,wfull2} <= 2'b11;
80 else
81 {wfull,wfull2} <= {wfull2,~afull_n};
82 end
83
84 //rempty and rptr
85
86 always @(posedge rclk or negedge rrst_n)
87 begin
88 if(!rrst_n)
89 begin
90 rbin <= 0;
91 rptr <= 0;
92 end
93 else
94 begin
95 rbin <= rbnext;
96 rptr <= rgnext;
97 end
98 end
99
100 assign rbnext = !rempty ? rbin + rreq : rbin;
101 assign rgnext = (rbnext>>1) ^ rbnext;
102
103 always @(posedge rclk or negedge aempty_n)
104 begin
105 if (!aempty_n)
106 {rempty,rempty2} <= 2'b11;
107 else
108 {rempty,rempty2} <= {rempty2,~aempty_n};
109 end
110
111 //dp_ram
112
113 assign waddr = wptr;
114 assign raddr = rptr;
115 parameter DEPTH = 1<<ADDR_WIDTH;
116 reg [DATA_WIDTH-1:0] MEM[0:DEPTH-1];
117 always @(posedge wclk or negedge wrst_n)
118 begin
119 if(!wrst_n)
120 MEM[waddr] <= 0;
121 else if(wreq)
122 MEM[waddr] <= wdata;
123 end
124
125 assign rdata = MEM[raddr];
126
127 endmodule
posted @ 2011-04-21 17:29  xxfighting  阅读(1780)  评论(0编辑  收藏  举报