📄 usb1_pe.v
字号:
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
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
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 endpoints
always @(posedge clk or negedge rst)
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)
if(!rst) out_token <= #1 1'b0;
else
if(pid_OUT | pid_SETUP) out_token <= #1 1'b1;
else
if(pid_IN) out_token <= #1 1'b0;
always @(posedge clk or negedge rst)
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 operation
assign in_op = IN_ep | (CTRL_ep & in_token);
// Indicates if we are performing an OUT operation
assign 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;
// Abort signal
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 timer
always @(posedge clk)
rx_ack_to_clr <= #1 tx_valid | rx_ack_to_clr_d;
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 <= #1 (rx_ack_to_cnt == rx_ack_to_val);
assign rx_ack_to_val = `USBF_RX_ACK_TO_VAL_FS;
// 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 timer
assign tx_data_to_clr = rx_active;
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
//
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)
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);
assign int_crc16_set = rx_data_done & crc16_err;
always @(posedge clk)
int_seqerr_set <= #1 int_seqerr_set_d;
reg send_stall_r;
always @(posedge clk or negedge rst)
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;
///////////////////////////////////////////////////////////////////
//
// 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;
send_token_d = 1'b0;
rx_dma_en = 1'b0;
tx_dma_en = 1'b0;
uc_stat_set_d = 1'b0;
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
/*
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)
begin
token_pid_sel_d = NACK;
send_token_d = 1'b1;
next_state = TOKEN;
end
else
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;
next_state = OUT;
end
end
end
TOKEN:
begin
// synopsys translate_off
`ifdef USBF_VERBOSE_DEBUG
$display("PE: Entered state TOKEN (%t)", $time);
`endif
// synopsys translate_on
next_state = IDLE;
end
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;
if(idma_done)
begin
if(txfr_iso) next_state = UPDATE;
else next_state = IN2;
end
end
IN2:
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;
else
if(token_valid & pid_ACK)
begin
next_state = UPDATE;
end
end
OUT:
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 )
next_state = IDLE;
else
if(rx_data_done)
begin // Send Ack
if(txfr_iso)
begin
if(pid_seq_err) int_seqerr_set_d = 1'b1;
next_state = UPDATEW;
end
else next_state = OUT2A;
end
end
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;
end
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)
begin
token_pid_sel_d = STALL;
send_token_d = 1'b1;
next_state = IDLE;
end
else
if(ep_full)
begin
token_pid_sel_d = NACK;
send_token_d = 1'b1;
next_state = IDLE;
end
else
begin
token_pid_sel_d = ACK;
send_token_d = 1'b1;
if(pid_seq_err) next_state = IDLE;
else next_state = UPDATE;
end
end
UPDATEW:
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;
next_state = IDLE;
end
endcase
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -