-
Notifications
You must be signed in to change notification settings - Fork 40
/
usb_tx.v
142 lines (126 loc) · 3.36 KB
/
usb_tx.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
module usb_tx(
input rst_n,
input clk_48,
output tx_en,
output tx_j,
output tx_se0,
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 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 = !bit_stuff && (state == st_eop1 || state == st_eop2);
wire tx_data_empty = (tx_data[8:2] == 1'b0);
assign data_strobe = transmit && tx_data_empty && tx_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 (!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 <= tx_en? j: 1'b1;
end
assign tx_j = j;
assign tx_se0 = se0;
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