⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb1_pe.v

📁 usb1.1 ip核
💻 V
📖 第 1 页 / 共 3 页
字号:
reg	pid_OUT_r, pid_IN_r, pid_PING_r, pid_SETUP_r;//把这四个引脚的情况存入相应的寄存器always @(posedge clk)	pid_OUT_r <= #1 pid_OUT;always @(posedge clk)	pid_IN_r <= #1 pid_IN;always @(posedge clk)	pid_PING_r <= #1 pid_PING;always @(posedge clk)	pid_SETUP_r <= #1 pid_SETUP;always @(posedge clk)//如果匹配了,且不是sof包,out端点只支持out或ping事务,依此类推	int_upid_set <= #1 match_r & !pid_SOF & (				( OUT_ep & !(pid_OUT_r | pid_PING_r))		|				(  IN_ep &  !pid_IN_r)				|				(CTRL_ep & !(pid_IN_r | pid_OUT_r | pid_PING_r | pid_SETUP_r))					);assign int_to_set  = ((state == IN2) & rx_ack_to) | ((state == OUT) & tx_data_to);//前面说的两种time out中断                                        assign int_crc16_set = rx_data_done & crc16_err;//数据接收完了发现有crc16校验错always @(posedge clk)	int_seqerr_set <= #1 int_seqerr_set_d;//一级缓冲,序列错reg	send_stall_r;always @(posedge clk or negedge rst)//对send_stall_r赋值	if(!rst)	send_stall_r <= #1 1'b0;	else	if(send_stall)	send_stall_r <= #1 1'b1;	else		if(send_token)	send_stall_r <= #1 1'b0;//这是为什么?发送握手包时不可能发送stall                                             //这个解释不怎么样!!!/////////////////////////////////////////////////////////////////////// Main Protocol State Machine//always @(posedge clk or negedge rst)	if(!rst)	state <= #1 IDLE;//复位立即进入空闲状态	else	if(match)	state <= #1 IDLE;//如果匹配立即进入空闲状态,这是为什么?奇怪	else		state <= #1 next_state;always @(state or 	pid_seq_err or idma_done or ep_full or ep_empty or	token_valid or pid_ACK or rx_data_done or	tx_data_to or crc16_err or 	rx_ack_to or pid_PING or txfr_iso or txfr_int or	CTRL_ep or pid_IN or pid_OUT or IN_ep or OUT_ep or pid_SETUP or pid_SOF	or match_r or abort or send_stall_r	)   begin	next_state = state;//默认状态保持状态不变	token_pid_sel_d = ACK;//默认发送ack握手	send_token_d = 1'b0;//默认不发送握手包	rx_dma_en = 1'b0;	tx_dma_en = 1'b0;	uc_stat_set_d = 1'b0;//默认不改变data0,data1,uc_stat_set_d给了uc_dpd_set	rx_ack_to_clr_d = 1'b1;//默认状是想清零计数器的,即不计数	int_seqerr_set_d = 1'b0;	case(state)	// synopsys full_case parallel_case	   IDLE:		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state IDLE (%t)", $time);`endif`ifdef USBF_DEBUG		if(rst & match_r & !pid_SOF)		begin		if(match_r === 1'bx)	$display("ERROR: IDLE: match_r is unknown. (%t)", $time);		if(pid_SOF === 1'bx)	$display("ERROR: IDLE: pid_SOF is unknown. (%t)", $time);		if(CTRL_ep === 1'bx)	$display("ERROR: IDLE: CTRL_ep is unknown. (%t)", $time);		if(pid_IN === 1'bx)	$display("ERROR: IDLE: pid_IN is unknown. (%t)", $time);		if(pid_OUT === 1'bx)	$display("ERROR: IDLE: pid_OUT is unknown. (%t)", $time);		if(pid_SETUP === 1'bx)	$display("ERROR: IDLE: pid_SETUP is unknown. (%t)", $time);		if(pid_PING === 1'bx)	$display("ERROR: IDLE: pid_PING is unknown. (%t)", $time);		if(IN_ep === 1'bx)	$display("ERROR: IDLE: IN_ep is unknown. (%t)", $time);		if(OUT_ep === 1'bx)	$display("ERROR: IDLE: OUT_ep is unknown. (%t)", $time);		end`endif// synopsys translate_on			if(match_r & !pid_SOF)//不是帧开始包			   begin/*为什么要注释掉?????这是需要的,事实上ep_stall根本不存在!!所以必须注释掉,但这样就缺少考虑端点stall的状态				if(ep_stall)		// Halt Forced send STALL				   begin					token_pid_sel_d = STALL;					send_token_d = 1'b1;					next_state = TOKEN;				   end				else*/				if(IN_ep | (CTRL_ep & pid_IN))//输入事务				   begin					if(txfr_int & ep_empty)//中断传输且ep寄存器为空					   begin						token_pid_sel_d = NACK;//组装"还没准备好"的包:nack						send_token_d = 1'b1;						next_state = TOKEN;					   end					else//ep寄存器内有货					   begin						tx_dma_en = 1'b1;//通知存储器准备输出,						next_state = IN;					   end				   end				else				if(OUT_ep | (CTRL_ep & (pid_OUT | pid_SETUP)))//输出事务				   begin					rx_dma_en = 1'b1;//通知存储器准备接收输入,怎么不考虑ep_full之类的,象664,在out2a中考虑了					next_state = OUT;				   end			   end		   end	   TOKEN://直接返回idle了		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state TOKEN (%t)", $time);`endif// synopsys translate_on			next_state = IDLE;//直接让它返回空闲状态了		   end	   IN://send_data的信号是idma模块给pa的,不必期望在in中看到什么		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state IN (%t)", $time);`endif`ifdef USBF_DEBUG		if(idma_done === 1'bx)	$display("ERROR: IN: idma_done is unknown. (%t)", $time);		if(txfr_iso === 1'bx)	$display("ERROR: IN: txfr_iso is unknown. (%t)", $time);`endif// synopsys translate_on			rx_ack_to_clr_d = 1'b0;//rx_ack_to_clr <= #1 tx_valid | rx_ack_to_clr_d,并不能说此时就开始计数。			if(idma_done)//传输完毕,引发往主机输出是在idle中就完成了的,就是tx_dma_en.			   begin				if(txfr_iso)	next_state = UPDATE;//如果是同步传输,则进入update,它不要来自主机的ack,也就谈不上rx_ack_to了				else		next_state = IN2;//否则进入in2,去等待来自主机的ack了			   end		   end	   IN2://主要是为了等待主机在接收完数据后送来的ack信号		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state IN2 (%t)", $time);`endif`ifdef USBF_DEBUG		if(rx_ack_to === 1'bx)	$display("ERROR: IN2: rx_ack_to is unknown. (%t)", $time);		if(token_valid === 1'bx)$display("ERROR: IN2: token_valid is unknown. (%t)", $time);		if(pid_ACK === 1'bx)	$display("ERROR: IN2: pid_ACK is unknown. (%t)", $time);`endif// synopsys translate_on			rx_ack_to_clr_d = 1'b0;//不让计数器清零,即准备计数,这个计数时机不错,正确!!			// Wait for ACK from HOST or Timeout			if(rx_ack_to)	next_state = IDLE;//如果时间等满还没有ack,则进入空闲状态			else			if(token_valid & pid_ACK)//如果收到有效的ack握手信号,则进入update状态			   begin				next_state = UPDATE;//即准备变化data0,data1			   end		   end	   OUT://其实数据的接收已在idle中启动,即rx_dma_en,这里主要在处理启动后各种可能的情况		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state OUT (%t)", $time);`endif`ifdef USBF_DEBUG		if(tx_data_to === 1'bx)	$display("ERROR: OUT: tx_data_to is unknown. (%t)", $time);		if(crc16_err === 1'bx)	$display("ERROR: OUT: crc16_err is unknown. (%t)", $time);		if(abort === 1'bx)	$display("ERROR: OUT: abort is unknown. (%t)", $time);		if(rx_data_done === 1'bx)$display("ERROR: OUT: rx_data_done is unknown. (%t)", $time);		if(txfr_iso === 1'bx)	$display("ERROR: OUT: txfr_iso is unknown. (%t)", $time);		if(pid_seq_err === 1'bx)$display("ERROR: OUT: rx_data_done is unknown. (%t)", $time);`endif// synopsys translate_on			if(tx_data_to | crc16_err | abort )//如果等数据时间已满,或是crc16错或是abort,				next_state = IDLE;             //则进入idle			else			if(rx_data_done)//如果数据已经接收完,则发送ack给主机			   begin		// Send Ack				if(txfr_iso)//如果在进行同步传输,则进入updataw状态,因为同步传输不需握手				   begin					if(pid_seq_err)		int_seqerr_set_d = 1'b1;					next_state = UPDATEW;				   end				else		next_state = OUT2A;//如果不是同步传输,则进入out2a状态			   end		   end	   OUT2B://等设备完成工作。nack,很奇怪,找不到进out2b的入口,有可能根本不需要out2b这个状态		   begin	// This is a delay State to NACK to small or to				// large packets. this state could be skipped// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state OUT2B (%t)", $time);`endif`ifdef USBF_DEBUG		if(abort === 1'bx)	$display("ERROR: OUT2A: abort is unknown. (%t)", $time);`endif// synopsys translate_on			if(abort)	next_state = IDLE;			else		next_state = OUT2B;//在match为低的情况下,会一直停留在out2b态,我已不记得这个条件是怎么得来的了		   end                             //好象除非abort为1,否则根本出不去这个状态	   OUT2A:		   begin	// Send ACK/NACK/NYET// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state OUT2A (%t)", $time);`endif`ifdef USBF_DEBUG		if(abort === 1'bx)	$display("ERROR: OUT2A: abort is unknown. (%t)", $time);		if(pid_seq_err === 1'bx)$display("ERROR: OUT2A: rx_data_done is unknown. (%t)", $time);`endif// synopsys translate_on			if(abort)	next_state = IDLE;			else			if(send_stall_r)//发送stall握手信号。注意,send_stall来自pe模块外			   begin				token_pid_sel_d = STALL;				send_token_d = 1'b1;				next_state = IDLE;			   end			else			if(ep_full)//如果端点寄存器满,则发送nack信号,因为没地方放数据			   begin				token_pid_sel_d = NACK;				send_token_d = 1'b1;				next_state = IDLE;			   end			else//就是发送ack的情况了			   begin				token_pid_sel_d = ACK;				send_token_d = 1'b1;				if(pid_seq_err)	next_state = IDLE;//标识符序列错,则不变化本地的当前标识符而直接到idle				else		next_state = UPDATE;			   end		   end	   UPDATEW://进入update的预科班		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state UPDATEW (%t)", $time);`endif// synopsys translate_on			next_state = UPDATE;//感觉仅是延迟了一个时钟		   end	   UPDATE:		   begin// synopsys translate_off`ifdef USBF_VERBOSE_DEBUG		$display("PE: Entered state UPDATE (%t)", $time);`endif// synopsys translate_on			uc_stat_set_d = 1'b1;//指示要不要变化,即data0,data1的切换,打开了uc_dpd_set			next_state = IDLE;		   end	endcase   endendmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -