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

Subversion Repositories usb_fpga_2_14

[/] [usb_fpga_2_14/] [trunk/] [examples/] [memfifo/] [fpga-2.04b/] [dram_fifo.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ZTEX
/*%
2
   memfifo -- Connects the bi-directional high speed interface of default firmware to a FIFO built of on-board SDRAM or on-chip BRAM
3
   Copyright (C) 2009-2017 ZTEX GmbH.
4
   http://www.ztex.de
5
 
6
   Copyright and related rights are licensed under the Solderpad Hardware
7
   License, Version 0.51 (the "License"); you may not use this file except
8
   in compliance with the License. You may obtain a copy of the License at
9
 
10
       http://solderpad.org/licenses/SHL-0.51.
11
 
12
   Unless required by applicable law or agreed to in writing, software, hardware
13
   and materials distributed under this License is distributed on an "AS IS"
14
   BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15
   implied. See the License for the specific language governing permissions
16
   and limitations under the License.
17
%*/
18
/*
19
   Implements a huge FIFO  from all SDRAM.
20
*/
21
 
22
 
23
module dram_fifo # (
24
        parameter CLKOUT_DIVIDE = 2     // (2, 4, 8, 16, 32), see clkout
25
    ) (
26
 
27
        input fxclk_in,                 // 48 MHz input clock pin
28
        input reset,
29
        output reset_out,               // reset output
30
        output clkout,                  // clock output 200MHz/CLKOUT_DIVIDE
31
        // ddr3 pins
32
        inout[15:0] ddr_dram_dq,
33
        inout ddr_rzq,
34
        inout ddr_zio,
35
        inout ddr_dram_udqs,
36
        inout ddr_dram_dqs,
37
        output[12:0] ddr_dram_a,
38
        output[1:0] ddr_dram_ba,
39
        output ddr_dram_cke,
40
        output ddr_dram_ras_n,
41
        output ddr_dram_cas_n,
42
        output ddr_dram_we_n,
43
        output ddr_dram_dm,
44
        output ddr_dram_udm,
45
        output ddr_dram_ck,
46
        output ddr_dram_ck_n,
47
 
48
        // FIFO protocol equal to FWFT FIFO in "7 Series Memory Resources" user guide (ug743)
49
        // input fifo interface
50
        input [31:0] DI,                // must be hold while FULL is asserted
51
        output FULL,                    // 1-bit output: Full flag
52
        output reg WRERR,               // 1-bit output: Write error
53
        input WRCLK,                    // 1-bit input: Rising edge write clock.
54
        input WREN,                     // 1-bit input: Write enable
55
 
56
        // output fifo interface
57
        output reg [31:0] DO,
58
        output reg EMPTY,               // 1-bit output: Empty flag, can be used as data valid indicator
59
        output reg RDERR,               // 1-bit output: Read error
60
        input RDCLK,                    // 1-bit input: Read clock
61
        input RDEN,                     // 1-bit input: Read enable
62
 
63
        // free memory
64
        output reg [APP_ADDR_WIDTH-1:0] mem_free_out,
65
 
66
        // for debugging
67
        output [9:0] status
68
    );
69
 
70
    localparam APP_ADDR_WIDTH = 18;     // 256 byte bursts
71
 
72
    wire fxclk, memclk, dcm0_locked, reset0, memclk_in;
73
 
74
    assign reset0 = reset || (!dcm0_locked);
75
    assign reset_out = reset0 || !c3_calib_done || c3_rst0;
76
 
77
    assign status[0] = reset;
78
    assign status[1] = dcm0_locked;
79
    assign status[2] = c3_calib_done;
80
    assign status[3] = c3_rst0;
81
    assign status[4] = WR_UNDERRUN[0] || WR_UNDERRUN[1] || WR_UNDERRUN[2];
82
    assign status[5] = WR_ERROR[0] || WR_ERROR[1] || WR_ERROR[2];
83
    assign status[6] = RD_OVERFLOW[0] || RD_OVERFLOW[1] || RD_OVERFLOW[2];
84
    assign status[7] = RD_ERROR[0] || RD_ERROR[1] || RD_ERROR[2];
85
    assign status[8] = FULL;
86
    assign status[9] = EMPTY;
87
 
88
    // DRAM controller: status
89
    wire c3_calib_done, c3_rst0;
90
 
91
    // DRAM controller: writing
92
    reg reset_wr, WREN_BUF;
93
    reg [7:0] reset_wr_buf;
94
    reg [1:0] WR_PORT, WR_PORT2;
95
    reg [2:0] WR_CMD_EN, WR_EN;
