www.pudn.com > usb_funct.rar > usbf_utmi_ls.v
/////////////////////////////////////////////////////////////////////
//// ////
//// UTMI Line Status & Speed Negotiation block ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// ////
//// Downloaded from: http://www.opencores.org/cores/usb/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer.////
//// ////
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
//// POSSIBILITY OF SUCH DAMAGE. ////
//// ////
/////////////////////////////////////////////////////////////////////
// CVS Log
//
// $Id: usbf_utmi_ls.v,v 1.2 2001/08/10 08:48:33 rudi Exp $
//
// $Date: 2001/08/10 08:48:33 $
// $Revision: 1.2 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: usbf_utmi_ls.v,v $
// Revision 1.2 2001/08/10 08:48:33 rudi
//
// - Changed IO names to be more clear.
// - Uniquifyed define names to be core specific.
//
// Revision 1.1 2001/08/03 05:30:09 rudi
//
//
// 1) Reorganized directory structure
//
// Revision 1.2 2001/03/31 13:00:52 rudi
//
// - Added Core configuration
// - Added handling of OUT packets less than MAX_PL_SZ in DMA mode
// - Modified WISHBONE interface and sync logic
// - Moved SSRAM outside the core (added interface)
// - Many small bug fixes ...
//
// Revision 1.1 2001/03/07 09:08:13 rudi
//
// Added USB control signaling (Line Status) block. Fixed some minor
// typos, added resume bit and signal.
//
//
//
`include "usbf_defines.v"
module usbf_utmi_ls( clk, rst,
resume_req,
// UTMI Interface
rx_active, tx_ready, drive_k,
XcvSelect, TermSel, SuspendM, LineState, OpMode,
usb_vbus,
// Misc Interfaces
mode_hs, usb_reset, usb_suspend, usb_attached
);
input clk;
input rst;
input resume_req;
input rx_active, tx_ready;
output drive_k;
output XcvSelect;
output TermSel;
output SuspendM;
input [1:0] LineState;
output [1:0] OpMode;
input usb_vbus;
output mode_hs; // High Speed Mode
output usb_reset; // USB Reset
output usb_suspend; // USB Suspend
output usb_attached; // Attached to USB
///////////////////////////////////////////////////////////////////
//
// Parameters
//
parameter [14:0] // synopsys enum state
POR = 15'b000_0000_0000_0001,
NORMAL = 15'b000_0000_0000_0010,
RES_SUSP = 15'b000_0000_0000_0100,
SUSPEND = 15'b000_0000_0000_1000,
RESUME = 15'b000_0000_0001_0000,
RESUME_REQ = 15'b000_0000_0010_0000,
RESUME_WAIT = 15'b000_0000_0100_0000,
RESUME_SIG = 15'b000_0000_1000_0000,
ATTACH = 15'b000_0001_0000_0000,
RESET = 15'b000_0010_0000_0000,
SPEED_NEG = 15'b000_0100_0000_0000,
SPEED_NEG_K = 15'b000_1000_0000_0000,
SPEED_NEG_J = 15'b001_0000_0000_0000,
SPEED_NEG_HS = 15'b010_0000_0000_0000,
SPEED_NEG_FS = 15'b100_0000_0000_0000;
///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//
reg [14:0] /* synopsys enum state */ state, next_state;
// synopsys state_vector state
reg [1:0] line_state_r;
reg mode_hs, mode_set_hs, mode_set_fs;
reg usb_suspend, suspend_set, suspend_clr;
reg usb_attached, attached_set, attached_clr;
reg TermSel, fs_term_on, fs_term_off;
reg XcvSelect, xcv_set_hs, xcv_set_fs;
reg [1:0] OpMode;
reg bit_stuff_on, bit_stuff_off;
reg usb_reset, usb_reset_d;
wire ls_se0, ls_j, ls_k, ls_se1;
reg ls_k_r, ls_j_r, ls_se0_r;
reg ls_idle_r, ls_idle_r1;
wire ls_idle;
reg idle_long;
wire idle_long_set, idle_long_clr;
wire k_long, j_long, se0_long;
reg drive_k, drive_k_d;
reg [3:0] ps_cnt;
reg ps_cnt_clr;
reg idle_cnt_clr;
reg idle_cnt1_clr;
reg [7:0] idle_cnt1, idle_cnt1_next;
reg [5:0] idle_cnt2;
reg T1_gt_2_5_uS, T1_gt_100_uS, T1_st_3_0_mS, T1_gt_3_0_mS;
reg T1_gt_3_125_mS, T1_gt_5_0_mS;
reg [7:0] me_ps;
reg me_cnt_clr;
reg me_ps_2_5_us;
reg [7:0] me_ps2;
reg me_ps2_0_5_ms;
reg [7:0] me_cnt;
reg me_cnt_100_ms;
reg T2_gt_100_uS, T2_wakeup, T2_gt_1_0_mS, T2_gt_1_2_mS;
reg [2:0] chirp_cnt;
reg chirp_cnt_clr, chirp_cnt_inc;
reg chirp_cnt_is_6;
wire resume_req_sr;
///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
always @(posedge clk)
drive_k <= #1 drive_k_d;
assign SuspendM = (usb_suspend & !resume_req_sr) | (LineState == 2'b10);
assign resume_req_sr = (!rst | usb_suspend) ? 0 : resume_req ? 1 : resume_req_sr;
// ---------------------------------------------------------
// USB State/Operation Mode JK Flops
always @(posedge clk)
if(mode_set_fs) mode_hs <= #1 0;
else
if(mode_set_hs) mode_hs <= #1 1;
always @(posedge clk)
if(suspend_clr) usb_suspend <= #1 0;
else
if(suspend_set) usb_suspend <= #1 1;
always @(posedge clk)
if(attached_clr) usb_attached <= #1 0;
else
if(attached_set) usb_attached <= #1 1;
always @(posedge clk)
if(fs_term_off) TermSel <= #1 0;
else
if(fs_term_on) TermSel <= #1 1;
always @(posedge clk)
if(xcv_set_fs) XcvSelect <= #1 1;
else
if(xcv_set_hs) XcvSelect <= #1 0;
always @(posedge clk)
if(bit_stuff_off) OpMode <= #1 2'b10;
else
if(bit_stuff_on) OpMode <= #1 2'b00;
always @(posedge clk)
usb_reset <= #1 usb_reset_d;
// ---------------------------------------------------------
// Line State Detector
always @(posedge clk)
line_state_r <= #1 LineState;
assign ls_se0 = (line_state_r == 2'b00);
assign ls_j = (line_state_r == 2'b01);
assign ls_k = (line_state_r == 2'b10);
assign ls_se1 = (line_state_r == 2'b11);
assign ls_idle = mode_hs ? ls_se0 : ls_j;
// Idle Detection
// Idle Has to persist for at least two cycles in a roe in the
// same state to recognized
always @(posedge clk)
ls_idle_r <= #1 ls_idle;
assign idle_long_set = ls_idle & ls_idle_r;
assign idle_long_clr = !ls_idle & !ls_idle_r;
always @(posedge clk)
if(!rst) idle_long <= #1 0;
else
if(idle_long_clr) idle_long <= #1 0;
else
if(idle_long_set) idle_long <= #1 1;
// Detect Signals for two cycles ina row before making a transaction ...
always @(posedge clk)
ls_k_r <= #1 ls_k;
always @(posedge clk)
ls_j_r <= #1 ls_j;
always @(posedge clk)
ls_se0_r <= #1 ls_se0;
assign k_long = ls_k & ls_k_r;
assign j_long = ls_j & ls_j_r;
assign se0_long = ls_se0 & ls_se0_r;
///////////////////////////////////////////////////////////////////
//
// Counters
//
// ---------------------------------------------------------
// idle Counter
// Pre-Scaler
// Generates a 0.25 uS Count Enable (ps_cnt_clr)
always @(posedge clk)
if(!idle_long | idle_cnt_clr | ps_cnt_clr) ps_cnt <= #1 0;
else ps_cnt <= #1 ps_cnt + 1;
always @(posedge clk) // Clear the pre-scaler in 250 nS intervals
ps_cnt_clr <= #1 (ps_cnt == `USBF_T1_PS_250_NS);
// Count uS
always @(posedge clk)
if(!idle_long | idle_cnt1_clr | idle_cnt_clr) idle_cnt1 <= #1 0;
else
if(!T1_gt_3_125_mS & ps_cnt_clr) idle_cnt1 <= #1 idle_cnt1_next;
always @(posedge clk)
idle_cnt1_next <= #1 idle_cnt1 + 1;
always @(posedge clk) // Clear the uS counter every 62.5 uS
idle_cnt1_clr <= #1 idle_cnt1 == `USBF_T1_C_62_5_US;
// Count mS
always @(posedge clk)
if(!idle_long | idle_cnt_clr) idle_cnt2 <= #1 0;
else
if(!T1_gt_5_0_mS & idle_cnt1_clr) idle_cnt2 <= #1 idle_cnt2 + 1;
always @(posedge clk) // Greater Than 2.5uS (Actual Time will be T0+2.75uS)
T1_gt_2_5_uS <= #1 !idle_cnt_clr & (idle_cnt1 > `USBF_T1_C_2_5_US);
always @(posedge clk) // Greater Than 100uS (Actual Time will be T0+187.5uS)
T1_gt_100_uS <= #1 !idle_cnt_clr & (`USBF_T1_C_100_US < idle_cnt2);
always @(posedge clk) // Smaller Than 3 mS (Actual Time will be 0-2.9375mS)
T1_st_3_0_mS <= #1 !idle_cnt_clr & (idle_cnt1 < `USBF_T1_C_3_0_MS);
always @(posedge clk) // Greater Than 3 mS (Actual Time will be T0+3.0625mS)
T1_gt_3_0_mS <= #1 !idle_cnt_clr & (idle_cnt1 > `USBF_T1_C_3_0_MS);
always @(posedge clk) // Greater Than 3.125 mS (Actual Time will be T0+3.1875uS)
T1_gt_3_125_mS <= #1 !idle_cnt_clr & (idle_cnt1 > `USBF_T1_C_3_125_MS);
always @(posedge clk) // Greater Than 3.125 mS (Actual Time will be T0+3.1875uS)
T1_gt_5_0_mS <= #1 !idle_cnt_clr & (idle_cnt1 > `USBF_T1_C_5_MS);
// ---------------------------------------------------------
// Misc Events Counter
// Pre-scaler - 2.5uS
always @(posedge clk)
if(me_cnt_clr | me_ps_2_5_us) me_ps <= #1 0;
else me_ps <= #1 me_ps + 1;
always @(posedge clk) // Generate a pulse every 2.5 uS
me_ps_2_5_us <= #1 (me_ps == `USBF_T2_C_2_5_US);
// Second Pre-scaler - 0.5mS
always @(posedge clk)
if(me_cnt_clr | me_ps2_0_5_ms ) me_ps2 <= #1 0;
else
if(me_ps_2_5_us) me_ps2 <= #1 me_ps2 + 1;
always @(posedge clk) // Generate a pulse every 0.5 mS
me_ps2_0_5_ms <= #1 (me_ps2 == `USBF_T2_C_0_5_MS) & !me_ps2_0_5_ms;
// final misc Counter
always @(posedge clk)
if(me_cnt_clr) me_cnt <= #1 0;
else
if(!me_cnt_100_ms & me_ps2_0_5_ms) me_cnt <= #1 me_cnt + 1;
always @(posedge clk) // Indicate when 100uS have passed
T2_gt_100_uS <= #1 !me_cnt_clr & (me_ps2 > `USBF_T2_C_100_US); // Actual Time: 102.5 uS
always @(posedge clk) // Indicate when wakeup period has passed
T2_wakeup <= #1 !me_cnt_clr & (me_cnt > `USBF_T2_C_WAKEUP);
always @(posedge clk) // Indicate when 1 mS has passed
T2_gt_1_0_mS <= #1 !me_cnt_clr & (me_cnt > `USBF_T2_C_1_0_MS); // Actual Time: 1.5 mS
always @(posedge clk) // Indicate when 1.2 mS has passed
T2_gt_1_2_mS <= #1 !me_cnt_clr & (me_cnt > `USBF_T2_C_1_2_MS); // Actual Time: 1.5 mS
always @(posedge clk) // Generate a pulse after 100 mS
me_cnt_100_ms <= #1 !me_cnt_clr & (me_cnt == `USBF_T2_C_100_MS); // Actual Time: 100 mS
// ---------------------------------------------------------
// Chirp Counter
always @(posedge clk)
if(chirp_cnt_clr) chirp_cnt <= #1 0;
else
if(chirp_cnt_inc) chirp_cnt <= #1 chirp_cnt + 1;
always @(posedge clk)
chirp_cnt_is_6 <= #1 (chirp_cnt == 6);
///////////////////////////////////////////////////////////////////
//
// Main State Machine
//
always @(posedge clk)
if(!rst | !usb_vbus) state <= #1 POR;
else state <= #1 next_state;
always @(state or mode_hs or idle_long or resume_req_sr or me_cnt_100_ms or
j_long or k_long or se0_long or ls_se0 or
T1_gt_2_5_uS or T1_gt_100_uS or T1_st_3_0_mS or T1_gt_3_0_mS or T1_gt_5_0_mS or
T2_gt_100_uS or T2_wakeup or T2_gt_1_0_mS or T2_gt_1_2_mS or
chirp_cnt_is_6)
begin
next_state = state; // Default don't change state
mode_set_hs = 0;
mode_set_fs = 0;
suspend_set = 0;
suspend_clr = 0;
attached_set = 0;
attached_clr = 0;
usb_reset_d = 0;
fs_term_on = 0;
fs_term_off = 0;
xcv_set_hs = 0;
xcv_set_fs = 0;
bit_stuff_on = 0;
bit_stuff_off = 0;
idle_cnt_clr = 0;
me_cnt_clr = 0;
drive_k_d = 0;
chirp_cnt_clr = 0;
chirp_cnt_inc = 0;
case(state) // synopsys full_case parallel_case
POR: // Power On/Reset
begin
me_cnt_clr = 1;
xcv_set_fs = 1;
fs_term_on = 1;
mode_set_fs = 1;
attached_clr = 1;
bit_stuff_on = 1;
suspend_clr = 1;
next_state = ATTACH;
end
NORMAL: // Normal Operation
begin
if(!mode_hs & T1_gt_2_5_uS & T1_st_3_0_mS & !idle_long)
begin
me_cnt_clr = 1;
next_state = RESET;
end
else
if(!mode_hs & T1_gt_3_0_mS)
begin
idle_cnt_clr = 1;
suspend_set = 1;
next_state = SUSPEND;
end
else
if(mode_hs & T1_gt_3_0_mS)
begin // Switch to FS mode, and decide
// if it's a RESET or SUSPEND
me_cnt_clr = 1;
xcv_set_fs = 1;
fs_term_on = 1;
next_state = RES_SUSP;
end
end
RES_SUSP: // Decide if it's a Reset or Suspend Signaling
begin // We are now in FS mode, wait 100uS first
if(T2_gt_100_uS & se0_long)
begin
me_cnt_clr = 1;
next_state = RESET;
end
else
if(T2_gt_100_uS & j_long)
begin
idle_cnt_clr = 1;
suspend_set = 1;
next_state = SUSPEND;
end
end
SUSPEND: // In Suspend
begin
if(T1_gt_2_5_uS & se0_long)
begin
suspend_clr = 1;
me_cnt_clr = 1;
next_state = RESET;
end
else
if(k_long) // Start Resuming
begin
next_state = RESUME;
end
else
if(T1_gt_5_0_mS & resume_req_sr)
next_state = RESUME_REQ;
end
RESUME:
begin
suspend_clr = 1;
if(ls_se0)
begin
if(mode_hs)
begin // Switch Back to HS mode
xcv_set_hs = 1;
fs_term_off = 1;
end
me_cnt_clr = 1;
next_state = RESUME_WAIT;
end
end
RESUME_WAIT:
begin
if(T2_gt_100_uS) next_state = NORMAL;
end
RESUME_REQ: // Function Resume Request
begin
suspend_clr = 1;
// Wait for internal wake up
if(T2_wakeup)
begin
me_cnt_clr = 1;
next_state = RESUME_SIG;
end
end
RESUME_SIG: // Signal resume
begin
// Drive Resume ('K') for 1-15 mS
drive_k_d = 1;
// Stop driving after 1.5 mS
if(T2_gt_1_0_mS) next_state = RESUME;
end
ATTACH: // Attach To USB Detected
begin
idle_cnt_clr = 1;
if(me_cnt_100_ms & j_long)
begin
attached_set = 1;
next_state = NORMAL;
end
if(me_cnt_100_ms & se0_long)
begin
attached_set = 1;
me_cnt_clr = 1;
next_state = RESET;
end
end
RESET: // In Reset
begin
usb_reset_d = 1; // Assert Internal USB Reset
xcv_set_hs = 1; // Switch xcvr to HS mode
fs_term_on = 1; // Turn FS termination On
mode_set_fs = 1; // Change mode to FS
// Get out of reset after 1.5 mS
if(T2_gt_1_0_mS)
begin
me_cnt_clr = 1;
next_state = SPEED_NEG;
end
end
SPEED_NEG: // Speed Negotiation
begin
drive_k_d = 1;
chirp_cnt_clr = 1;
// Start looking for 'K' after 1.5 mS
if(T2_gt_1_2_mS) next_state = SPEED_NEG_K;
end
SPEED_NEG_K:
begin
if(chirp_cnt_is_6) next_state = SPEED_NEG_HS;
else
begin
if(k_long)
begin
chirp_cnt_inc = 1;
next_state = SPEED_NEG_J;
end
if(se0_long)
next_state = SPEED_NEG_FS;
end
end
SPEED_NEG_J:
begin
if(chirp_cnt_is_6) next_state = SPEED_NEG_HS;
else
begin
if(j_long)
begin
chirp_cnt_inc = 1;
next_state = SPEED_NEG_K;
end
if(se0_long)
next_state = SPEED_NEG_FS;
end
end
SPEED_NEG_HS:
begin
xcv_set_hs = 1; // Switch xcvr to HS mode
fs_term_off = 1; // Turn FS termination Off
mode_set_hs = 1; // Change mode to FS
if(se0_long) next_state = NORMAL;
end
SPEED_NEG_FS:
begin
xcv_set_fs = 1; // Switch xcvr to FS mode
fs_term_on = 1; // Turn FS termination On
mode_set_fs = 1; // Change mode to FS
next_state = NORMAL;
end
endcase
end
endmodule