📄 usb1_pe.v
字号:
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 + -