96
    wire [2:0] WR_UNDERRUN, WR_ERROR, WR_EMPTY, WR_FULL;
97
    reg [APP_ADDR_WIDTH-1:0] WR_ADDR, WR_ADDR_FIRST, RD_ADDR_FIRST_WR1, RD_ADDR_FIRST_WR2;
98
    reg [31:0] WR_DATA;
99
    reg [6:0] WR_COUNT [0:2];
100
 
101
    // DRAM controller: reading
102
    reg reset_rd;
103
    reg [7:0] reset_rd_buf;
104
    reg [1:0] RD_PORT, RD_PORT2;
105
    reg [2:0] RD_CMD_EN, RD_EN;
106
    wire [2:0] RD_EMPTY, RD_OVERFLOW, RD_ERROR;
107
    wire [31:0] RD_DATA [0:2];
108
    reg [6:0] RD_COUNT [0:2];
109
    reg [APP_ADDR_WIDTH-1:0] RD_ADDR, RD_ADDR_NEXT, WR_ADDR_FIRST_RD1, WR_ADDR_FIRST_RD2, RD_ADDR_FIRST;
110
 
111
 
112
    DCM_CLKGEN #(
113
      .CLKFXDV_DIVIDE(CLKOUT_DIVIDE),       // CLKFXDV divide value (2, 4, 8, 16, 32)
114
      .CLKFX_DIVIDE(6),         // Divide value - D - (1-256)
115
      .CLKFX_MULTIPLY(25),      // Multiply value - M - (2-256)
116
      .CLKIN_PERIOD(20.833333),    // Input clock period specified in nS
117
      .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD",
118
                                // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2" 
119
      .STARTUP_WAIT("FALSE")    // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE)
120
    )
