www.pudn.com > USB2.0_rtl_ipcore_verilog.rar > usbf_rx_phy.v


//RX & DPLL  
 
module usbf_rx_phy(	clk, rst, fs_ce, 
	 
			// Transciever Interface 
			rxd, rxdp, rxdn, 
 
			// UTMI Interface 
			RxValid_o, RxActive_o, RxError_o, DataIn_o, 
			RxEn_i, LineState); 
 
input		clk; 
input		rst; 
output		fs_ce; 
input		rxd, rxdp, rxdn; 
output	[7:0]	DataIn_o; 
output		RxValid_o; 
output		RxActive_o; 
output		RxError_o; 
input		RxEn_i; 
output	[1:0]	LineState; 
 
/////////////////////////////////////////////////////////////////// 
// 
// Local Wires and Registers 
// 
 
reg		rxd_s0, rxd_s1,  rxd_s; 
reg		rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r; 
reg		rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r; 
reg		synced_d; 
wire		k, j, se0; 
reg		rxd_r; 
reg		rx_en; 
reg		rx_active; 
reg	[2:0]	bit_cnt; 
reg		rx_valid1, rx_valid; 
reg		shift_en; 
reg		sd_r; 
reg		sd_nrzi; 
reg	[7:0]	hold_reg; 
wire		drop_bit;	// Indicates a stuffed bit 
reg	[2:0]	one_cnt; 
 
reg	[1:0]	dpll_state, dpll_next_state; 
reg		fs_ce_d; 
reg		fs_ce; 
wire		change; 
wire		lock_en; 
reg	[2:0]	fs_state, fs_next_state; 
reg		rx_valid_r; 
reg		sync_err_d, sync_err; 
reg		bit_stuff_err; 
reg		se0_r, byte_err; 
 
/////////////////////////////////////////////////////////////////// 
// 
// Misc Logic 
// 
 
assign RxActive_o = rx_active; 
assign RxValid_o = rx_valid; 
assign RxError_o = sync_err | bit_stuff_err | byte_err; 
assign DataIn_o = hold_reg; 
assign LineState = {rxdp_s1, rxdn_s1}; 
 
always @(posedge clk)	rx_en <= RxEn_i; 
always @(posedge clk)	sync_err <= !rx_active & sync_err_d; 
 
/////////////////////////////////////////////////////////////////// 
// 
// Synchronize Inputs 
// 
 
// First synchronize to the local system clock to 
// avoid metastability outside the sync block (*_s0). 
// Then make sure we see the signal for at least two 
// clock cycles stable to avoid glitches and noise 
 
always @(posedge clk)	rxd_s0  <= rxd; 
always @(posedge clk)	rxd_s1  <= rxd_s0; 
always @(posedge clk)							// Avoid detecting Line Glitches and noise 
	if(rxd_s0 && rxd_s1)	rxd_s <= 1'b1; 
	else 
	if(!rxd_s0 && !rxd_s1)	rxd_s <= 1'b0; 
 
always @(posedge clk)	rxdp_s0  <= rxdp; 
always @(posedge clk)	rxdp_s1  <= rxdp_s0; 
always @(posedge clk)	rxdp_s_r <= rxdp_s0 & rxdp_s1; 
always @(posedge clk)	rxdp_s   <= (rxdp_s0 & rxdp_s1) | rxdp_s_r;	// Avoid detecting Line Glitches and noise 
 
always @(posedge clk)	rxdn_s0  <= rxdn; 
always @(posedge clk)	rxdn_s1  <= rxdn_s0; 
always @(posedge clk)	rxdn_s_r <= rxdn_s0 & rxdn_s1; 
always @(posedge clk)	rxdn_s   <= (rxdn_s0 & rxdn_s1) | rxdn_s_r;	// Avoid detecting Line Glitches and noise 
 
assign k = !rxdp_s &  rxdn_s; 
assign j =  rxdp_s & !rxdn_s; 
assign se0 = !rxdp_s & !rxdn_s; 
 
/////////////////////////////////////////////////////////////////// 
// 
// DPLL 
// 
 
// This design uses a clock enable to do 12Mhz timing and not a 
// real 12Mhz clock. Everything always runs at 48Mhz. We want to 
// make sure however, that the clock enable is always exactly in 
// the middle between two virtual 12Mhz rising edges. 
// We monitor rxdp and rxdn for any changes and do the appropiate 
// adjustments. 
// In addition to the locking done in the dpll FSM, we adjust the 
// final latch enable to compensate for various sync registers ... 
 
// Allow lockinf only when we are receiving 
assign	lock_en = rx_en; 
 
always @(posedge clk)	rxd_r <= rxd_s; 
 
// Edge detector 
assign change = rxd_r != rxd_s; 
 
// DPLL FSM 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)	dpll_state <= 2'h1; 
	else		dpll_state <= dpll_next_state; 
 
always @(dpll_state or lock_en or change) 
   begin 
	fs_ce_d = 1'b0; 
	case(dpll_state)	// synopsys full_case parallel_case 
	   2'h0: 
		if(lock_en && change)	dpll_next_state = 2'h0; 
		else			dpll_next_state = 2'h1; 
	   2'h1:begin 
		fs_ce_d = 1'b1; 
		if(lock_en && change)	dpll_next_state = 2'h3; 
		else			dpll_next_state = 2'h2; 
		end 
	   2'h2: 
		if(lock_en && change)	dpll_next_state = 2'h0; 
		else			dpll_next_state = 2'h3; 
	   2'h3: 
		if(lock_en && change)	dpll_next_state = 2'h0; 
		else			dpll_next_state = 2'h0; 
	endcase 
   end 
 
