//////////////////////////////////////////////////////////////////////////////// // // Create Date: 09/20/08 // Module Name: USBinf // Description: Implement a simple interface for Digilent USB interface // // // // Revision: // Revision 0.01 - File Created // // File format: This file has been formated to use tabstop of 4 // // Development platform: Spartan-3 Nexys from Digilent // // Copyright (C) 2008, Rick Huang // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // //////////////////////////////////////////////////////////////////////////////// module USBinf (clk, reset, EppAstb, EppDstb, EppWr, EppWait, EppDB, wADR_O, wSTB_O, wDAT_O, wDAT_I, wACK_I, wWE_O ); // Basic connections input clk; input reset; // USB connection input EppAstb; input EppDstb; input EppWr; output EppWait; inout [7:0] EppDB; // Wishbone bus connections output [15:0] wADR_O; output wSTB_O; output [7:0] wDAT_O; input [7:0] wDAT_I; input wACK_I; output wWE_O; // Sync up the external signals reg EppAstbReg; reg EppDstbReg; reg EppWrReg; always @ (posedge clk) begin EppAstbReg <= EppAstb; EppDstbReg <= EppDstb; EppWrReg <= EppWr; end // Local storage reg [15:0] wADR_O; reg wSTB_O; reg [7:0] wDAT_O; reg wWE_O; parameter STATE_INIT = 4'd0; parameter STATE_AD_WR = 4'd1; parameter STATE_AD_RD = 4'd2; parameter STATE_AD_RD1 = 4'd3; parameter STATE_DD_WR = 4'd4; parameter STATE_DD_WR1 = 4'd5; parameter STATE_DD_WR2 = 4'd6; parameter STATE_DD_RD = 4'd7; parameter STATE_DD_RD1 = 4'd8; parameter STATE_DD_RD2 = 4'd9; parameter STATE_END = 4'd10; parameter TIMEOUT_SET = 12'd2048; reg [3:0] xfr_state; reg [2:0] addr; reg EppWait; reg [7:0] Dout; reg DoutEn; assign EppDB = DoutEn ? Dout : 8'bz; reg [11:0] wbTimeout; // RAM read/write test always @ (posedge clk) begin if(reset) begin EppWait <= 0; xfr_state <= STATE_INIT; end else begin if(EppWrReg == 1) DoutEn <= 1; else DoutEn <= 0; case (xfr_state) STATE_INIT: begin wbTimeout <= 0; if(EppAstbReg == 0 && EppWrReg == 0) xfr_state <= STATE_AD_WR; else if(EppDstbReg == 0 && EppWrReg == 0) xfr_state <= STATE_DD_WR; else if(EppAstbReg == 0 && EppWrReg == 1) xfr_state <= STATE_AD_RD; else if(EppDstbReg == 0 && EppWrReg == 1) xfr_state <= STATE_DD_RD; end STATE_AD_WR: begin EppWait <= 1; addr <= EppDB[2:0]; xfr_state <= STATE_END; end STATE_AD_RD: begin Dout <= {5'b0, addr}; xfr_state <= STATE_AD_RD1; end STATE_AD_RD1: begin EppWait <= 1; xfr_state <= STATE_END; end STATE_END: begin if(EppAstbReg == 1 && EppDstbReg == 1) begin xfr_state <= STATE_INIT; EppWait <= 0; wWE_O <= 0; end end STATE_DD_WR: begin if(addr == 0) begin wADR_O[7:0] <= EppDB; EppWait <= 1; xfr_state <= STATE_DD_WR1; end else if(addr == 1) begin wADR_O[15:8] <= EppDB; EppWait <= 1; xfr_state <= STATE_DD_WR1; end else if(addr == 3) begin wDAT_O <= EppDB; wSTB_O <= 1; wWE_O <= 1; xfr_state <= STATE_DD_WR2; end end STATE_DD_WR1: begin xfr_state <= STATE_END; end STATE_DD_WR2: begin wbTimeout <= wbTimeout + 1; if(wbTimeout == TIMEOUT_SET) begin wSTB_O <= 0; xfr_state <= STATE_END; end else if(wACK_I == 1) begin EppWait <= 1; wSTB_O <= 0; xfr_state <= STATE_DD_WR1; end end STATE_DD_RD: begin case (addr) 3'b000: begin Dout <= wADR_O[7:0]; xfr_state <= STATE_DD_RD2; end 3'b001: begin Dout <= wADR_O[15:8]; xfr_state <= STATE_DD_RD2; end 3'b010: begin Dout <= 7'hff; xfr_state <= STATE_DD_RD2; end 3'b011: begin wSTB_O <= 1; wWE_O <= 0; xfr_state <= STATE_DD_RD1; end default: begin Dout <= 8'h0; xfr_state <= STATE_DD_RD2; end endcase end STATE_DD_RD1: begin wbTimeout <= wbTimeout + 1; if(wbTimeout == TIMEOUT_SET) begin wSTB_O <= 0; xfr_state <= STATE_END; end if(wACK_I == 1) begin wSTB_O <= 0; xfr_state <= STATE_DD_RD2; Dout <= wDAT_I; end end STATE_DD_RD2: begin EppWait <= 1; xfr_state <= STATE_END; end endcase end // Reset block end // Always block endmodule