121
    dcm0 (
122
      .CLKIN(fxclk),         // 1-bit input: Input clock
123
      .CLKFX(memclk_in),
124
      .CLKFX180(),              // 1-bit output: Generated clock output 180 degree out of phase from CLKFX.
125
      .CLKFXDV(clkout),         // 1-bit output: Divided clock output
126
      .LOCKED(dcm0_locked),     // 1-bit output: Locked output
127
      .PROGDONE(),              // 1-bit output: Active high output to indicate the successful re-programming
128
      .STATUS(),                // 2-bit output: DCM_CLKGEN status
129
      .FREEZEDCM(1'b0),         // 1-bit input: Prevents frequency adjustments to input clock
130
      .PROGCLK(1'b0),           // 1-bit input: Clock input for M/D reconfiguration
131
      .PROGDATA(1'b0),          // 1-bit input: Serial data input for M/D reconfiguration
132
      .PROGEN(1'b0),            // 1-bit input: Active high program enable
133
      .RST(reset)               // 1-bit input: Reset input pin
134
    );
135
 
136
    BUFG memclk_buf (
137
        .I(memclk_in),
138
        .O(memclk)
139
    );
140
 
141
    BUFG fxclk_buf (
142
        .I(fxclk_in),
143
        .O(fxclk)
144
    );
145
 
146
    mem0 # (
147
        .C3_P0_MASK_SIZE(4),
148
        .C3_P0_DATA_PORT_SIZE(32),
149
        .C3_P1_MASK_SIZE(4),
150
        .C3_P1_DATA_PORT_SIZE(32),
151
        .DEBUG_EN(0),
152
        .C3_MEMCLK_PERIOD(5000),
153
        .C3_CALIB_SOFT_IP("TRUE"),
154
        .C3_SIMULATION("FALSE"),
155
        .C3_RST_ACT_LOW(0),
156
        .C3_INPUT_CLK_TYPE("SINGLE_ENDED"),
157
        .C3_MEM_ADDR_ORDER("ROW_BANK_COLUMN"),
158
        .C3_NUM_DQ_PINS(16),
159
        .C3_MEM_ADDR_WIDTH(13),
160
        .C3_MEM_BANKADDR_WIDTH(2)
161
    )
162
    u_mem0 (
163
        .mcb3_dram_dq           (ddr_dram_dq),
164
        .mcb3_dram_a            (ddr_dram_a),
165
        .mcb3_dram_ba           (ddr_dram_ba),
166
        .mcb3_dram_ras_n        (ddr_dram_ras_n),
167
        .mcb3_dram_cas_n        (ddr_dram_cas_n),
168
        .mcb3_dram_we_n         (ddr_dram_we_n),
169
        .mcb3_dram_cke          (ddr_dram_cke),
170
        .mcb3_dram_ck           (ddr_dram_ck),
171
        .mcb3_dram_ck_n         (ddr_dram_ck_n),
172
        .mcb3_dram_dqs          (ddr_dram_dqs),
173
        .mcb3_dram_udqs         (ddr_dram_udqs),    // for X16 parts
174
        .mcb3_dram_udm          (ddr_dram_udm),     // for X16 parts
175
        .mcb3_dram_dm           (ddr_dram_dm),
176
        .mcb3_rzq               (ddr_rzq),
177
 
178
        .c3_clk0                (),
179
        .c3_calib_done          (c3_calib_done),
180
        .c3_rst0                (c3_rst0),
181
        .c3_sys_clk             (memclk),
182
        .c3_sys_rst_i           (reset0),
183
 
184
        .c3_p0_cmd_clk          (WRCLK),
185
        .c3_p0_cmd_en           (WR_CMD_EN[0]),
186
        .c3_p0_cmd_instr        (3'b000),
187
        .c3_p0_cmd_bl           (6'd63),
188
        .c3_p0_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
189
        .c3_p0_cmd_empty        (),
190
        .c3_p0_cmd_full         (),
191
        .c3_p0_wr_clk           (WRCLK),
192
        .c3_p0_wr_en            (WR_EN[0]),
193
        .c3_p0_wr_mask          (4'd0),
194
        .c3_p0_wr_data          (WR_DATA),
195
        .c3_p0_wr_full          (WR_FULL[0]),
196
        .c3_p0_wr_empty         (WR_EMPTY[0]),
197
        .c3_p0_wr_count         (),
198
        .c3_p0_wr_underrun      (WR_UNDERRUN[0]),
199
        .c3_p0_wr_error         (WR_ERROR[0]),
200
        .c3_p0_rd_clk           (WRCLK),
201
        .c3_p0_rd_en            (1'b0),
202
        .c3_p0_rd_data          (),
203
        .c3_p0_rd_full          (),
204
        .c3_p0_rd_empty         (),
205
        .c3_p0_rd_count         (),
206
        .c3_p0_rd_overflow      (),
207
        .c3_p0_rd_error         (),
208
 
209
        .c3_p1_cmd_clk          (RDCLK),
210
        .c3_p1_cmd_en           (RD_CMD_EN[0]),
211
        .c3_p1_cmd_instr        (3'b001),
212
        .c3_p1_cmd_bl           (6'd63),
213
        .c3_p1_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
214
        .c3_p1_cmd_empty        (),
215
        .c3_p1_cmd_full         (),
216
        .c3_p1_wr_clk           (RDCLK),
217
        .c3_p1_wr_en            (1'b0),
218
        .c3_p1_wr_mask          (4'd0),
219
        .c3_p1_wr_data          (32'd0),
220
        .c3_p1_wr_full          (),
221
        .c3_p1_wr_empty         (),
222
        .c3_p1_wr_count         (),
223
        .c3_p1_wr_underrun      (),
224
        .c3_p1_wr_error         (),
225
        .c3_p1_rd_clk           (RDCLK),
226
        .c3_p1_rd_en            (RD_EN[0]),
227
        .c3_p1_rd_data          (RD_DATA[0]),
228
        .c3_p1_rd_full          (),
229
        .c3_p1_rd_empty         (RD_EMPTY[0]),
230
        .c3_p1_rd_count         (),
231
        .c3_p1_rd_overflow      (RD_OVERFLOW[0]),
232
        .c3_p1_rd_error         (RD_ERROR[0]),
233
 
234
        .c3_p2_cmd_clk          (WRCLK),
235
        .c3_p2_cmd_en           (WR_CMD_EN[1]),
236
        .c3_p2_cmd_instr        (3'b000),
237
        .c3_p2_cmd_bl           (6'd63),
238
        .c3_p2_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
239
        .c3_p2_cmd_empty        (),
240
        .c3_p2_cmd_full         (),
241
        .c3_p2_wr_clk           (WRCLK),
242
        .c3_p2_wr_en            (WR_EN[1]),
243
        .c3_p2_wr_mask          (4'd0),
244
        .c3_p2_wr_data          (WR_DATA),
245
        .c3_p2_wr_full          (WR_FULL[1]),
246
        .c3_p2_wr_empty         (WR_EMPTY[1]),
247
        .c3_p2_wr_count         (),
248
        .c3_p2_wr_underrun      (WR_UNDERRUN[1]),
249
        .c3_p2_wr_error         (WR_ERROR[1]),
250
 
251
        .c3_p3_cmd_clk          (RDCLK),
252
        .c3_p3_cmd_en           (RD_CMD_EN[1]),
253
        .c3_p3_cmd_instr        (3'b001),
254
        .c3_p3_cmd_bl           (6'd63),
255
        .c3_p3_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
256
        .c3_p3_cmd_empty        (),
257
        .c3_p3_cmd_full         (),
258
        .c3_p3_rd_clk           (RDCLK),
259
        .c3_p3_rd_en            (RD_EN[1]),
260
        .c3_p3_rd_data          (RD_DATA[1]),
261
        .c3_p3_rd_full          (),
262
        .c3_p3_rd_empty         (RD_EMPTY[1]),
263
        .c3_p3_rd_count         (),
264
        .c3_p3_rd_overflow      (RD_OVERFLOW[1]),
265
        .c3_p3_rd_error         (RD_ERROR[1]),
266
 
267
        .c3_p4_cmd_clk          (WRCLK),
268
        .c3_p4_cmd_en           (WR_CMD_EN[2]),
269
        .c3_p4_cmd_instr        (3'b000),
270
        .c3_p4_cmd_bl           (6'd63),
271
        .c3_p4_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
272
        .c3_p4_cmd_empty        (),
273
        .c3_p4_cmd_full         (),
274
        .c3_p4_wr_clk           (WRCLK),
275
        .c3_p4_wr_en            (WR_EN[2]),
276
        .c3_p4_wr_mask          (4'd0),
277
        .c3_p4_wr_data          (WR_DATA),
278
        .c3_p4_wr_full          (WR_FULL[2]),
279
        .c3_p4_wr_empty         (WR_EMPTY[2]),
280
        .c3_p4_wr_count         (),
281
        .c3_p4_wr_underrun      (WR_UNDERRUN[2]),
282
        .c3_p4_wr_error         (WR_ERROR[2]),
283
 
284
        .c3_p5_cmd_clk          (RDCLK),
285
        .c3_p5_cmd_en           (RD_CMD_EN[2]),
286
        .c3_p5_cmd_instr        (3'b001),
287
        .c3_p5_cmd_bl           (6'd63),
288
        .c3_p5_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
289
        .c3_p5_cmd_empty        (),
290
        .c3_p5_cmd_full         (),
291
        .c3_p5_rd_clk           (RDCLK),
292
        .c3_p5_rd_en            (RD_EN[2]),
293
        .c3_p5_rd_data          (RD_DATA[2]),
294
        .c3_p5_rd_full          (),
295
        .c3_p5_rd_empty         (RD_EMPTY[2]),
296
        .c3_p5_rd_count         (),
297
        .c3_p5_rd_overflow      (RD_OVERFLOW[2]),
298
        .c3_p5_rd_error         (RD_ERROR[2])
299
    );
300
 
301
    assign FULL = WR_COUNT[WR_PORT][6] || reset_wr;
302
 
303
    always @ (posedge WRCLK)
304
    begin
305
        reset_wr_buf <= { reset_out, reset_wr_buf[7:1] };
306
        reset_wr <= reset_wr_buf != 8'd0;
307
        WR_CMD_EN <= 3'd0;
308
        WR_EN <= 3'd0;
309
        if ( reset_wr )
310
        begin
311
            WR_ADDR <= { APP_ADDR_WIDTH{1'b1} };        // 1st address is WR_ADDR+1
312
            WR_ADDR_FIRST <= { APP_ADDR_WIDTH{1'b0} };
313
            WR_PORT <= 2'd0;
314
            WR_PORT2 <= 2'd0;
315
            WRERR <= 1'b0;
316
            RD_ADDR_FIRST_WR1 <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };
317
            RD_ADDR_FIRST_WR2 <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };
318
            WR_COUNT[0] <= 7'd0;
319
            WR_COUNT[1] <= 7'd0;
320
            WR_COUNT[2] <= 7'd0;
321
            WREN_BUF <= 1'b0;
322
        end else
323
        begin
324
            RD_ADDR_FIRST_WR1 <= RD_ADDR_FIRST;
325
            RD_ADDR_FIRST_WR2 <= RD_ADDR_FIRST_WR1;
326
 
327
            if ( WREN || WREN_BUF )             // process data
328
            begin
329
                WR_EN[WR_PORT] <= !WR_COUNT[WR_PORT][6];
330
                WR_DATA <= DI;
331
                WREN_BUF <= WR_COUNT[WR_PORT][6];
332
            end
333
            WRERR <= WREN && WREN_BUF;
334
 
335
            if ( WR_COUNT[WR_PORT] != 7'd65 ) // fifo stuff
336
            begin
337
                if ( WR_COUNT[WR_PORT][6] || ((WR_COUNT[WR_PORT]==7'd63) && WREN) )
338
                begin
339
                    if ( RD_ADDR_FIRST_WR1==RD_ADDR_FIRST_WR2 && RD_ADDR_FIRST_WR1!=WR_ADDR )
340
                    begin
341
                        WR_CMD_EN[WR_PORT] <= 1'b1;
342
                        WR_PORT <= WR_PORT[1] ? 2'b00 : WR_PORT + 2'd1;
343
                        WR_ADDR <= WR_ADDR + 1;
344
                        WR_COUNT[WR_PORT] <= 7'd65;
345
                    end else
346
                    begin
347
                        WR_COUNT[WR_PORT] <= 7'd64;
348
                    end
349
                end else if ( WREN || WREN_BUF )
350
                begin
351
                    WR_COUNT[WR_PORT] <= WR_COUNT[WR_PORT] + 7'd1;
352
                end
353
            end
354
 
355
            if ( WR_COUNT[WR_PORT2]==7'd65 && WR_EMPTY[WR_PORT2] && !WR_FULL[WR_PORT2])   // determines 1st (i.e. lowest) address in use
356
            begin
357
                WR_PORT2 <= WR_PORT2[1] ? 2'b00 : WR_PORT2 + 2'd1;
358
                WR_COUNT[WR_PORT2] <= 7'd0;
359
                WR_ADDR_FIRST <= WR_ADDR_FIRST + 1;
360
            end
361
        end
362
        mem_free_out <= RD_ADDR_FIRST_WR1 - WR_ADDR;
363
    end
364
 
365
    always @ (posedge RDCLK)
366
    begin
367
        reset_rd_buf <= { reset_out, reset_rd_buf[7:1] };
368
        reset_rd <= reset_rd_buf != 8'd0;
369
        RD_CMD_EN <= 3'd0;
370
        RD_EN <= 3'd0;
371
        RD_ADDR <= RD_ADDR_NEXT;
372
        if ( reset_rd )
373
        begin
374
            RD_ADDR_NEXT <= { APP_ADDR_WIDTH{1'b0} };
375
            RD_ADDR_FIRST <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };  // 1st addresse minus 1 that has to be read
376
            RD_COUNT[0] <= 7'd0;
377
            RD_COUNT[1] <= 7'd0;
378
            RD_COUNT[2] <= 7'd0;
379
            RD_PORT <= 2'd0;
380
            RD_PORT2 <= 2'd0;
381
            WR_ADDR_FIRST_RD1 <= { APP_ADDR_WIDTH{1'b0} };
382
            WR_ADDR_FIRST_RD2 <= { APP_ADDR_WIDTH{1'b0} };
383
            RDERR <= 1'b0;
384
            EMPTY <= 1'b1;
385
        end else
386
        begin
387
            RDERR <= RDEN && EMPTY;
388
 
389
            if ( RDEN || EMPTY )
390
            begin
391
                if ( (RD_COUNT[RD_PORT]!=7'd0) && (!RD_EMPTY[RD_PORT]) )
392
                begin
393
                    EMPTY <= 1'b0;
394
                    DO <= RD_DATA[RD_PORT];
395
//                  DO <= { RD_DATA[RD_PORT][23:0], 1'd0, RD_COUNT[RD_PORT] };
396
                    RD_COUNT[RD_PORT] <= RD_COUNT[RD_PORT] - 7'd1;
397
                    RD_EN[RD_PORT] <= 1'b1;
398
                    if ( (RD_COUNT[RD_PORT]==7'd1) )
399
                    begin
400
                        RD_PORT <= RD_PORT[1] ? 2'b00 : RD_PORT + 2'd1;
401
                        RD_ADDR_FIRST <= RD_ADDR_FIRST + 1;
402
                    end
403
                end else
404
                begin
405
                    EMPTY <= 1'b1;
406
                end
407
            end
408
 
409
            WR_ADDR_FIRST_RD1 <= WR_ADDR_FIRST;         // cmd generator
410
            WR_ADDR_FIRST_RD2 <= WR_ADDR_FIRST_RD1;
411
            if ( (RD_ADDR_NEXT != WR_ADDR_FIRST_RD1) && (WR_ADDR_FIRST_RD1 == WR_ADDR_FIRST_RD2) && (RD_COUNT[RD_PORT2]==7'd0) )
412
            begin
413
                RD_COUNT[RD_PORT2] <= 7'd64;
414
                RD_CMD_EN[RD_PORT2] <= 1'b1;
415
                RD_PORT2 <= RD_PORT2[1] ? 2'b00 : RD_PORT2 + 2'd1;
416
                RD_ADDR_NEXT <= RD_ADDR_NEXT + 1;
417
            end
418
        end
419
    end
420
 
421
endmodule
422
 

powered by: WebSVN 2.1.0

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