forked from Spritetm/hadbadge2019_fpgasoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
usb_phy.v
181 lines (169 loc) · 4.21 KB
/
usb_phy.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
* usb_phy.v
*
* vim: ts=4 sw=4
*
* Copyright (C) 2019 Sylvain Munaut
* All rights reserved.
*
* LGPL v3+, see LICENSE.lgpl3
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
`default_nettype none
module usb_phy #(
parameter TARGET = "ICE40"
)(
// Pads
inout wire pad_dp,
inout wire pad_dn,
// RX
output wire rx_dp,
output wire rx_dn,
output wire rx_chg,
// TX
input wire tx_dp,
input wire tx_dn,
input wire tx_en,
// Common
input wire clk,
input wire rst
);
wire [1:0] rx_dp_i;
wire [1:0] rx_dn_i;
reg [2:0] dp_state;
reg [2:0] dn_state;
// IO buffers
generate
if (TARGET == "xxICE40") begin
SB_IO #(
.PIN_TYPE(6'b110100),
.PULLUP(1'b0),
.NEG_TRIGGER(1'b0),
.IO_STANDARD("SB_LVCMOS")
) io_dp_I (
.PACKAGE_PIN(pad_dp),
.LATCH_INPUT_VALUE(1'b0),
.CLOCK_ENABLE(1'b1),
.INPUT_CLK(clk),
.OUTPUT_CLK(clk),
.OUTPUT_ENABLE(tx_en),
.D_OUT_0(tx_dp),
.D_OUT_1(1'b0),
.D_IN_0(rx_dp_i[0]),
.D_IN_1(rx_dp_i[1])
);
SB_IO #(
.PIN_TYPE(6'b110100),
.PULLUP(1'b0),
.NEG_TRIGGER(1'b0),
.IO_STANDARD("SB_LVCMOS")
) io_dn_I (
.PACKAGE_PIN(pad_dn),
.LATCH_INPUT_VALUE(1'b0),
.CLOCK_ENABLE(1'b1),
.INPUT_CLK(clk),
.OUTPUT_CLK(clk),
.OUTPUT_ENABLE(tx_en),
.D_OUT_0(tx_dn),
.D_OUT_1(1'b0),
.D_IN_0(rx_dn_i[0]),
.D_IN_1(rx_dn_i[1])
);
end else if (TARGET == "ECP5") begin
//ecp5 io isn't latching (afaik); manually latch instead.
wire rx_dp_in;
wire rx_dn_in;
reg [1:0] rx_dp_in_l;
reg [1:0] rx_dn_in_l;
TRELLIS_IO #(
.DIR("BIDIR")
) io_dp_I (
.O(rx_dp_in),
.T(!tx_en),
.B(pad_dp),
.I(tx_dp)
);
TRELLIS_IO #(
.DIR("BIDIR")
) io_dn_I (
.O(rx_dn_in),
.T(!tx_en),
.B(pad_dn),
.I(tx_dn)
);
always @(posedge clk) begin
rx_dp_in_l[0] <= rx_dp_in;
rx_dn_in_l[0] <= rx_dn_in;
end
always @(negedge clk) begin
rx_dp_in_l[1] <= rx_dp_in;
rx_dn_in_l[1] <= rx_dn_in;
end
assign rx_dp_i = rx_dp_in_l;
assign rx_dn_i = rx_dn_in_l;
end
endgenerate
// Input sync, filter and change detect
always @(posedge clk or posedge rst)
begin
if (rst) begin
dp_state <= 3'b000;
dn_state <= 3'b000;
end else begin
case ({dp_state[1:0], rx_dp_i})
4'b0000: dp_state <= 3'b000;
4'b0001: dp_state <= 3'b001;
4'b0010: dp_state <= 3'b001;
4'b0011: dp_state <= 3'b001;
4'b0100: dp_state <= 3'b000;
4'b0101: dp_state <= 3'b001;
4'b0110: dp_state <= 3'b001;
4'b0111: dp_state <= 3'b111;
4'b1000: dp_state <= 3'b100;
4'b1001: dp_state <= 3'b010;
4'b1010: dp_state <= 3'b010;
4'b1011: dp_state <= 3'b011;
4'b1100: dp_state <= 3'b010;
4'b1101: dp_state <= 3'b010;
4'b1110: dp_state <= 3'b010;
4'b1111: dp_state <= 3'b011;
default: dp_state <= 3'bxxx;
endcase
case ({dn_state[1:0], rx_dn_i})
4'b0000: dn_state <= 3'b000;
4'b0001: dn_state <= 3'b001;
4'b0010: dn_state <= 3'b001;
4'b0011: dn_state <= 3'b001;
4'b0100: dn_state <= 3'b000;
4'b0101: dn_state <= 3'b001;
4'b0110: dn_state <= 3'b001;
4'b0111: dn_state <= 3'b111;
4'b1000: dn_state <= 3'b100;
4'b1001: dn_state <= 3'b010;
4'b1010: dn_state <= 3'b010;
4'b1011: dn_state <= 3'b011;
4'b1100: dn_state <= 3'b010;
4'b1101: dn_state <= 3'b010;
4'b1110: dn_state <= 3'b010;
4'b1111: dn_state <= 3'b011;
default: dn_state <= 3'bxxx;
endcase
end
end
assign rx_dp = dp_state[1];
assign rx_dn = dn_state[1];
assign rx_chg = dp_state[2] | dn_state[2];
endmodule // usb_phy