📄 usb1_pe.v
字号:
if(uc_dpd_set & (ep_sel == 4'h1)) ep1_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep2_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h2)) ep2_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep3_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h3)) ep3_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep4_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h4)) ep4_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep5_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h5)) ep5_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep6_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h6)) ep6_dpid <= next_dpid;always @(posedge clk or negedge rst) if(!rst) ep7_dpid <= 2'b00; else if(uc_dpd_set & (ep_sel == 4'h7)) ep7_dpid <= next_dpid;always @(posedge clk)//uc_dpd是什么东西??,当前传输的data包的pid, case(ep_sel) 4'h0: uc_dpd <= ep0_dpid; 4'h1: uc_dpd <= ep1_dpid; 4'h2: uc_dpd <= ep2_dpid; 4'h3: uc_dpd <= ep3_dpid; 4'h4: uc_dpd <= ep4_dpid; 4'h5: uc_dpd <= ep5_dpid; 4'h6: uc_dpd <= ep6_dpid; 4'h7: uc_dpd <= ep7_dpid; endcase/////////////////////////////////////////////////////////////////////// Data Pid Sequencer//assign tr_fr_d = 2'h0;//岂不是tr_fr_d一直为00??这可是持续赋值啊!!正是!always @(posedge clk) // tr/mf:ep/type:tr/type:last dpd casex({tr_fr_d,ep_type,txfr_type,uc_dpd}) // synopsys full_case parallel_case 8'b0?_01_01_??: next_dpid <= #1 2'b00; // ISO txfr. IN, 1 tr/mf,设备到主机,data0 8'b10_01_01_?0: next_dpid <= #1 2'b01; // ISO txfr. IN, 2 tr/mf不必看 8'b10_01_01_?1: next_dpid <= #1 2'b00; // ISO txfr. IN, 2 tr/mf不必看 8'b11_01_01_00: next_dpid <= #1 2'b01; // ISO txfr. IN, 3 tr/mf不必看 8'b11_01_01_01: next_dpid <= #1 2'b10; // ISO txfr. IN, 3 tr/mf不必看 8'b11_01_01_10: next_dpid <= #1 2'b00; // ISO txfr. IN, 3 tr/mf不必看 8'b0?_10_01_??: next_dpid <= #1 2'b00; // ISO txfr. OUT, 1 tr/mf,主机到设备,data0 8'b10_10_01_??: // ISO txfr. OUT, 2 tr/mf不必看 begin // Resynchronize in case of PID error case({pid_MDATA, pid_DATA1}) // synopsys full_case parallel_case 2'b10: next_dpid <= #1 2'b01; 2'b01: next_dpid <= #1 2'b00; endcase end 8'b11_10_01_00: // ISO txfr. OUT, 3 tr/mf不必看 begin // Resynchronize in case of PID error case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case 2'b10: next_dpid <= #1 2'b01; 2'b01: next_dpid <= #1 2'b00; endcase end 8'b11_10_01_01: // ISO txfr. OUT, 3 tr/mf不必看 begin // Resynchronize in case of PID error case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case 2'b10: next_dpid <= #1 2'b10; 2'b01: next_dpid <= #1 2'b00; endcase end 8'b11_10_01_10: // ISO txfr. OUT, 3 tr/mf不必看 begin // Resynchronize in case of PID error case({pid_MDATA, pid_DATA2}) // synopsys full_case parallel_case 2'b10: next_dpid <= #1 2'b01; 2'b01: next_dpid <= #1 2'b00; endcase end //当前用的是data0,则下次切换成data1 8'b??_01_00_?0, // IN/OUT endpoint only下面是中断传输,满足data0,data1轮换 8'b??_10_00_?0: next_dpid <= #1 2'b01; // INT transfers为什么不明写??_10_00_00呢 //当前用的是data1,则下次切换成data0 8'b??_01_00_?1, // IN/OUT endpoint only 8'b??_10_00_?1: next_dpid <= #1 2'b00; // INT transfers //当前是data0,下次切换为data1 8'b??_01_10_?0, // IN/OUT endpoint only下面是批量传输,满足data0,data1轮换 8'b??_10_10_?0: next_dpid <= #1 2'b01; // BULK transfers //当前是data1,下次切换为data0 8'b??_01_10_?1, // IN/OUT endpoint only 8'b??_10_10_?1: next_dpid <= #1 2'b00; // BULK transfers 8'b??_00_??_??: // CTRL Endpoint怎么回事?明白了,左右循环机制,详见笔记本 casex({setup_token, in_op, out_op, uc_dpd}) // synopsys full_case parallel_case 5'b1_??_??: next_dpid <= #1 2'b11; // SETUP operation 永远记住,next_dpid只是一个中间变量 5'b0_10_0?: next_dpid <= #1 2'b11; // IN operation 5'b0_10_1?: next_dpid <= #1 2'b01; // IN operation 5'b0_01_?0: next_dpid <= #1 2'b11; // OUT operation 5'b0_01_?1: next_dpid <= #1 2'b10; // OUT operation endcase endcase// Current PID decoder// Allow any PID for ISO. transfers when mode full speed or tr_fr is zeroalways @(pid_DATA0 or pid_DATA1 or pid_DATA2 or pid_MDATA) case({pid_DATA0, pid_DATA1, pid_DATA2, pid_MDATA} ) // synopsys full_case parallel_case 4'b1000: allow_pid = 2'b00; 4'b0100: allow_pid = 2'b01; 4'b0010: allow_pid = 2'b10; 4'b0001: allow_pid = 2'b11; endcasealways @(posedge clk) // tf/mf:ep/type:tr/type:last dpd这部分也有严重的理解问题,420 casex({tr_fr_d,ep_type,txfr_type,uc_dpd}) // synopsys full_case parallel_case 8'b0?_01_01_??: this_dpid <= #1 2'b00; // ISO txfr. IN, 1 tr/mf仅data0,如果没有意外,基本符合协议规定 8'b10_01_01_?0: this_dpid <= #1 2'b01; // ISO txfr. IN, 2 tr/mf不必看 8'b10_01_01_?1: this_dpid <= #1 2'b00; // ISO txfr. IN, 2 tr/mf不必看 8'b11_01_01_00: this_dpid <= #1 2'b10; // ISO txfr. IN, 3 tr/mf不必看 8'b11_01_01_01: this_dpid <= #1 2'b01; // ISO txfr. IN, 3 tr/mf不必看 8'b11_01_01_10: this_dpid <= #1 2'b00; // ISO txfr. IN, 3 tr/mf不必看 8'b00_10_01_??: this_dpid <= #1 allow_pid; // ISO txfr. OUT, 0 tr/mf符合输出时的协议规定 8'b01_10_01_??: this_dpid <= #1 2'b00; // ISO txfr. OUT, 1 tr/mf它也用不到的 8'b10_10_01_?0: this_dpid <= #1 2'b11; // ISO txfr. OUT, 2 tr/mf不必看 8'b10_10_01_?1: this_dpid <= #1 2'b01; // ISO txfr. OUT, 2 tr/mf不必看 8'b11_10_01_00: this_dpid <= #1 2'b11; // ISO txfr. OUT, 3 tr/mf不必看 8'b11_10_01_01: this_dpid <= #1 2'b11; // ISO txfr. OUT, 3 tr/mf不必看 8'b11_10_01_10: this_dpid <= #1 2'b10; // ISO txfr. OUT, 3 tr/mf不必看 8'b??_01_00_?0, // IN/OUT endpoint only中断传输的场合 8'b??_10_00_?0: this_dpid <= #1 2'b00; // INT transfers 8'b??_01_00_?1, // IN/OUT endpoint only 8'b??_10_00_?1: this_dpid <= #1 2'b01; // INT transfers 8'b??_01_10_?0, // IN/OUT endpoint only批量传输的场合 8'b??_10_10_?0: this_dpid <= #1 2'b00; // BULK transfers 8'b??_01_10_?1, // IN/OUT endpoint only 8'b??_10_10_?1: this_dpid <= #1 2'b01; // BULK transfers 8'b??_00_??_??: // CTRL Endpoint casex({setup_token,in_op, out_op, uc_dpd}) // synopsys full_case parallel_case 5'b1_??_??: this_dpid <= #1 2'b00; // SETUP operation,data0包,正确 5'b0_10_0?: this_dpid <= #1 2'b00; // IN operation我觉得与协议有出入!事实上没有一点问题,我已明白 5'b0_10_1?: this_dpid <= #1 2'b01; // IN operation很严重的理解问题,已解决 5'b0_01_?0: this_dpid <= #1 2'b00; // OUT operation主机输出 5'b0_01_?1: this_dpid <= #1 2'b01; // OUT operation endcase endcase// Assign PID for outgoing packets,为输出数据包加包标识符assign data_pid_sel = this_dpid;// Verify PID for incoming data packets,要注意:这里的incoming是从设备的角度说的,自然交给pd处理always @(posedge clk) pid_seq_err <= #1 !( (this_dpid==2'b00 & pid_DATA0) | (this_dpid==2'b01 & pid_DATA1) | (this_dpid==2'b10 & pid_DATA2) | (this_dpid==2'b11 & pid_MDATA) );/////////////////////////////////////////////////////////////////////// IDMA Setup & src/dst buffer select//// For Control endpoints things are different:// buffer0 is used for OUT (incoming) data packets// buffer1 is used for IN (outgoing) data packets// Keep track of last token for control endpointsalways @(posedge clk or negedge rst)//对in_token赋值,很清晰,in_token,reg型 if(!rst) in_token <= #1 1'b0; else if(pid_IN) in_token <= #1 1'b1; else if(pid_OUT | pid_SETUP) in_token <= #1 1'b0;always @(posedge clk or negedge rst)//对out_token赋值,也很清晰 if(!rst) out_token <= #1 1'b0; else if(pid_OUT | pid_SETUP) out_token <= #1 1'b1;//特别提醒:包含了setup事务,因为setup也是主机发送数据到设备 else if(pid_IN) out_token <= #1 1'b0;always @(posedge clk or negedge rst)//给setup_token赋值 if(!rst) setup_token <= #1 1'b0; else if(pid_SETUP) setup_token <= #1 1'b1; else if(pid_OUT | pid_IN) setup_token <= #1 1'b0;// Indicates if we are performing an IN operationassign in_op = IN_ep | (CTRL_ep & in_token);//从输入端点输入,或控制端点的输入事务// Indicates if we are performing an OUT operationassign out_op = OUT_ep | (CTRL_ep & out_token);//输出端点输出,或控制端点的输出事务/////////////////////////////////////////////////////////////////////// Determine if packet is to small or to large// This is used to NACK and ignore packet for OUT endpoints///////////////////////////////////////////////////////////////////////// Register File Update Logic//always @(posedge clk) uc_dpd_set <= #1 uc_stat_set_d;//uc_stat_set_d是来自状态机的是否切换data0,data1的标志, //而uc_dpd_set是是否允许改变epN_dpid的标志,很显然,如果epN_dpid得不到修改// Abort signal //那么uc_dpd也不会变化的always @(posedge clk) abort <= #1 match & fsel & (state != IDLE);//还不明白,不空闲??/////////////////////////////////////////////////////////////////////// TIME OUT TIMERS//// After sending Data in response to an IN token from host, the// host must reply with an ack. The host has 622nS in Full Speed// mode and 400nS in High Speed mode to reply.// "rx_ack_to" indicates when this time has expired.// rx_ack_to_clr, clears the timeralways @(posedge clk) rx_ack_to_clr <= #1 tx_valid | rx_ack_to_clr_d;//tx_valid产生于包组装模块 //传输有效即正在传输就不计数always @(posedge clk) if(rx_ack_to_clr) rx_ack_to_cnt <= #1 8'h0;//计数器清零了 else rx_ack_to_cnt <= #1 rx_ack_to_cnt + 8'h1;//否则计数always @(posedge clk)//给rx_ack_to赋值 rx_ack_to <= #1 (rx_ack_to_cnt == rx_ack_to_val);assign rx_ack_to_val = `USBF_RX_ACK_TO_VAL_FS;//从usb1_defines.v中取了预定值// After sending a OUT token the host must send a data packet.// The host has 622nS in Full Speed mode and 400nS in High Speed// mode to send the data packet.// "tx_data_to" indicates when this time has expired.// "tx_data_to_clr" clears the timerassign tx_data_to_clr = rx_active;//注意这个持续赋值,这里的与上面的rx_ack_to一致 //能检测到同步头就不计数,说明收到数据always @(posedge clk) if(tx_data_to_clr) tx_data_to_cnt <= #1 8'h0; else tx_data_to_cnt <= #1 tx_data_to_cnt + 8'h1;always @(posedge clk) tx_data_to <= #1 (tx_data_to_cnt == tx_data_to_val);assign tx_data_to_val = `USBF_TX_DATA_TO_VAL_FS;/////////////////////////////////////////////////////////////////////// Interrupts//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -