mirror of
https://github.com/avakar/usbcorev.git
synced 2024-10-22 02:17:39 +08:00
Initial commit.
The module works correctly during USB enumeration, no more tests were performed at this point. No documentation or tests.
This commit is contained in:
commit
fb2e32dc58
13
crc16.py
Normal file
13
crc16.py
Normal file
@ -0,0 +1,13 @@
|
||||
import sys
|
||||
|
||||
while True:
|
||||
crc = 0xffff
|
||||
|
||||
binary = raw_input('Enter sequence: ')
|
||||
for ch in binary:
|
||||
top = (crc & 0x8000) != 0
|
||||
crc = (crc << 1) & 0xffff
|
||||
if (ch == '1') != top:
|
||||
crc = crc ^ 0x8005
|
||||
|
||||
print bin(crc)
|
13
crc5.py
Normal file
13
crc5.py
Normal file
@ -0,0 +1,13 @@
|
||||
import sys
|
||||
|
||||
while True:
|
||||
crc = 0x1f
|
||||
|
||||
binary = raw_input('Enter sequence: ')
|
||||
for ch in binary:
|
||||
top = (crc & 0x10) != 0
|
||||
crc = (crc << 1) & 0x1f
|
||||
if (ch == '1') != top:
|
||||
crc = crc ^ 5
|
||||
|
||||
print bin(crc)
|
339
usb.v
Normal file
339
usb.v
Normal file
@ -0,0 +1,339 @@
|
||||
module usb(
|
||||
input rst_n,
|
||||
input clk_48,
|
||||
|
||||
input dp_in,
|
||||
input dn_in,
|
||||
input d0p_in,
|
||||
input d0n_in,
|
||||
|
||||
output dp_out,
|
||||
output dn_out,
|
||||
output d_dir_out,
|
||||
|
||||
input[6:0] usb_address,
|
||||
|
||||
output usb_rst,
|
||||
|
||||
output reg transaction_active,
|
||||
output reg[3:0] endpoint,
|
||||
output reg direction_in,
|
||||
output reg setup,
|
||||
input data_toggle,
|
||||
|
||||
input[1:0] handshake,
|
||||
|
||||
output reg[7:0] data_out,
|
||||
input[7:0] data_in,
|
||||
input data_in_valid,
|
||||
output reg data_strobe,
|
||||
output reg success
|
||||
);
|
||||
|
||||
localparam
|
||||
hs_ack = 2'b00,
|
||||
hs_none = 2'b01,
|
||||
hs_nak = 2'b10,
|
||||
hs_stall = 2'b11;
|
||||
|
||||
wire[3:0] recv_pid;
|
||||
wire[7:0] recv_data;
|
||||
wire recv_packet;
|
||||
wire recv_datastrobe;
|
||||
wire recv_crc5_ok;
|
||||
wire recv_crc16_ok;
|
||||
wire recv_short_idle;
|
||||
|
||||
usb_recv recv(
|
||||
.rst_n(rst_n),
|
||||
.clk_48(clk_48),
|
||||
|
||||
.dp_in(dp_in),
|
||||
.dn_in(dn_in),
|
||||
.d0p_in(d0p_in),
|
||||
.d0n_in(d0n_in),
|
||||
|
||||
.short_idle(recv_short_idle),
|
||||
.usb_rst(usb_rst),
|
||||
|
||||
.xpid(recv_pid),
|
||||
.xdata(recv_data),
|
||||
.xpacket(recv_packet),
|
||||
.xdatastrobe(recv_datastrobe),
|
||||
.xcrc5_ok(recv_crc5_ok),
|
||||
.xcrc16_ok(recv_crc16_ok)
|
||||
);
|
||||
|
||||
reg tx_transmit;
|
||||
reg[7:0] tx_data;
|
||||
wire tx_data_strobe;
|
||||
|
||||
reg tx_enable_crc16;
|
||||
wire tx_send_crc16;
|
||||
usb_tx tx(
|
||||
.rst_n(rst_n),
|
||||
.clk_48(clk_48),
|
||||
|
||||
.usb_dp(dp_out),
|
||||
.usb_dn(dn_out),
|
||||
.usb_tx_en(d_dir_out),
|
||||
|
||||
.transmit(tx_transmit),
|
||||
.data(tx_data),
|
||||
.data_strobe(tx_data_strobe),
|
||||
|
||||
.update_crc16(tx_enable_crc16),
|
||||
.send_crc16(tx_send_crc16)
|
||||
);
|
||||
|
||||
reg[7:0] recv_queue_0;
|
||||
reg[7:0] recv_queue_1;
|
||||
reg recv_queue_0_valid;
|
||||
reg recv_queue_1_valid;
|
||||
|
||||
always @(posedge clk_48) begin
|
||||
if (!recv_packet) begin
|
||||
recv_queue_1_valid <= 1'b0;
|
||||
recv_queue_0_valid <= 1'b0;
|
||||
end else if (recv_datastrobe) begin
|
||||
data_out <= recv_queue_1;
|
||||
recv_queue_1 <= recv_queue_0;
|
||||
recv_queue_0 <= recv_data;
|
||||
recv_queue_1_valid <= recv_queue_0_valid;
|
||||
recv_queue_0_valid <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
localparam
|
||||
st_idle = 3'b000,
|
||||
st_data = 3'b001,
|
||||
st_err = 3'b010,
|
||||
st_send_handshake = 3'b011,
|
||||
st_in = 3'b100,
|
||||
st_prep_recv_ack = 3'b101,
|
||||
st_recv_ack = 3'b110,
|
||||
st_send_ack = 3'b111;
|
||||
|
||||
reg[2:0] state;
|
||||
|
||||
assign tx_send_crc16 = state == st_prep_recv_ack;
|
||||
|
||||
localparam
|
||||
pt_special = 2'b00,
|
||||
pt_token = 2'b01,
|
||||
pt_handshake = 2'b10,
|
||||
pt_data = 2'b11;
|
||||
|
||||
localparam
|
||||
tok_out = 2'b00,
|
||||
tok_sof = 2'b01,
|
||||
tok_in = 2'b10,
|
||||
tok_setup = 2'b11;
|
||||
|
||||
// Note that the token is perishable. The standard prescribes at most
|
||||
// 7.5 bits of inter-packet idle time. We allow at most 31 bits between
|
||||
// token activation and receiving the corresponding DATA packet.
|
||||
reg[6:0] token_timeout;
|
||||
wire token_active = token_timeout != 1'b0;
|
||||
|
||||
always @(posedge clk_48 or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
success <= 1'b0;
|
||||
state <= st_idle;
|
||||
data_strobe <= 1'b0;
|
||||
endpoint <= 1'sbx;
|
||||
direction_in <= 1'bx;
|
||||
setup <= 1'bx;
|
||||
transaction_active <= 1'b0;
|
||||
token_timeout <= 1'b0;
|
||||
tx_transmit <= 1'b0;
|
||||
|
||||
tx_enable_crc16 <= 1'b0;
|
||||
end else begin
|
||||
if (token_timeout != 1'b0)
|
||||
token_timeout <= token_timeout - 1'b1;
|
||||
|
||||
if (!transaction_active) begin
|
||||
endpoint <= 1'sbx;
|
||||
direction_in <= 1'bx;
|
||||
setup <= 1'bx;
|
||||
end
|
||||
|
||||
success <= 1'b0;
|
||||
data_strobe <= 1'b0;
|
||||
tx_transmit <= 1'b0;
|
||||
case (state)
|
||||
st_idle: begin
|
||||
if (!token_active)
|
||||
transaction_active <= 1'b0;
|
||||
|
||||
if (recv_packet) begin
|
||||
if (recv_pid[1:0] == pt_token) begin
|
||||
state <= st_data;
|
||||
end else begin
|
||||
if (recv_pid[1:0] == pt_data && !recv_pid[2] && token_active)
|
||||
state <= recv_pid[3] == data_toggle? st_data: st_send_ack;
|
||||
else
|
||||
state <= st_err;
|
||||
end
|
||||
end
|
||||
end
|
||||
st_data: begin
|
||||
if (!recv_packet) begin
|
||||
state <= st_idle;
|
||||
case (recv_pid[1:0])
|
||||
pt_token: begin
|
||||
if (recv_queue_1_valid && recv_crc5_ok && recv_queue_1[6:0] == usb_address && recv_pid[3:2] != tok_sof) begin
|
||||
token_timeout <= 7'h7f;
|
||||
transaction_active <= 1'b1;
|
||||
endpoint <= { recv_queue_0[2:0], recv_queue_1[7] };
|
||||
case (recv_pid[3:2])
|
||||
tok_in: begin
|
||||
direction_in <= 1'b1;
|
||||
setup <= 1'bx;
|
||||
state <= st_in;
|
||||
end
|
||||
tok_out: begin
|
||||
direction_in <= 1'b0;
|
||||
setup <= 1'b0;
|
||||
end
|
||||
tok_setup: begin
|
||||
direction_in <= 1'b0;
|
||||
setup <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
transaction_active <= 1'b0;
|
||||
endpoint <= 1'sbx;
|
||||
direction_in <= 1'bx;
|
||||
setup <= 1'bx;
|
||||
end
|
||||
end
|
||||
pt_data: begin
|
||||
if (recv_queue_1_valid && recv_crc16_ok) begin
|
||||
transaction_active <= 1'b0;
|
||||
if (handshake == hs_ack || handshake == hs_none)
|
||||
success <= 1'b1;
|
||||
state <= st_send_handshake;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
endpoint <= 1'sbx;
|
||||
direction_in <= 1'bx;
|
||||
setup <= 1'bx;
|
||||
end
|
||||
endcase
|
||||
end else if (recv_datastrobe) begin
|
||||
case (recv_pid[1:0])
|
||||
pt_token: begin
|
||||
if (recv_queue_1_valid)
|
||||
state <= st_err;
|
||||
end
|
||||
pt_data: begin
|
||||
if (recv_queue_1_valid)
|
||||
data_strobe <= 1'b1;
|
||||
end
|
||||
default: begin
|
||||
state <= st_err;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
st_in: begin
|
||||
tx_transmit <= tx_transmit;
|
||||
|
||||
if (!tx_transmit && recv_short_idle) begin
|
||||
if (handshake != hs_ack && handshake != hs_none) begin
|
||||
state <= st_send_handshake;
|
||||
end else begin
|
||||
tx_data <= { !data_toggle, 3'b100, data_toggle, 3'b011 };
|
||||
tx_transmit <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (tx_transmit && tx_data_strobe) begin
|
||||
if (!data_in_valid) begin
|
||||
if (handshake == hs_ack) begin
|
||||
state <= st_prep_recv_ack;
|
||||
end else begin
|
||||
state <= st_err;
|
||||
success <= 1'b1;
|
||||
transaction_active <= 1'b0;
|
||||
end
|
||||
tx_enable_crc16 <= 1'b0;
|
||||
tx_transmit <= 1'b0;
|
||||
end else begin
|
||||
tx_data <= data_in;
|
||||
data_strobe <= 1'b1;
|
||||
tx_enable_crc16 <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
st_prep_recv_ack: begin
|
||||
token_timeout <= 7'h7f;
|
||||
if (!d_dir_out && !recv_packet)
|
||||
state <= st_recv_ack;
|
||||
end
|
||||
st_recv_ack: begin
|
||||
if (recv_packet) begin
|
||||
state <= st_err;
|
||||
if (recv_pid == 4'b0010) begin
|
||||
success <= 1'b1;
|
||||
transaction_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
if (!token_active && !recv_packet)
|
||||
state <= st_idle;
|
||||
end
|
||||
st_send_ack: begin
|
||||
tx_transmit <= tx_transmit;
|
||||
|
||||
if (!tx_transmit && recv_short_idle) begin
|
||||
tx_data <= 8'b11010010; // ACK
|
||||
tx_transmit <= 1'b1;
|
||||
|
||||
end
|
||||
|
||||
if (tx_transmit && tx_data_strobe) begin
|
||||
tx_transmit <= 1'b0;
|
||||
state <= st_err;
|
||||
end
|
||||
end
|
||||
st_send_handshake: begin
|
||||
tx_transmit <= tx_transmit;
|
||||
|
||||
if (!tx_transmit && recv_short_idle) begin
|
||||
case (handshake)
|
||||
hs_none: begin
|
||||
state <= st_idle;
|
||||
end
|
||||
hs_ack: begin
|
||||
tx_data <= 8'b11010010;
|
||||
tx_transmit <= 1'b1;
|
||||
end
|
||||
hs_nak: begin
|
||||
tx_data <= 8'b01011010;
|
||||
tx_transmit <= 1'b1;
|
||||
end
|
||||
hs_stall: begin
|
||||
tx_data <= 8'b00011110;
|
||||
tx_transmit <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (tx_transmit && tx_data_strobe) begin
|
||||
tx_transmit <= 1'b0;
|
||||
state <= st_err;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
transaction_active <= 1'b0;
|
||||
if (!d_dir_out && !recv_packet)
|
||||
state <= st_idle;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
237
usb_recv.v
Normal file
237
usb_recv.v
Normal file
@ -0,0 +1,237 @@
|
||||
module usb_recv_sm(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input strobe,
|
||||
input din,
|
||||
input sync,
|
||||
input se0,
|
||||
|
||||
output reg[3:0] xpid,
|
||||
output reg[7:0] xdata,
|
||||
output xpacket,
|
||||
output reg xdatastrobe,
|
||||
output reg xcrc5_ok,
|
||||
output reg xcrc16_ok
|
||||
);
|
||||
|
||||
reg clear_shift;
|
||||
reg[7:0] shift_reg;
|
||||
reg[8:0] next_shift;
|
||||
|
||||
always @(*) begin
|
||||
if (clear_shift)
|
||||
next_shift = { 7'b1, din };
|
||||
else
|
||||
next_shift = { shift_reg[7:0], din };
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (strobe) begin
|
||||
shift_reg <= next_shift[7:0];
|
||||
end
|
||||
end
|
||||
|
||||
localparam
|
||||
st_idle = 2'b00,
|
||||
st_done = 2'b10,
|
||||
st_pid = 2'b01,
|
||||
st_data = 2'b11;
|
||||
|
||||
reg[1:0] state;
|
||||
|
||||
wire crc5_valid;
|
||||
usb_crc5 crc5(
|
||||
.rst_n(rst_n && xpacket),
|
||||
.clk(clk),
|
||||
.clken(strobe),
|
||||
.d(din),
|
||||
.valid(crc5_valid)
|
||||
);
|
||||
|
||||
wire crc16_valid;
|
||||
usb_crc16 crc16(
|
||||
.rst_n(rst_n && xpacket),
|
||||
.clk(clk),
|
||||
.clken(strobe),
|
||||
.d(din),
|
||||
.dump(1'b0),
|
||||
.out(),
|
||||
.valid(crc16_valid)
|
||||
);
|
||||
|
||||
assign xpacket = (state == st_data);
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= st_idle;
|
||||
clear_shift <= 1'bx;
|
||||
|
||||
xpid <= 1'sbx;
|
||||
xdata <= 1'sbx;
|
||||
xdatastrobe <= 1'b0;
|
||||
xcrc5_ok <= 1'b0;
|
||||
xcrc16_ok <= 1'b0;
|
||||
end else if (strobe) begin
|
||||
clear_shift <= 1'bx;
|
||||
xdatastrobe <= 1'b0;
|
||||
|
||||
case (state)
|
||||
st_idle: begin
|
||||
if (sync && !se0) begin
|
||||
state <= st_pid;
|
||||
clear_shift <= 1'b1;
|
||||
end
|
||||
end
|
||||
st_pid: begin
|
||||
if (se0) begin
|
||||
state <= st_idle;
|
||||
end else begin
|
||||
if (next_shift[8]) begin
|
||||
if (next_shift[7:4] == ~next_shift[3:0]) begin
|
||||
clear_shift <= 1'b1;
|
||||
xpid <= { next_shift[4], next_shift[5], next_shift[6], next_shift[7] };
|
||||
state <= st_data;
|
||||
xcrc5_ok <= 1'b0;
|
||||
xcrc16_ok <= 1'b0;
|
||||
end else begin
|
||||
state <= st_done;
|
||||
end
|
||||
end else begin
|
||||
clear_shift <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
st_data: begin
|
||||
if (se0) begin
|
||||
state <= st_idle;
|
||||
end else begin
|
||||
clear_shift <= 1'b0;
|
||||
if (next_shift[8]) begin
|
||||
clear_shift <= 1'b1;
|
||||
xdata <= {
|
||||
next_shift[0], next_shift[1], next_shift[2], next_shift[3],
|
||||
next_shift[4], next_shift[5], next_shift[6], next_shift[7] };
|
||||
xdatastrobe <= 1'b1;
|
||||
xcrc5_ok <= crc5_valid;
|
||||
xcrc16_ok <= crc16_valid;
|
||||
end
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
if (se0)
|
||||
state <= st_idle;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module usb_recv(
|
||||
input rst_n,
|
||||
input clk_48,
|
||||
|
||||
input dp_in,
|
||||
input dn_in,
|
||||
input d0p_in,
|
||||
input d0n_in,
|
||||
|
||||
output short_idle,
|
||||
output usb_rst,
|
||||
|
||||
output[3:0] xpid,
|
||||
output[7:0] xdata,
|
||||
output xpacket,
|
||||
output xdatastrobe,
|
||||
output xcrc5_ok,
|
||||
output xcrc16_ok
|
||||
);
|
||||
|
||||
wire d_presync;
|
||||
IBUFDS diff_buffer(.I(dp_in), .IB(dn_in), .O(d_presync));
|
||||
|
||||
wire d_prefilter, d0p, d0n;
|
||||
sync d_sync(.clk(clk_48), .i(d_presync), .o(d_prefilter));
|
||||
sync d0p_sync(.clk(clk_48), .i(d0p_in), .o(d0p));
|
||||
sync d0n_sync(.clk(clk_48), .i(d0n_in), .o(d0n));
|
||||
|
||||
wire j;
|
||||
multisample3 d_filter(
|
||||
.clk(clk_48),
|
||||
.in(d_prefilter),
|
||||
.out(j));
|
||||
|
||||
wire se0;
|
||||
multisample5 se0_filter(
|
||||
.clk(clk_48),
|
||||
.in(!d0p && !d0n),
|
||||
.out(se0));
|
||||
|
||||
reg[2:0] short_idle_counter;
|
||||
assign short_idle = short_idle_counter == 1'b0;
|
||||
always @(posedge clk_48) begin
|
||||
if (se0 || !j)
|
||||
short_idle_counter <= 3'b111;
|
||||
else if (short_idle_counter != 1'b0)
|
||||
short_idle_counter <= short_idle_counter - 1'b1;
|
||||
end
|
||||
|
||||
wire nrzi_strobe;
|
||||
usb_clk_recovery clk_rcvr(
|
||||
.rst_n(rst_n),
|
||||
.clk(clk_48),
|
||||
.i(j),
|
||||
.strobe(nrzi_strobe)
|
||||
);
|
||||
|
||||
wire d;
|
||||
nrzi_decode nrzi_decoder(
|
||||
.clk(clk_48),
|
||||
.clken(nrzi_strobe),
|
||||
.i(j),
|
||||
.o(d));
|
||||
|
||||
wire strobe;
|
||||
usb_bit_destuff destuffer(
|
||||
.rst_n(rst_n),
|
||||
.clk(clk_48),
|
||||
.clken(nrzi_strobe),
|
||||
.d(d),
|
||||
.strobe(strobe)
|
||||
);
|
||||
|
||||
usb_reset_detect reset_detect(
|
||||
.rst_n(rst_n),
|
||||
.clk(clk_48),
|
||||
.se0(se0),
|
||||
.usb_rst(usb_rst));
|
||||
|
||||
wire sync_seq;
|
||||
usb_sync_detect sync_detect(
|
||||
.rst_n(rst_n),
|
||||
.clk(clk_48),
|
||||
.clken(nrzi_strobe),
|
||||
.j(j),
|
||||
.se0(se0),
|
||||
.sync(sync_seq));
|
||||
|
||||
wire strobed_xdatastrobe;
|
||||
assign xdatastrobe = strobed_xdatastrobe && strobe;
|
||||
|
||||
usb_recv_sm sm(
|
||||
.rst_n(rst_n),
|
||||
.clk(clk_48),
|
||||
.strobe(strobe),
|
||||
.din(d),
|
||||
.sync(sync_seq),
|
||||
.se0(se0),
|
||||
|
||||
.xpid(xpid),
|
||||
.xdata(xdata),
|
||||
.xpacket(xpacket),
|
||||
.xdatastrobe(strobed_xdatastrobe),
|
||||
.xcrc5_ok(xcrc5_ok),
|
||||
.xcrc16_ok(xcrc16_ok)
|
||||
);
|
||||
|
||||
endmodule
|
142
usb_tx.v
Normal file
142
usb_tx.v
Normal file
@ -0,0 +1,142 @@
|
||||
module usb_tx(
|
||||
input rst_n,
|
||||
input clk_48,
|
||||
|
||||
output usb_dp,
|
||||
output usb_dn,
|
||||
output usb_tx_en,
|
||||
|
||||
input transmit,
|
||||
input[7:0] data,
|
||||
input update_crc16,
|
||||
input send_crc16,
|
||||
output data_strobe
|
||||
);
|
||||
|
||||
reg[1:0] tx_clock;
|
||||
wire bit_strobe = tx_clock == 2'b00;
|
||||
always @(posedge clk_48 or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
tx_clock <= 2'b00;
|
||||
end else begin
|
||||
tx_clock <= tx_clock + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
wire bit_stuff;
|
||||
wire tx_strobe = bit_strobe && !bit_stuff;
|
||||
|
||||
reg[2:0] state;
|
||||
localparam
|
||||
st_idle = 3'b000,
|
||||
st_sync = 3'b101,
|
||||
st_run = 3'b001,
|
||||
st_eop1 = 3'b010,
|
||||
st_eop2 = 3'b011,
|
||||
st_eop3 = 3'b100,
|
||||
st_crc1 = 3'b110,
|
||||
st_crc2 = 3'b111;
|
||||
|
||||
assign usb_tx_en = (state != st_idle);
|
||||
|
||||
reg[8:0] tx_data;
|
||||
reg crc_enabled;
|
||||
|
||||
wire dump_crc = state == st_crc1 || state == st_crc2;
|
||||
wire crc_out;
|
||||
wire d = dump_crc? !crc_out: tx_data[0];
|
||||
wire se0 = state == st_eop1 || state == st_eop2;
|
||||
|
||||
wire tx_data_empty = (tx_data[8:2] == 1'b0);
|
||||
assign data_strobe = transmit && tx_data_empty && bit_strobe;
|
||||
|
||||
always @(posedge clk_48 or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= st_idle;
|
||||
end else if (tx_strobe) begin
|
||||
case (state)
|
||||
st_idle: begin
|
||||
if (transmit)
|
||||
state <= st_run;
|
||||
end
|
||||
st_sync: begin
|
||||
if (tx_data_empty)
|
||||
state <= st_run;
|
||||
end
|
||||
st_run: begin
|
||||
if (tx_data_empty && !transmit) begin
|
||||
if (send_crc16)
|
||||
state <= st_crc1;
|
||||
else
|
||||
state <= st_eop1;
|
||||
end
|
||||
end
|
||||
st_crc1: begin
|
||||
if (tx_data_empty)
|
||||
state <= st_crc2;
|
||||
end
|
||||
st_crc2: begin
|
||||
if (tx_data_empty)
|
||||
state <= st_eop1;
|
||||
end
|
||||
st_eop1: begin
|
||||
state <= st_eop2;
|
||||
end
|
||||
st_eop2: begin
|
||||
state <= st_eop3;
|
||||
end
|
||||
st_eop3: begin
|
||||
state <= st_idle;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_48) begin
|
||||
if (tx_strobe) begin
|
||||
if (!usb_tx_en) begin
|
||||
tx_data <= 9'b110000000; // starting with J, go through KJKJKJKK
|
||||
crc_enabled <= 1'b0;
|
||||
end else if (tx_data_empty) begin
|
||||
tx_data <= { 1'b1, data };
|
||||
crc_enabled <= update_crc16;
|
||||
end else begin
|
||||
tx_data <= { 1'b0, tx_data[8:1] };
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg[2:0] bit_stuff_counter;
|
||||
assign bit_stuff = bit_stuff_counter == 3'd6;
|
||||
always @(posedge clk_48 or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
bit_stuff_counter <= 1'b0;
|
||||
end else if (bit_strobe) begin
|
||||
if (state == st_idle || !d || bit_stuff || se0)
|
||||
bit_stuff_counter <= 1'b0;
|
||||
else
|
||||
bit_stuff_counter <= bit_stuff_counter + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
reg last_j;
|
||||
wire j = state == st_idle || state == st_eop3? 1'b1: (bit_stuff || !d? !last_j: last_j);
|
||||
always @(posedge clk_48) begin
|
||||
if (bit_strobe)
|
||||
last_j <= usb_tx_en? j: 1'b1;
|
||||
end
|
||||
|
||||
assign usb_dp = se0? 1'b0: j;
|
||||
assign usb_dn = se0? 1'b0: !j;
|
||||
|
||||
usb_crc16 tx_crc(
|
||||
.rst_n(rst_n && state != st_idle),
|
||||
.clk(clk_48),
|
||||
.clken(tx_strobe && (dump_crc || crc_enabled)),
|
||||
.d(d),
|
||||
.dump(dump_crc),
|
||||
.out(crc_out),
|
||||
.valid()
|
||||
);
|
||||
|
||||
endmodule
|
163
usb_utils.v
Normal file
163
usb_utils.v
Normal file
@ -0,0 +1,163 @@
|
||||
module usb_crc5(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input clken,
|
||||
input d,
|
||||
output valid
|
||||
);
|
||||
|
||||
reg[4:0] r;
|
||||
reg[4:0] next;
|
||||
|
||||
wire top = r[4];
|
||||
assign valid = (next == 5'b01100);
|
||||
|
||||
always @(*) begin
|
||||
if (top == d)
|
||||
next = { r[3], r[2], r[1], r[0], 1'b0 };
|
||||
else
|
||||
next = { r[3], r[2], !r[1], r[0], 1'b1 };
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
r <= 5'b11111;
|
||||
end else if (clken) begin
|
||||
r <= next;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module usb_crc16(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input clken,
|
||||
input d,
|
||||
|
||||
input dump,
|
||||
output out,
|
||||
output valid
|
||||
);
|
||||
|
||||
reg[15:0] r;
|
||||
reg[15:0] next;
|
||||
|
||||
assign out = r[15];
|
||||
assign valid = (next == 16'b1000000000001101);
|
||||
|
||||
always @(*) begin
|
||||
if (dump || out == d)
|
||||
next = { r[14:0], 1'b0 };
|
||||
else
|
||||
next = { !r[14], r[13:2], !r[1], r[0], 1'b1 };
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
r <= 16'hffff;
|
||||
end else if (clken) begin
|
||||
r <= next;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module usb_clk_recovery(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input i,
|
||||
output strobe
|
||||
);
|
||||
|
||||
reg[1:0] cntr;
|
||||
reg prev_i;
|
||||
|
||||
assign strobe = cntr == 1'b0;
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cntr <= 1'b0;
|
||||
prev_i <= 1'b0;
|
||||
end else begin
|
||||
if (i == prev_i) begin
|
||||
cntr <= cntr - 1'b1;
|
||||
end else begin
|
||||
cntr <= 1'b1;
|
||||
end
|
||||
prev_i <= i;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module usb_bit_destuff(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input clken,
|
||||
input d,
|
||||
output strobe);
|
||||
|
||||
reg[6:0] data;
|
||||
assign strobe = clken && (data != 7'b0111111);
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data <= 7'b0000000;
|
||||
end else if (clken) begin
|
||||
data <= { data[5:0], d };
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module usb_sync_detect(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input clken,
|
||||
input j,
|
||||
input se0,
|
||||
output sync);
|
||||
|
||||
// 3KJ's followed by 2K's
|
||||
reg[6:0] data;
|
||||
assign sync = (data == 7'b0101010 && !j && !se0);
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data <= 1'd0;
|
||||
end else if (clken) begin
|
||||
data <= { data[5:0], j || se0 };
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module usb_reset_detect(
|
||||
input rst_n,
|
||||
input clk,
|
||||
input se0,
|
||||
output usb_rst);
|
||||
|
||||
reg[18:0] cntr;
|
||||
assign usb_rst = cntr == 1'b0;
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cntr <= 1'b0;
|
||||
end else begin
|
||||
if (se0) begin
|
||||
if (!usb_rst)
|
||||
cntr <= cntr - 1'b1;
|
||||
end else begin
|
||||
cntr <= 19'd480000;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
112
utils.v
Normal file
112
utils.v
Normal file
@ -0,0 +1,112 @@
|
||||
module multisample3(
|
||||
input clk,
|
||||
input in,
|
||||
output reg out
|
||||
);
|
||||
|
||||
reg[2:0] r;
|
||||
|
||||
always @(r) begin
|
||||
case (r)
|
||||
3'b000: out = 1'b0;
|
||||
3'b001: out = 1'b0;
|
||||
3'b010: out = 1'b0;
|
||||
3'b011: out = 1'b1;
|
||||
3'b100: out = 1'b0;
|
||||
3'b101: out = 1'b1;
|
||||
3'b110: out = 1'b1;
|
||||
3'b111: out = 1'b1;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
r <= { r[1:0], in };
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module multisample5(
|
||||
input clk,
|
||||
input in,
|
||||
output reg out
|
||||
);
|
||||
|
||||
reg[4:0] r;
|
||||
|
||||
always @(r) begin
|
||||
case (r)
|
||||
5'b00000: out = 1'b0;
|
||||
5'b00001: out = 1'b0;
|
||||
5'b00010: out = 1'b0;
|
||||
5'b00011: out = 1'b0;
|
||||
5'b00100: out = 1'b0;
|
||||
5'b00101: out = 1'b0;
|
||||
5'b00110: out = 1'b0;
|
||||
5'b00111: out = 1'b1;
|
||||
5'b01000: out = 1'b0;
|
||||
5'b01001: out = 1'b0;
|
||||
5'b01010: out = 1'b0;
|
||||
5'b01011: out = 1'b1;
|
||||
5'b01100: out = 1'b0;
|
||||
5'b01101: out = 1'b1;
|
||||
5'b01110: out = 1'b1;
|
||||
5'b01111: out = 1'b1;
|
||||
5'b10000: out = 1'b0;
|
||||
5'b10001: out = 1'b0;
|
||||
5'b10010: out = 1'b0;
|
||||
5'b10011: out = 1'b1;
|
||||
5'b10100: out = 1'b0;
|
||||
5'b10101: out = 1'b1;
|
||||
5'b10110: out = 1'b1;
|
||||
5'b10111: out = 1'b1;
|
||||
5'b11000: out = 1'b0;
|
||||
5'b11001: out = 1'b1;
|
||||
5'b11010: out = 1'b1;
|
||||
5'b11011: out = 1'b1;
|
||||
5'b11100: out = 1'b1;
|
||||
5'b11101: out = 1'b1;
|
||||
5'b11110: out = 1'b1;
|
||||
5'b11111: out = 1'b1;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
r <= { r[3:0], in };
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module sync(
|
||||
input clk,
|
||||
input i,
|
||||
output o);
|
||||
|
||||
reg[2:0] s;
|
||||
assign o = s[1];
|
||||
|
||||
always @(posedge clk) begin
|
||||
s <= { s[1:0], i };
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
module nrzi_decode(
|
||||
input clk,
|
||||
input clken,
|
||||
input i,
|
||||
output o
|
||||
);
|
||||
|
||||
reg prev_i;
|
||||
assign o = (prev_i == i);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (clken) begin
|
||||
prev_i <= i;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user