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/] [default/] [fpga-fx3/] [ezusb_io.v] - Rev 2

Compare with Previous | Blame | View Log

/*%
   Common communication interface of default firmwares
   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 the bi-directional high speed interface of default 
   firmwares using the GPIF-II of FX3. It also includes an scheduler 
   (required if both directions are used at the same time) and short 
   packets (PKTEND).
 
   DMA0: FPGA --> FX3 transfers
   DMA1: FX3 --> FPGA transfers
*/  
module ezusb_io (
        output ifclk,
        input reset,                    // asynchronous reset input
        output reset_out,		// synchronous reset output
        // pins
        input ifclk_in,
        inout [15:0] fd,
	output reg SLWR, SLRD,	        // low active
	output reg SLOE, PKTEND,	// low active
	input EMPTY_FLAG, FULL_FLAG,	// almost full/empty due to flag latency of several clocks, low active
// signals for FPGA -> EZ-USB transfer
        input [15:0] DI,                // data written to EZ-USB
        input DI_valid,			// 1 indicates data valid; DI and DI_valid must be hold if DI_ready is 0
        output DI_ready, 		// 1 if new data are accepted
        input DI_enable,		// setting to 0 disables FPGA -> EZ-USB transfers
    	input pktend_arm,		// 0->1 transition enables the manual PKTEND mechanism:
    	                                // PKTEND is asserted as soon output becomes idle
    	                                // recommended procedure for accurate packet transfers:
    	                                //   * DI_valid goes low after last data of package
    	                                //   * monitor PKTEND and hold DI_valid until PKTEND is asserted (PKTEND = 0)
        input [15:0] pktend_timeout,	// automatic PKTEN assertion after pktend_timeout*65536 clocks of no output data
    					// setting to 0 disables this feature
	// signals for EZ-USB -> FPGA transfer
        output reg [15:0] DO,           // data read from EZ-USB
        output reg DO_valid,		// 1 indicated valid data
        input DO_ready,			// setting to 1 enables writing new data to DO in next clock; DO and DO_valid are hold if DO_ready is 0
    					// set to 0 to disable data reads 
        // debug output
        output [6:0] status
    );
 
 
    wire ifclk_inbuf, ifclk_fbin, ifclk_fbout, ifclk_out, locked;
 
    IBUFG ifclkin_buf (
	.I(ifclk_in),
	.O(ifclk_inbuf) 
    );
 
    BUFG ifclk_fb_buf (
        .I(ifclk_fbout),
        .O(ifclk_fbin)
     ); 
 
    BUFG ifclk_out_buf (
        .I(ifclk_out),
        .O(ifclk)
     ); 
 
    MMCME2_BASE #(
       .BANDWIDTH("OPTIMIZED"),
       .CLKFBOUT_MULT_F(10.0),
       .CLKFBOUT_PHASE(0.0),
       .CLKIN1_PERIOD(0.0),
       .CLKOUT0_DIVIDE_F(10.0), 
       .CLKOUT1_DIVIDE(1),
       .CLKOUT2_DIVIDE(1),
       .CLKOUT3_DIVIDE(1),
       .CLKOUT4_DIVIDE(1),
       .CLKOUT5_DIVIDE(1),
       .CLKOUT0_DUTY_CYCLE(0.5),
       .CLKOUT1_DUTY_CYCLE(0.5),
       .CLKOUT2_DUTY_CYCLE(0.5),
       .CLKOUT3_DUTY_CYCLE(0.5),
       .CLKOUT4_DUTY_CYCLE(0.5),
       .CLKOUT5_DUTY_CYCLE(0.5),
       .CLKOUT0_PHASE(0.0),
       .CLKOUT1_PHASE(0.0),
       .CLKOUT2_PHASE(0.0),
       .CLKOUT3_PHASE(0.0),
       .CLKOUT4_PHASE(0.0),
       .CLKOUT5_PHASE(0.0),
       .CLKOUT4_CASCADE("FALSE"), 
       .DIVCLK_DIVIDE(1),
       .REF_JITTER1(0.0),
       .STARTUP_WAIT("FALSE")
    )  isclk_mmcm_inst (
       .CLKOUT0(ifclk_out),
       .CLKFBOUT(ifclk_fbout),
       .CLKIN1(ifclk_inbuf),
       .PWRDWN(1'b0),
       .RST(reset),
       .CLKFBIN(ifclk_fbin),
       .LOCKED(locked)
    );
 
    reg reset_ifclk = 1;
    reg if_out;
    reg [4:0] if_out_delay;
    reg [15:0] fd_buf;
    reg [15:0] resend_buf0, resend_buf1, resend_buf2, resend_buf3;
    reg [3:0] resend, resend_valid;
 
    reg SLRD_buf1, SLRD_buf2;
    reg pktend_auto, pktend_arm_buf, pktend_arm_prev;
    reg [31:0] pktend_cnt;
    reg [15:0] DO_buf1, DO_buf2, DO_buf3;
    reg DO_buf1_valid, DO_buf2_valid, DO_buf3_valid;
 
    wire SLRD_next, SLWR_next;
 
    // FPGA <-> EZ-USB signals
    assign fd = if_out ? fd_buf : {16{1'bz}};
 
    assign status = { if_out, !SLRD, !SLWR, DI_valid, DO_ready, !EMPTY_FLAG, !FULL_FLAG };
 
    assign reset_out = reset || reset_ifclk;
 
    assign DI_ready = !reset_ifclk && FULL_FLAG && if_out && !resend[0];
    assign SLWR_next = reset_ifclk || !FULL_FLAG || !if_out || !(resend[0] || DI_valid);
 
    assign SLRD_next = reset_ifclk || !EMPTY_FLAG || if_out || !DO_ready || DO_buf1_valid;
 
    always @ (posedge ifclk)
    begin
	reset_ifclk <= reset || !locked;
 
	SLRD <= SLRD_next;
	SLRD_buf1 <= SLRD;
	SLRD_buf2 <= SLRD_buf1;
 
	SLWR <= SLWR_next;
 
	SLOE <= reset_ifclk || if_out;
 
	// FPGA --> EZ-USB
        if ( reset_ifclk )
        begin
	    resend <= 4'd0;
	    resend_valid <= 4'd0;
	end else if ( if_out )  
	begin
	    if ( FULL_FLAG ) 
	    begin
		fd_buf <= resend[0] ? resend_buf0 : DI;
		resend_buf0 <= resend_buf1;
		resend_buf1 <= resend_buf2;
		resend_buf2 <= resend_buf3;
		resend_buf3 <= DI;
		resend_valid <= { !resend[0] && DI_valid, resend_valid[3:1] };
		resend <= { 1'b0, resend[3:1] };
	    end else
	    begin
		resend <= resend_valid;  	// FLAGS are received three clocks after data.
	    end
	end
 
	// EZ-USB -> FPGA
	// SLRD -> DATA,FLAG latency is two clocks
	// DATA - FLAG latency is 0
	// if DO_ready goes low two data word have to be buffered
        if ( reset_ifclk )
        begin
	    DO_buf1_valid = 1'b0;
	    DO_buf2_valid = 1'b0;
	    DO_buf3_valid = 1'b0;
	end else if ( EMPTY_FLAG && !SLRD_buf2 )	// EZ-USB -> FPGA: valid data
	begin
	    if ( DO_ready && !DO_buf1_valid )
	    begin
		DO <= fd;
	    end else
	    begin					// buffers data if DO_ready has been deasserted
		DO_buf1 <= fd;
		DO_buf2 <= DO_buf1;
		DO_buf3 <= DO_buf2;
		DO_buf1_valid <= 1'b1;
		DO_buf2_valid <= DO_buf1_valid;
		DO_buf3_valid <= DO_buf2_valid;
	    end
	    if ( DO_ready ) DO_valid = !DO_buf1_valid;
	end else if ( DO_ready ) 
	begin
	    if ( DO_buf3_valid )			// writes buffered data
	    begin
		DO <= DO_buf3;
		DO_buf3_valid <= 1'b0;
	    end else if ( DO_buf2_valid )		// writes buffered data
	    begin
		DO <= DO_buf2;
		DO_buf2_valid <= 1'b0;
	    end else if ( DO_buf1_valid )		// writes buffered data
	    begin
		DO <= DO_buf1;
		DO_buf1_valid <= 1'b0;
	    end 
	    DO_valid <= DO_buf1_valid;
	end 
 
	// select direction
	if ( reset_ifclk )
	begin
	    if_out_delay = 5'd0;
	    if_out <= DI_enable;  	// direction of EZ-USB interface: 1 means FPGA --> EZ_USB
	end else if ( SLWR && SLRD && SLWR_next && SLRD_next ) 
	begin
	    if_out_delay <= { 1'b1, if_out_delay[4:1] };
	    if ( if_out_delay[0] ) if_out <= DI_enable && (!DO_ready || !EMPTY_FLAG || DO_buf1_valid);
	end else
	begin
	    if_out_delay = 5'd0;
	end
 
	// PKTEND processing
	pktend_arm_prev <= pktend_arm;
        if ( reset_ifclk || !SLWR || DI_valid || resend!=4'd0 || !FULL_FLAG )
        begin
    	    // auto mode is always enabled if data appears. It may send ZLP's.
    	    pktend_auto <= (!reset_ifclk) && (pktend_auto || !SLWR);
    	    pktend_cnt <= 32'd0;
    	    PKTEND <= 1'b1;
    	    pktend_arm_buf <= (!reset_ifclk) && ( pktend_arm_buf || ( pktend_arm && !pktend_arm_prev ) );
    	// PKTEND must not be asserted unless a buffer is available (FULL=1)
    	// assertion of PKTEND should also work during reading (SLRD=0), but this has not been tested
    	end else if ( /*SLRD && SLRD_next &&*/ FULL_FLAG && ( pktend_arm_buf || ( pktend_auto && (pktend_timeout != 16'd0) && (pktend_timeout == pktend_cnt[31:16]) ) ) )
    	begin
    	    PKTEND <= 1'b0;
    	    pktend_auto <= 1'b0;
    	    pktend_arm_buf <= 1'b0;
    	end else 
    	begin
    	    PKTEND <= 1'b1;
	    pktend_cnt <= pktend_cnt + 32'd1;
    	    pktend_arm_buf <= pktend_arm_buf || ( pktend_arm && !pktend_arm_prev );
    	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.