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] - Rev 2

Compare with Previous | Blame | View Log

/*%
   memfifo -- Connects the bi-directional high speed interface of default firmware to a FIFO built of on-board SDRAM or on-chip BRAM
   Copyright (C) 2009-2017 ZTEX GmbH.
   http://www.ztex.de
 
   Copyright and related rights are licensed under the Solderpad Hardware
   License, Version 0.51 (the "License"); you may not use this file except
   in compliance with the License. You may obtain a copy of the License at
 
       http://solderpad.org/licenses/SHL-0.51.
 
   Unless required by applicable law or agreed to in writing, software, hardware
   and materials distributed under this License is distributed on an "AS IS"
   BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   implied. See the License for the specific language governing permissions
   and limitations under the License.
%*/
/* 
   Implements a huge FIFO  from all SDRAM.
*/  
 
 
module dram_fifo # (
      	parameter CLKOUT_DIVIDE = 2	// (2, 4, 8, 16, 32), see clkout
    ) (
 
	input fxclk_in,			// 48 MHz input clock pin
        input reset,
        output reset_out,		// reset output
      	output clkout,			// clock output 200MHz/CLKOUT_DIVIDE
	// ddr3 pins
	inout[15:0] ddr_dram_dq,
        inout ddr_rzq,
        inout ddr_zio,
        inout ddr_dram_udqs,
        inout ddr_dram_dqs,
	output[12:0] ddr_dram_a,
	output[1:0] ddr_dram_ba,
        output ddr_dram_cke,
        output ddr_dram_ras_n,
        output ddr_dram_cas_n,
        output ddr_dram_we_n,
        output ddr_dram_dm,
        output ddr_dram_udm,
        output ddr_dram_ck,
        output ddr_dram_ck_n,
 
	// FIFO protocol equal to FWFT FIFO in "7 Series Memory Resources" user guide (ug743)
	// input fifo interface
        input [31:0] DI,                // must be hold while FULL is asserted
        output FULL,                    // 1-bit output: Full flag
        output reg WRERR,               // 1-bit output: Write error
        input WRCLK,                    // 1-bit input: Rising edge write clock.
        input WREN,                     // 1-bit input: Write enable
 
	// output fifo interface
	output reg [31:0] DO,
	output reg EMPTY,               // 1-bit output: Empty flag, can be used as data valid indicator
        output reg RDERR,               // 1-bit output: Read error
        input RDCLK,                    // 1-bit input: Read clock
        input RDEN,                     // 1-bit input: Read enable
 
	// free memory
	output reg [APP_ADDR_WIDTH-1:0] mem_free_out,
 
	// for debugging
	output [9:0] status
    );
 
    localparam APP_ADDR_WIDTH = 18;	// 256 byte bursts
 
    wire fxclk, memclk, dcm0_locked, reset0, memclk_in;
 
    assign reset0 = reset || (!dcm0_locked);
    assign reset_out = reset0 || !c3_calib_done || c3_rst0;
 
    assign status[0] = reset;
    assign status[1] = dcm0_locked;
    assign status[2] = c3_calib_done;
    assign status[3] = c3_rst0;
    assign status[4] = WR_UNDERRUN[0] || WR_UNDERRUN[1] || WR_UNDERRUN[2];
    assign status[5] = WR_ERROR[0] || WR_ERROR[1] || WR_ERROR[2];
    assign status[6] = RD_OVERFLOW[0] || RD_OVERFLOW[1] || RD_OVERFLOW[2];
    assign status[7] = RD_ERROR[0] || RD_ERROR[1] || RD_ERROR[2];
    assign status[8] = FULL;
    assign status[9] = EMPTY; 
 
    // DRAM controller: status
    wire c3_calib_done, c3_rst0;
 
    // DRAM controller: writing
    reg reset_wr, WREN_BUF;
    reg [7:0] reset_wr_buf;
    reg [1:0] WR_PORT, WR_PORT2;
    reg [2:0] WR_CMD_EN, WR_EN;
    wire [2:0] WR_UNDERRUN, WR_ERROR, WR_EMPTY, WR_FULL;
    reg [APP_ADDR_WIDTH-1:0] WR_ADDR, WR_ADDR_FIRST, RD_ADDR_FIRST_WR1, RD_ADDR_FIRST_WR2;
    reg [31:0] WR_DATA;
    reg [6:0] WR_COUNT [0:2];
 
    // DRAM controller: reading
    reg reset_rd;
    reg [7:0] reset_rd_buf;
    reg [1:0] RD_PORT, RD_PORT2;
    reg [2:0] RD_CMD_EN, RD_EN;
    wire [2:0] RD_EMPTY, RD_OVERFLOW, RD_ERROR;
    wire [31:0] RD_DATA [0:2];
    reg [6:0] RD_COUNT [0:2];
    reg [APP_ADDR_WIDTH-1:0] RD_ADDR, RD_ADDR_NEXT, WR_ADDR_FIRST_RD1, WR_ADDR_FIRST_RD2, RD_ADDR_FIRST;
 
 
    DCM_CLKGEN #(
      .CLKFXDV_DIVIDE(CLKOUT_DIVIDE),       // CLKFXDV divide value (2, 4, 8, 16, 32)
      .CLKFX_DIVIDE(6),         // Divide value - D - (1-256)
      .CLKFX_MULTIPLY(25),      // Multiply value - M - (2-256)
      .CLKIN_PERIOD(20.833333),    // Input clock period specified in nS
      .SPREAD_SPECTRUM("NONE"), // Spread Spectrum mode "NONE", "CENTER_LOW_SPREAD", "CENTER_HIGH_SPREAD",
                                // "VIDEO_LINK_M0", "VIDEO_LINK_M1" or "VIDEO_LINK_M2" 
      .STARTUP_WAIT("FALSE")    // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE)
    )
    dcm0 (
      .CLKIN(fxclk),         // 1-bit input: Input clock
      .CLKFX(memclk_in),
      .CLKFX180(),              // 1-bit output: Generated clock output 180 degree out of phase from CLKFX.
      .CLKFXDV(clkout),         // 1-bit output: Divided clock output
      .LOCKED(dcm0_locked),     // 1-bit output: Locked output
      .PROGDONE(),              // 1-bit output: Active high output to indicate the successful re-programming
      .STATUS(),                // 2-bit output: DCM_CLKGEN status
      .FREEZEDCM(1'b0),         // 1-bit input: Prevents frequency adjustments to input clock
      .PROGCLK(1'b0),           // 1-bit input: Clock input for M/D reconfiguration
      .PROGDATA(1'b0),          // 1-bit input: Serial data input for M/D reconfiguration
      .PROGEN(1'b0),            // 1-bit input: Active high program enable
      .RST(reset)               // 1-bit input: Reset input pin
    );
 
    BUFG memclk_buf (
	.I(memclk_in),
	.O(memclk) 
    );
 
    BUFG fxclk_buf (
	.I(fxclk_in),
	.O(fxclk) 
    );
 
    mem0 # (
	.C3_P0_MASK_SIZE(4),
	.C3_P0_DATA_PORT_SIZE(32),
	.C3_P1_MASK_SIZE(4),
    	.C3_P1_DATA_PORT_SIZE(32),
    	.DEBUG_EN(0),
    	.C3_MEMCLK_PERIOD(5000),
    	.C3_CALIB_SOFT_IP("TRUE"),
    	.C3_SIMULATION("FALSE"),
    	.C3_RST_ACT_LOW(0),
    	.C3_INPUT_CLK_TYPE("SINGLE_ENDED"),
    	.C3_MEM_ADDR_ORDER("ROW_BANK_COLUMN"),
    	.C3_NUM_DQ_PINS(16),
    	.C3_MEM_ADDR_WIDTH(13),
    	.C3_MEM_BANKADDR_WIDTH(2)
    )
    u_mem0 (
  	.mcb3_dram_dq           (ddr_dram_dq),  
  	.mcb3_dram_a            (ddr_dram_a),  
  	.mcb3_dram_ba           (ddr_dram_ba),
  	.mcb3_dram_ras_n        (ddr_dram_ras_n),                        
  	.mcb3_dram_cas_n        (ddr_dram_cas_n),                        
  	.mcb3_dram_we_n         (ddr_dram_we_n),                          
  	.mcb3_dram_cke          (ddr_dram_cke),                          
  	.mcb3_dram_ck           (ddr_dram_ck),                          
  	.mcb3_dram_ck_n         (ddr_dram_ck_n),       
  	.mcb3_dram_dqs          (ddr_dram_dqs),
  	.mcb3_dram_udqs         (ddr_dram_udqs),    // for X16 parts
  	.mcb3_dram_udm          (ddr_dram_udm),     // for X16 parts
  	.mcb3_dram_dm           (ddr_dram_dm),
      	.mcb3_rzq               (ddr_rzq),
 
  	.c3_clk0	        (),
  	.c3_calib_done  	(c3_calib_done),
  	.c3_rst0	        (c3_rst0),
    	.c3_sys_clk           	(memclk),
  	.c3_sys_rst_i           (reset0),                        
 
     	.c3_p0_cmd_clk          (WRCLK),
   	.c3_p0_cmd_en           (WR_CMD_EN[0]),
   	.c3_p0_cmd_instr        (3'b000),
   	.c3_p0_cmd_bl           (6'd63),
   	.c3_p0_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
   	.c3_p0_cmd_empty        (),
   	.c3_p0_cmd_full         (),
   	.c3_p0_wr_clk           (WRCLK),
   	.c3_p0_wr_en            (WR_EN[0]),
   	.c3_p0_wr_mask          (4'd0),
   	.c3_p0_wr_data          (WR_DATA),
   	.c3_p0_wr_full          (WR_FULL[0]),
   	.c3_p0_wr_empty         (WR_EMPTY[0]),
   	.c3_p0_wr_count         (),
   	.c3_p0_wr_underrun      (WR_UNDERRUN[0]),
   	.c3_p0_wr_error         (WR_ERROR[0]),
   	.c3_p0_rd_clk           (WRCLK),
   	.c3_p0_rd_en            (1'b0),
   	.c3_p0_rd_data          (),
   	.c3_p0_rd_full          (),
   	.c3_p0_rd_empty         (),
   	.c3_p0_rd_count         (),
   	.c3_p0_rd_overflow      (),
   	.c3_p0_rd_error         (),
 
   	.c3_p1_cmd_clk          (RDCLK),
   	.c3_p1_cmd_en           (RD_CMD_EN[0]),
   	.c3_p1_cmd_instr        (3'b001),
   	.c3_p1_cmd_bl           (6'd63),
   	.c3_p1_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
   	.c3_p1_cmd_empty        (),
   	.c3_p1_cmd_full         (),
   	.c3_p1_wr_clk           (RDCLK),
   	.c3_p1_wr_en            (1'b0),
   	.c3_p1_wr_mask          (4'd0),
   	.c3_p1_wr_data          (32'd0),
   	.c3_p1_wr_full          (),
   	.c3_p1_wr_empty         (),
   	.c3_p1_wr_count         (),
   	.c3_p1_wr_underrun      (),
   	.c3_p1_wr_error         (),
   	.c3_p1_rd_clk           (RDCLK),
   	.c3_p1_rd_en            (RD_EN[0]),
   	.c3_p1_rd_data          (RD_DATA[0]),
   	.c3_p1_rd_full          (),
   	.c3_p1_rd_empty         (RD_EMPTY[0]),
   	.c3_p1_rd_count         (),
   	.c3_p1_rd_overflow      (RD_OVERFLOW[0]),
   	.c3_p1_rd_error         (RD_ERROR[0]),
 
     	.c3_p2_cmd_clk          (WRCLK),
   	.c3_p2_cmd_en           (WR_CMD_EN[1]),
   	.c3_p2_cmd_instr        (3'b000),
   	.c3_p2_cmd_bl           (6'd63),
   	.c3_p2_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
   	.c3_p2_cmd_empty        (),
   	.c3_p2_cmd_full         (),
   	.c3_p2_wr_clk           (WRCLK),
   	.c3_p2_wr_en            (WR_EN[1]),
   	.c3_p2_wr_mask          (4'd0),
   	.c3_p2_wr_data          (WR_DATA),
   	.c3_p2_wr_full          (WR_FULL[1]),
   	.c3_p2_wr_empty         (WR_EMPTY[1]),
   	.c3_p2_wr_count         (),
   	.c3_p2_wr_underrun      (WR_UNDERRUN[1]),
   	.c3_p2_wr_error         (WR_ERROR[1]),
 
   	.c3_p3_cmd_clk          (RDCLK),
   	.c3_p3_cmd_en           (RD_CMD_EN[1]),
   	.c3_p3_cmd_instr        (3'b001),
   	.c3_p3_cmd_bl           (6'd63),
   	.c3_p3_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
   	.c3_p3_cmd_empty        (),
   	.c3_p3_cmd_full         (),
   	.c3_p3_rd_clk           (RDCLK),
   	.c3_p3_rd_en            (RD_EN[1]),
   	.c3_p3_rd_data          (RD_DATA[1]),
   	.c3_p3_rd_full          (),
   	.c3_p3_rd_empty         (RD_EMPTY[1]),
   	.c3_p3_rd_count         (),
   	.c3_p3_rd_overflow      (RD_OVERFLOW[1]),
   	.c3_p3_rd_error         (RD_ERROR[1]),
 
     	.c3_p4_cmd_clk          (WRCLK),
   	.c3_p4_cmd_en           (WR_CMD_EN[2]),
   	.c3_p4_cmd_instr        (3'b000),
   	.c3_p4_cmd_bl           (6'd63),
   	.c3_p4_cmd_byte_addr    ( {4'd0, WR_ADDR, 8'd0} ),
   	.c3_p4_cmd_empty        (),
   	.c3_p4_cmd_full         (),
   	.c3_p4_wr_clk           (WRCLK),
   	.c3_p4_wr_en            (WR_EN[2]),
   	.c3_p4_wr_mask          (4'd0),
   	.c3_p4_wr_data          (WR_DATA),
   	.c3_p4_wr_full          (WR_FULL[2]),
   	.c3_p4_wr_empty         (WR_EMPTY[2]),
   	.c3_p4_wr_count         (),
   	.c3_p4_wr_underrun      (WR_UNDERRUN[2]),
   	.c3_p4_wr_error         (WR_ERROR[2]),
 
   	.c3_p5_cmd_clk          (RDCLK),
   	.c3_p5_cmd_en           (RD_CMD_EN[2]),
   	.c3_p5_cmd_instr        (3'b001),
   	.c3_p5_cmd_bl           (6'd63),
   	.c3_p5_cmd_byte_addr    ( {4'd0, RD_ADDR, 8'd0} ),
   	.c3_p5_cmd_empty        (),
   	.c3_p5_cmd_full         (),
   	.c3_p5_rd_clk           (RDCLK),
   	.c3_p5_rd_en            (RD_EN[2]),
   	.c3_p5_rd_data          (RD_DATA[2]),
   	.c3_p5_rd_full          (),
   	.c3_p5_rd_empty         (RD_EMPTY[2]),
   	.c3_p5_rd_count         (),
   	.c3_p5_rd_overflow      (RD_OVERFLOW[2]),
   	.c3_p5_rd_error         (RD_ERROR[2])
    );
 
    assign FULL = WR_COUNT[WR_PORT][6] || reset_wr;
 
    always @ (posedge WRCLK)
    begin
	reset_wr_buf <= { reset_out, reset_wr_buf[7:1] };
	reset_wr <= reset_wr_buf != 8'd0;
	WR_CMD_EN <= 3'd0;
	WR_EN <= 3'd0;
	if ( reset_wr )
	begin
	    WR_ADDR <= { APP_ADDR_WIDTH{1'b1} }; 	// 1st address is WR_ADDR+1
	    WR_ADDR_FIRST <= { APP_ADDR_WIDTH{1'b0} }; 
	    WR_PORT <= 2'd0;
	    WR_PORT2 <= 2'd0;
	    WRERR <= 1'b0;
	    RD_ADDR_FIRST_WR1 <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };
	    RD_ADDR_FIRST_WR2 <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };
	    WR_COUNT[0] <= 7'd0;
	    WR_COUNT[1] <= 7'd0;
	    WR_COUNT[2] <= 7'd0;
    	    WREN_BUF <= 1'b0;
	end else
	begin
	    RD_ADDR_FIRST_WR1 <= RD_ADDR_FIRST;		
	    RD_ADDR_FIRST_WR2 <= RD_ADDR_FIRST_WR1;
 
	    if ( WREN || WREN_BUF ) 		// process data
	    begin
		WR_EN[WR_PORT] <= !WR_COUNT[WR_PORT][6];
		WR_DATA <= DI;
		WREN_BUF <= WR_COUNT[WR_PORT][6];
	    end
	    WRERR <= WREN && WREN_BUF;
 
	    if ( WR_COUNT[WR_PORT] != 7'd65 ) // fifo stuff
	    begin
	        if ( WR_COUNT[WR_PORT][6] || ((WR_COUNT[WR_PORT]==7'd63) && WREN) )
	        begin
	    	    if ( RD_ADDR_FIRST_WR1==RD_ADDR_FIRST_WR2 && RD_ADDR_FIRST_WR1!=WR_ADDR )
		    begin
		        WR_CMD_EN[WR_PORT] <= 1'b1;
		        WR_PORT <= WR_PORT[1] ? 2'b00 : WR_PORT + 2'd1;
		        WR_ADDR <= WR_ADDR + 1;
		        WR_COUNT[WR_PORT] <= 7'd65;
		    end else
		    begin
		        WR_COUNT[WR_PORT] <= 7'd64;
		    end
		end else if ( WREN || WREN_BUF )
		begin
		    WR_COUNT[WR_PORT] <= WR_COUNT[WR_PORT] + 7'd1;
		end
	    end
 
    	    if ( WR_COUNT[WR_PORT2]==7'd65 && WR_EMPTY[WR_PORT2] && !WR_FULL[WR_PORT2])   // determines 1st (i.e. lowest) address in use
    	    begin
		WR_PORT2 <= WR_PORT2[1] ? 2'b00 : WR_PORT2 + 2'd1;
		WR_COUNT[WR_PORT2] <= 7'd0;
		WR_ADDR_FIRST <= WR_ADDR_FIRST + 1;
	    end
	end 
	mem_free_out <= RD_ADDR_FIRST_WR1 - WR_ADDR;
    end
 
    always @ (posedge RDCLK)
    begin
	reset_rd_buf <= { reset_out, reset_rd_buf[7:1] };
	reset_rd <= reset_rd_buf != 8'd0;
	RD_CMD_EN <= 3'd0;
	RD_EN <= 3'd0;
	RD_ADDR <= RD_ADDR_NEXT;
	if ( reset_rd )
	begin
	    RD_ADDR_NEXT <= { APP_ADDR_WIDTH{1'b0} };
	    RD_ADDR_FIRST <= { { (APP_ADDR_WIDTH-1){1'b1} }, 1'b0 };  // 1st addresse minus 1 that has to be read
	    RD_COUNT[0] <= 7'd0;
	    RD_COUNT[1] <= 7'd0;
	    RD_COUNT[2] <= 7'd0;
	    RD_PORT <= 2'd0;
	    RD_PORT2 <= 2'd0;
	    WR_ADDR_FIRST_RD1 <= { APP_ADDR_WIDTH{1'b0} };
	    WR_ADDR_FIRST_RD2 <= { APP_ADDR_WIDTH{1'b0} };
	    RDERR <= 1'b0;
	    EMPTY <= 1'b1;
	end else
	begin
	    RDERR <= RDEN && EMPTY;
 
	    if ( RDEN || EMPTY )
	    begin
		if ( (RD_COUNT[RD_PORT]!=7'd0) && (!RD_EMPTY[RD_PORT]) ) 
		begin
		    EMPTY <= 1'b0;
		    DO <= RD_DATA[RD_PORT];
//		    DO <= { RD_DATA[RD_PORT][23:0], 1'd0, RD_COUNT[RD_PORT] };
		    RD_COUNT[RD_PORT] <= RD_COUNT[RD_PORT] - 7'd1;
	    	    RD_EN[RD_PORT] <= 1'b1;
		    if ( (RD_COUNT[RD_PORT]==7'd1) )
		    begin
		        RD_PORT <= RD_PORT[1] ? 2'b00 : RD_PORT + 2'd1;
	    	    	RD_ADDR_FIRST <= RD_ADDR_FIRST + 1;
		    end
		end else
		begin
		    EMPTY <= 1'b1;
		end
	    end
 
	    WR_ADDR_FIRST_RD1 <= WR_ADDR_FIRST;		// cmd generator
	    WR_ADDR_FIRST_RD2 <= WR_ADDR_FIRST_RD1;
	    if ( (RD_ADDR_NEXT != WR_ADDR_FIRST_RD1) && (WR_ADDR_FIRST_RD1 == WR_ADDR_FIRST_RD2) && (RD_COUNT[RD_PORT2]==7'd0) )
	    begin
		RD_COUNT[RD_PORT2] <= 7'd64;
		RD_CMD_EN[RD_PORT2] <= 1'b1;
		RD_PORT2 <= RD_PORT2[1] ? 2'b00 : RD_PORT2 + 2'd1;
		RD_ADDR_NEXT <= RD_ADDR_NEXT + 1;
	    end
	end
    end
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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