1
0
mirror of https://github.com/avakar/usbcorev.git synced 2024-10-22 02:17:39 +08:00
usbcorev/usb_ep_banked.v
2014-09-07 17:40:57 +02:00

167 lines
4.0 KiB
Verilog

module usb_ep_banked(
input clk,
input direction_in,
input setup,
input success,
input[6:0] cnt,
output reg toggle,
output bank_usb,
output reg[1:0] handshake,
output bank_in,
output bank_out,
output in_data_valid,
input ctrl_dir_in,
output reg[15:0] ctrl_rd_data,
input[15:0] ctrl_wr_data,
input[1:0] ctrl_wr_en
);
localparam
hs_ack = 2'b00,
hs_none = 2'b01,
hs_nak = 2'b10,
hs_stall = 2'b11;
reg ep_setup;
reg ep_out_full;
reg ep_out_empty;
reg ep_in_empty;
reg ep_out_stall;
reg ep_in_stall;
reg ep_out_toggle;
reg ep_in_toggle;
reg ep_in_bank;
reg[6:0] ep_in_cnt_0;
reg[6:0] ep_in_cnt_1;
reg[6:0] ep_out_cnt;
assign in_data_valid = (cnt != (ep_in_toggle? ep_in_cnt_1: ep_in_cnt_0));
assign bank_usb = direction_in? ep_in_toggle: 1'b0;
assign bank_in = ep_in_bank;
assign bank_out = 1'b0;
always @(*) begin
if (!direction_in && setup)
toggle = 1'b0;
else if (ep_setup)
toggle = 1'b1;
else if (direction_in)
toggle = ep_in_toggle;
else
toggle = ep_out_toggle;
end
always @(*) begin
if (direction_in) begin
if (!ep_in_stall && !ep_setup && !ep_in_empty) begin
handshake = hs_ack;
end else if (!ep_setup && ep_in_stall) begin
handshake = hs_stall;
end else begin
handshake = hs_nak;
end
end else begin
if (setup || (!ep_out_stall && !ep_setup && ep_out_full)) begin
handshake = hs_ack;
end else if (!ep_setup && ep_out_stall) begin
handshake = hs_stall;
end else begin
handshake = hs_nak;
end
end
end
always @(*) begin
if (ctrl_dir_in) begin
ctrl_rd_data[15:8] = ep_in_bank? ep_in_cnt_1: ep_in_cnt_0;
ctrl_rd_data[7:0] = { ep_in_bank, ep_in_toggle, ep_in_stall, 1'b0, ep_in_empty, !ep_in_empty && ep_in_toggle == ep_in_bank };
end else begin
ctrl_rd_data[15:8] = ep_out_cnt;
ctrl_rd_data[7:0] = { ep_out_toggle, ep_out_stall, ep_setup, ep_out_empty, ep_out_full };
end
end
wire flush = ctrl_wr_data[5] || ctrl_wr_data[4] || ctrl_wr_data[3];
always @(posedge clk) begin
if (success) begin
if (direction_in) begin
if (ep_in_toggle != ep_in_bank)
ep_in_empty <= 1'b1;
ep_in_toggle = !ep_in_toggle;
end else begin
if (setup)
ep_setup <= 1'b1;
ep_out_toggle = !ep_out_toggle;
ep_out_empty <= 1'b0;
ep_out_cnt <= cnt;
end
end
if (ctrl_wr_en[1] && ctrl_dir_in) begin
if (ep_in_bank)
ep_in_cnt_1 <= ctrl_wr_data[14:8];
else
ep_in_cnt_0 <= ctrl_wr_data[14:8];
end
if (ctrl_wr_en[0] && ctrl_dir_in) begin
if (ctrl_wr_data[5]) begin
ep_in_toggle = 1'b0;
ep_in_stall <= 1'b0;
ep_in_bank <= 1'b0;
end
if (ctrl_wr_data[4]) begin
ep_in_toggle = 1'b1;
ep_in_stall <= 1'b0;
ep_in_bank <= 1'b1;
end
if (ctrl_wr_data[3]) begin
ep_in_stall <= 1'b1;
ep_in_bank <= ep_in_toggle;
end
if (flush) begin
ep_in_empty <= 1'b1;
end
if (ctrl_wr_data[0]) begin
ep_in_empty <= 1'b0;
ep_in_bank <= !ep_in_bank;
end
end
if (ctrl_wr_en[0] && !ctrl_dir_in) begin
if (ctrl_wr_data[5]) begin
ep_out_toggle = 1'b0;
ep_out_stall <= 1'b0;
end
if (ctrl_wr_data[4]) begin
ep_out_toggle = 1'b1;
ep_out_stall <= 1'b0;
end
if (ctrl_wr_data[3])
ep_out_stall <= 1'b1;
if (flush) begin
ep_out_full <= 1'b0;
ep_out_empty <= 1'b1;
end
if (ctrl_wr_data[2])
ep_setup <= 1'b0;
if (ctrl_wr_data[1]) begin
ep_out_empty <= 1'b1;
ep_out_full <= 1'b0;
end
if (ctrl_wr_data[0])
ep_out_full <= 1'b1;
end
end
endmodule