OpenCores
URL https://opencores.org/ocsvn/sdr_ctrl/sdr_ctrl/trunk

Subversion Repositories sdr_ctrl

[/] [sdr_ctrl/] [trunk/] [rtl/] [lib/] [async_fifo.v] - Blame information for rev 67

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 dinesha
/*********************************************************************
2
 
3
  ASYNC FIFO
4
 
5
  This file is part of the sdram controller project
6
  http://www.opencores.org/cores/sdr_ctrl/
7
 
8
  Description: ASYNC FIFO
9
 
10
  To Do:
11
    nothing
12
 
13
  Author(s):  Dinesh Annayya, dinesha@opencores.org
14
 
15
 Copyright (C) 2000 Authors and OPENCORES.ORG
16
 
17
 This source file may be used and distributed without
18
 restriction provided that this copyright statement is not
19
 removed from the file and that any derivative work contains
20
 the original copyright notice and the associated disclaimer.
21
 
22
 This source file is free software; you can redistribute it
23
 and/or modify it under the terms of the GNU Lesser General
24
 Public License as published by the Free Software Foundation;
25
 either version 2.1 of the License, or (at your option) any
26
later version.
27
 
28
 This source is distributed in the hope that it will be
29
 useful, but WITHOUT ANY WARRANTY; without even the implied
30
 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
31
 PURPOSE.  See the GNU Lesser General Public License for more
32
 details.
33
 
34
 You should have received a copy of the GNU Lesser General
35
 Public License along with this source; if not, download it
36
 from http://www.opencores.org/lgpl.shtml
37
 
38
*******************************************************************/
39
 
40
//-------------------------------------------
41
// async FIFO
42
//-----------------------------------------------
43 67 dinesha
//`timescale  1ns/1ps
44 31 dinesha
 
45
module async_fifo (wr_clk,
46
                   wr_reset_n,
47
                   wr_en,
48
                   wr_data,
49
                   full,                 // sync'ed to wr_clk
50
                   afull,                 // sync'ed to wr_clk
51
                   rd_clk,
52
                   rd_reset_n,
53
                   rd_en,
54
                   empty,                // sync'ed to rd_clk
55
                   aempty,                // sync'ed to rd_clk
56
                   rd_data);
57
 
58
   parameter W = 4'd8;
59
   parameter DP = 3'd4;
60
   parameter WR_FAST = 1'b1;
61
   parameter RD_FAST = 1'b1;
62
   parameter FULL_DP = DP;
63
   parameter EMPTY_DP = 1'b0;
64
 
65
   parameter AW = (DP == 2)   ? 1 :
66
                  (DP == 4)   ? 2 :
67
                  (DP == 8)   ? 3 :
68
                  (DP == 16)  ? 4 :
69
                  (DP == 32)  ? 5 :
70
                  (DP == 64)  ? 6 :
71
                  (DP == 128) ? 7 :
72
                  (DP == 256) ? 8 : 0;
73
 
74
   output [W-1 : 0]  rd_data;
75
   input [W-1 : 0]   wr_data;
76
   input             wr_clk, wr_reset_n, wr_en, rd_clk, rd_reset_n,
77
                     rd_en;
78
   output            full, empty;
79
   output            afull, aempty;       // about full and about to empty
80
 
81
 
82
   // synopsys translate_off
83
 
84
   initial begin
85
      if (AW == 0) begin
86
         $display ("%m : ERROR!!! Fifo depth %d not in range 2 to 256", DP);
87
      end // if (AW == 0)
88
   end // initial begin
89
 
90
   // synopsys translate_on
91
 
92
   reg [W-1 : 0]    mem[DP-1 : 0];
93
 
94
   /*********************** write side ************************/
95
   reg [AW:0] sync_rd_ptr_0, sync_rd_ptr_1;
96
   wire [AW:0] sync_rd_ptr;
97
   reg [AW:0] wr_ptr, grey_wr_ptr;
98
   reg [AW:0] grey_rd_ptr;
99
   reg full_q;
100
   wire full_c;
101
   wire afull_c;
102
   wire [AW:0] wr_ptr_inc = wr_ptr + 1'b1;
103
   wire [AW:0] wr_cnt = get_cnt(wr_ptr, sync_rd_ptr);
104
 
105
   assign full_c  = (wr_cnt == FULL_DP) ? 1'b1 : 1'b0;
106
   assign afull_c = (wr_cnt == FULL_DP-1) ? 1'b1 : 1'b0;
107
 
108
 
109
   always @(posedge wr_clk or negedge wr_reset_n) begin
110
        if (!wr_reset_n) begin
111
                wr_ptr <= 0;
112
                grey_wr_ptr <= 0;
113
                full_q <= 0;
114
        end
115
        else if (wr_en) begin
116
                wr_ptr <= wr_ptr_inc;
117
                grey_wr_ptr <= bin2grey(wr_ptr_inc);
118
                if (wr_cnt == (FULL_DP-1)) begin
119
                        full_q <= 1'b1;
120
                end
121
        end
122
        else begin
123
                if (full_q && (wr_cnt<FULL_DP)) begin
124
                        full_q <= 1'b0;
125
                end
126
        end
127
    end
128
 
129
    assign full  = (WR_FAST == 1) ? full_c : full_q;
130
    assign afull = afull_c;
131
 
132
    always @(posedge wr_clk) begin
133
        if (wr_en) begin
134
                mem[wr_ptr[AW-1:0]] <= wr_data;
135
        end
136
    end
137
 
138
    wire [AW:0] grey_rd_ptr_dly ;
139
    assign #1 grey_rd_ptr_dly = grey_rd_ptr;
140
 
141
    // read pointer synchronizer
142
    always @(posedge wr_clk or negedge wr_reset_n) begin
143
        if (!wr_reset_n) begin
144
                sync_rd_ptr_0 <= 0;
145
                sync_rd_ptr_1 <= 0;
146
        end
147
        else begin
148
                sync_rd_ptr_0 <= grey_rd_ptr_dly;
149
                sync_rd_ptr_1 <= sync_rd_ptr_0;
150
        end
151
    end
152
 
153
    assign sync_rd_ptr = grey2bin(sync_rd_ptr_1);
154
 
155
   /************************ read side *****************************/
156
   reg [AW:0] sync_wr_ptr_0, sync_wr_ptr_1;
157
   wire [AW:0] sync_wr_ptr;
158
   reg [AW:0] rd_ptr;
159
   reg empty_q;
160
   wire empty_c;
161
   wire aempty_c;
162
   wire [AW:0] rd_ptr_inc = rd_ptr + 1'b1;
163
   wire [AW:0] sync_wr_ptr_dec = sync_wr_ptr - 1'b1;
164
   wire [AW:0] rd_cnt = get_cnt(sync_wr_ptr, rd_ptr);
165
 
166
   assign empty_c  = (rd_cnt == 0) ? 1'b1 : 1'b0;
167
   assign aempty_c = (rd_cnt == 1) ? 1'b1 : 1'b0;
168
 
169
   always @(posedge rd_clk or negedge rd_reset_n) begin
170
      if (!rd_reset_n) begin
171
         rd_ptr <= 0;
172
         grey_rd_ptr <= 0;
173
         empty_q <= 1'b1;
174
      end
175
      else begin
176
         if (rd_en) begin
177
            rd_ptr <= rd_ptr_inc;
178
            grey_rd_ptr <= bin2grey(rd_ptr_inc);
179
            if (rd_cnt==(EMPTY_DP+1)) begin
180
               empty_q <= 1'b1;
181
            end
182
         end
183
         else begin
184
            if (empty_q && (rd_cnt!=EMPTY_DP)) begin
185
              empty_q <= 1'b0;
186
            end
187
         end
188
       end
189
    end
190
 
191
    assign empty  = (RD_FAST == 1) ? empty_c : empty_q;
192
    assign aempty = aempty_c;
193
 
194 58 dinesha
    reg [W-1 : 0]  rd_data_q;
195 31 dinesha
 
196 58 dinesha
   wire [W-1 : 0] rd_data_c = mem[rd_ptr[AW-1:0]];
197
   always @(posedge rd_clk) begin
198
        rd_data_q <= rd_data_c;
199
   end
200
   assign rd_data  = (RD_FAST == 1) ? rd_data_c : rd_data_q;
201
 
202 31 dinesha
    wire [AW:0] grey_wr_ptr_dly ;
203
    assign #1 grey_wr_ptr_dly =  grey_wr_ptr;
204
 
205
    // write pointer synchronizer
206
    always @(posedge rd_clk or negedge rd_reset_n) begin
207
        if (!rd_reset_n) begin
208
           sync_wr_ptr_0 <= 0;
209
           sync_wr_ptr_1 <= 0;
210
        end
211
        else begin
212
           sync_wr_ptr_0 <= grey_wr_ptr_dly;
213
           sync_wr_ptr_1 <= sync_wr_ptr_0;
214
        end
215
    end
216
    assign sync_wr_ptr = grey2bin(sync_wr_ptr_1);
217
 
218
 
219
/************************ functions ******************************/
220
function [AW:0] bin2grey;
221
input [AW:0] bin;
222
reg [8:0] bin_8;
223
reg [8:0] grey_8;
224
begin
225
        bin_8 = bin;
226
        grey_8[1:0] = do_grey(bin_8[2:0]);
227
        grey_8[3:2] = do_grey(bin_8[4:2]);
228
        grey_8[5:4] = do_grey(bin_8[6:4]);
229
        grey_8[7:6] = do_grey(bin_8[8:6]);
230
        grey_8[8] = bin_8[8];
231
        bin2grey = grey_8;
232
end
233
endfunction
234
 
235
function [AW:0] grey2bin;
236
input [AW:0] grey;
237
reg [8:0] grey_8;
238
reg [8:0] bin_8;
239
begin
240
        grey_8 = grey;
241
        bin_8[8] = grey_8[8];
242
        bin_8[7:6] = do_bin({bin_8[8], grey_8[7:6]});
243
        bin_8[5:4] = do_bin({bin_8[6], grey_8[5:4]});
244
        bin_8[3:2] = do_bin({bin_8[4], grey_8[3:2]});
245
        bin_8[1:0] = do_bin({bin_8[2], grey_8[1:0]});
246
        grey2bin = bin_8;
247
end
248
endfunction
249
 
250
 
251
function [1:0] do_grey;
252
input [2:0] bin;
253
begin
254
        if (bin[2]) begin  // do reverse grey
255
                case (bin[1:0])
256
                        2'b00: do_grey = 2'b10;
257
                        2'b01: do_grey = 2'b11;
258
                        2'b10: do_grey = 2'b01;
259
                        2'b11: do_grey = 2'b00;
260
                endcase
261
        end
262
        else begin
263
                case (bin[1:0])
264
                        2'b00: do_grey = 2'b00;
265
                        2'b01: do_grey = 2'b01;
266
                        2'b10: do_grey = 2'b11;
267
                        2'b11: do_grey = 2'b10;
268
                endcase
269
        end
270
end
271
endfunction
272
 
273
function [1:0] do_bin;
274
input [2:0] grey;
275
begin
276
        if (grey[2]) begin      // actually bin[2]
277
                case (grey[1:0])
278
                        2'b10: do_bin = 2'b00;
279
                        2'b11: do_bin = 2'b01;
280
                        2'b01: do_bin = 2'b10;
281
                        2'b00: do_bin = 2'b11;
282
                endcase
283
        end
284
        else begin
285
                case (grey[1:0])
286
                        2'b00: do_bin = 2'b00;
287
                        2'b01: do_bin = 2'b01;
288
                        2'b11: do_bin = 2'b10;
289
                        2'b10: do_bin = 2'b11;
290
                endcase
291
        end
292
end
293
endfunction
294
 
295
function [AW:0] get_cnt;
296
input [AW:0] wr_ptr, rd_ptr;
297
begin
298
        if (wr_ptr >= rd_ptr) begin
299
                get_cnt = (wr_ptr - rd_ptr);
300
        end
301
        else begin
302
                get_cnt = DP*2 - (rd_ptr - wr_ptr);
303
        end
304
end
305
endfunction
306
 
307
// synopsys translate_off
308
always @(posedge wr_clk) begin
309
   if (wr_en && full) begin
310
      $display($time, "%m Error! afifo overflow!");
311
      $stop;
312
   end
313
end
314
 
315
always @(posedge rd_clk) begin
316
   if (rd_en && empty) begin
317
      $display($time, "%m error! afifo underflow!");
318
      $stop;
319
   end
320
end
321
// synopsys translate_on
322
 
323
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.