// Compensate for sync registers at the input - allign full speed 
// clock enable to be in the middle between two bit changes ... 
reg	fs_ce_r1, fs_ce_r2; 
 
always @(posedge clk)	fs_ce_r1 <= fs_ce_d; 
always @(posedge clk)	fs_ce_r2 <= fs_ce_r1; 
always @(posedge clk)	fs_ce <= fs_ce_r2; 
 
 
/////////////////////////////////////////////////////////////////// 
// 
// Find Sync Pattern FSM 
// 
 
parameter	FS_IDLE	= 3'h0, 
		K1	= 3'h1, 
		J1	= 3'h2, 
		K2	= 3'h3, 
		J2	= 3'h4, 
		K3	= 3'h5, 
		J3	= 3'h6, 
		K4	= 3'h7; 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)	fs_state <= FS_IDLE; 
	else		fs_state <= fs_next_state; 
 
always @(fs_state or fs_ce or k or j or rx_en) 
   begin 
	synced_d = 1'b0; 
	sync_err_d = 1'b0; 
	fs_next_state = fs_state; 
	if(fs_ce) 
	   case(fs_state)	// synopsys full_case parallel_case 
		FS_IDLE: 
		     begin 
			if(k && rx_en)	fs_next_state = K1; 
		     end 
		K1: 
		     begin 
			if(j && rx_en)	fs_next_state = J1; 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		J1: 
		     begin 
			if(k && rx_en)	fs_next_state = K2; 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		K2: 
		     begin 
			if(j && rx_en)	fs_next_state = J2; 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		J2: 
		     begin 
			if(k && rx_en)	fs_next_state = K3; 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		K3: 
		     begin 
			if(j && rx_en)	fs_next_state = J3; 
			else 
			if(k && rx_en)	fs_next_state = K4;	// Allow missing one J 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		J3: 
		     begin 
			if(k && rx_en)	fs_next_state = K4; 
			else 
			   begin 
					sync_err_d = 1'b1; 
					fs_next_state = FS_IDLE; 
			   end 
		     end 
		K4: 
		     begin 
			if(k)	synced_d = 1'b1; 
			fs_next_state = FS_IDLE; 
		     end 
	   endcase 
   end 
 
/////////////////////////////////////////////////////////////////// 
// 
// Generate RxActive 
// 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)		rx_active <= 1'b0; 
	else 
	if(synced_d && rx_en)	rx_active <= 1'b1; 
	else 
	if(se0 && rx_valid_r)	rx_active <= 1'b0; 
 
always @(posedge clk) 
	if(rx_valid)	rx_valid_r <= 1'b1; 
	else 
	if(fs_ce)	rx_valid_r <= 1'b0; 
 
/////////////////////////////////////////////////////////////////// 
// 
// NRZI Decoder 
// 
 
always @(posedge clk) 
	if(fs_ce)	sd_r <= rxd_s; 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)		sd_nrzi <= 1'b0; 
	else 
	if(!rx_active)		sd_nrzi <= 1'b1; 
	else 
	if(rx_active && fs_ce)	sd_nrzi <= !(rxd_s ^ sd_r); 
 
/////////////////////////////////////////////////////////////////// 
// 
// Bit Stuff Detect 
// 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)	one_cnt <= 3'h0; 
	else 
	if(!shift_en)	one_cnt <= 3'h0; 
	else 
	if(fs_ce) 
	   begin 
		if(!sd_nrzi || drop_bit)	one_cnt <= 3'h0; 
		else				one_cnt <= one_cnt + 3'h1; 
	   end 
 
assign drop_bit = (one_cnt==3'h6); 
 
always @(posedge clk)	// Bit Stuff Error 
	bit_stuff_err <= drop_bit & sd_nrzi & fs_ce & !se0 & rx_active; 
 
/////////////////////////////////////////////////////////////////// 
// 
// Serial => Parallel converter 
// 
 
always @(posedge clk) 
	if(fs_ce)	shift_en <= synced_d | rx_active; 
 
always @(posedge clk) 
	if(fs_ce && shift_en && !drop_bit) 
		hold_reg <= {sd_nrzi, hold_reg[7:1]}; 
 
/////////////////////////////////////////////////////////////////// 
// 
// Generate RxValid 
// 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)		bit_cnt <= 3'b0; 
	else 
	if(!shift_en)		bit_cnt <= 3'h0; 
	else 
	if(fs_ce && !drop_bit)	bit_cnt <= bit_cnt + 3'h1; 
 
`ifdef USB_ASYNC_REST 
always @(posedge clk or negedge rst) 
`else 
always @(posedge clk) 
`endif 
	if(!rst)					rx_valid1 <= 1'b0; 
	else 
	if(fs_ce && !drop_bit && (bit_cnt==3'h7))	rx_valid1 <= 1'b1; 
	else 
	if(rx_valid1 && fs_ce && !drop_bit)		rx_valid1 <= 1'b0; 
 
always @(posedge clk) 
	rx_valid <= !drop_bit & rx_valid1 & fs_ce; 
 
always @(posedge clk)	se0_r <= se0; 
 
always @(posedge clk)	byte_err <= se0 & !se0_r & (|bit_cnt); 
 
endmodule