├── README.md └── src_v ├── ulpi_wrapper.v ├── usb_cdc_core.v ├── usb_cdc_top.v ├── usb_desc_rom.v ├── usbf_crc16.v ├── usbf_defs.v ├── usbf_device_core.v ├── usbf_sie_rx.v └── usbf_sie_tx.v /README.md: -------------------------------------------------------------------------------- 1 | ### USB Serial Port Device (USB-CDC) 2 | 3 | Github: [https://github.com/ultraembedded/core_usb_uart](https://github.com/ultraembedded/core_usb_uart) 4 | 5 | This component is a simple USB Peripheral Interface (Device) implementation which enumerates as either a high-speed (480Mbit/s) or full-speed (12Mbit/s) CDC-ACM device. 6 | 7 | This IP acts as a USB to serial port (UART) converter which can be used to add a UART to a FPGA which has a ULPI interface. 8 | 9 | ##### Features 10 | * High or Full speed USB CDC device. 11 | * Enumeration in hardware - no SW intervention required. 12 | * ULPI interface (suitable for connection to a ULPI PHY - e.g. Microchip USB3300) 13 | * Fixed baud rate (param) Rx, Tx pins. 14 | 15 | ##### Example instantiation (Xilinx) 16 | ``` 17 | module usb_serial 18 | //----------------------------------------------------------------- 19 | // Params 20 | //----------------------------------------------------------------- 21 | #( 22 | parameter BAUDRATE = 1000000 23 | ) 24 | //----------------------------------------------------------------- 25 | // Ports 26 | //----------------------------------------------------------------- 27 | ( 28 | output uart_rx_o 29 | , input uart_tx_i 30 | 31 | // ULPI Interface 32 | , output ulpi_reset_o 33 | , inout [7:0] ulpi_data_io 34 | , output ulpi_stp_o 35 | , input ulpi_nxt_i 36 | , input ulpi_dir_i 37 | , input ulpi_clk60_i 38 | ); 39 | 40 | // USB clock / reset 41 | wire usb_clk_w; 42 | wire usb_rst_w; 43 | 44 | wire clk_bufg_w; 45 | IBUF u_ibuf ( .I(ulpi_clk60_i), .O(clk_bufg_w) ); 46 | BUFG u_bufg ( .I(clk_bufg_w), .O(usb_clk_w) ); 47 | 48 | reg [3:0] count_q = 4'b0; 49 | reg rst_q = 1'b1; 50 | 51 | always @(posedge usb_clk_w) 52 | if (count_q != 4'hF) 53 | count_q <= count_q + 4'd1; 54 | else 55 | rst_q <= 1'b0; 56 | 57 | assign usb_rst_w = rst_q; 58 | 59 | // ULPI Buffers 60 | wire [7:0] ulpi_out_w; 61 | wire [7:0] ulpi_in_w; 62 | wire ulpi_stp_w; 63 | 64 | genvar i; 65 | generate 66 | for (i=0; i < 8; i=i+1) 67 | begin: gen_buf 68 | IOBUF 69 | #( 70 | .DRIVE(12), 71 | .IOSTANDARD("DEFAULT"), 72 | .SLEW("FAST") 73 | ) 74 | IOBUF_inst 75 | ( 76 | .T(ulpi_dir_i), 77 | .I(ulpi_out_w[i]), 78 | .O(ulpi_in_w[i]), 79 | .IO(ulpi_data_io[i]) 80 | ); 81 | end 82 | endgenerate 83 | 84 | OBUF 85 | #( 86 | .DRIVE(12), 87 | .IOSTANDARD("DEFAULT"), 88 | .SLEW("FAST") 89 | ) 90 | OBUF_stp 91 | ( 92 | .I(ulpi_stp_w), 93 | .O(ulpi_stp_o) 94 | ); 95 | 96 | // USB Core 97 | usb_cdc_top 98 | #( .BAUDRATE(BAUDRATE) ) 99 | u_usb 100 | ( 101 | .clk_i(usb_clk_w) 102 | ,.rst_i(usb_rst_w) 103 | 104 | // ULPI 105 | ,.ulpi_data_out_i(ulpi_in_w) 106 | ,.ulpi_dir_i(ulpi_dir_i) 107 | ,.ulpi_nxt_i(ulpi_nxt_i) 108 | ,.ulpi_data_in_o(ulpi_out_w) 109 | ,.ulpi_stp_o(ulpi_stp_w) 110 | 111 | ,.tx_i(uart_tx_i) 112 | ,.rx_o(uart_rx_o) 113 | ); 114 | 115 | assign ulpi_reset_o = 1'b0; 116 | 117 | endmodule 118 | ``` 119 | 120 | ##### Limitations 121 | * Really basic USB-CDC class device implementation, will ignore encap, line state and line coding change requests! 122 | * USB suspend/resume will not work correctly. 123 | 124 | ##### Testing 125 | Verified under simulation then tested on FPGA against Linux, Windows and MAC OS-X. 126 | 127 | ##### References 128 | * [USB 2.0 Specification](https://usb.org/developers/docs/usb20_docs) 129 | * [ULPI Specification](https://www.sparkfun.com/datasheets/Components/SMD/ULPI_v1_1.pdf) 130 | * [USB Made Simple](http://www.usbmadesimple.co.uk/) 131 | -------------------------------------------------------------------------------- /src_v/ulpi_wrapper.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module ulpi_wrapper 40 | ( 41 | // Inputs 42 | input ulpi_clk60_i 43 | ,input ulpi_rst_i 44 | ,input [ 7:0] ulpi_data_out_i 45 | ,input ulpi_dir_i 46 | ,input ulpi_nxt_i 47 | ,input [ 7:0] utmi_data_out_i 48 | ,input utmi_txvalid_i 49 | ,input [ 1:0] utmi_op_mode_i 50 | ,input [ 1:0] utmi_xcvrselect_i 51 | ,input utmi_termselect_i 52 | ,input utmi_dppulldown_i 53 | ,input utmi_dmpulldown_i 54 | 55 | // Outputs 56 | ,output [ 7:0] ulpi_data_in_o 57 | ,output ulpi_stp_o 58 | ,output [ 7:0] utmi_data_in_o 59 | ,output utmi_txready_o 60 | ,output utmi_rxvalid_o 61 | ,output utmi_rxactive_o 62 | ,output utmi_rxerror_o 63 | ,output [ 1:0] utmi_linestate_o 64 | ); 65 | 66 | 67 | 68 | //----------------------------------------------------------------- 69 | // Module: UTMI+ to ULPI Wrapper 70 | // 71 | // Description: 72 | // - Converts from UTMI interface to reduced pin count ULPI. 73 | // - No support for low power mode. 74 | // - I/O synchronous to 60MHz ULPI clock input (from PHY) 75 | // - Tested against SMSC/Microchip USB3300 in device mode. 76 | //----------------------------------------------------------------- 77 | 78 | //----------------------------------------------------------------- 79 | // States 80 | //----------------------------------------------------------------- 81 | localparam STATE_W = 2; 82 | localparam STATE_IDLE = 2'd0; 83 | localparam STATE_CMD = 2'd1; 84 | localparam STATE_DATA = 2'd2; 85 | localparam STATE_REG = 2'd3; 86 | 87 | reg [STATE_W-1:0] state_q; 88 | 89 | //----------------------------------------------------------------- 90 | // Local Params 91 | //----------------------------------------------------------------- 92 | localparam REG_FUNC_CTRL = 8'h84; 93 | localparam REG_OTG_CTRL = 8'h8a; 94 | localparam REG_TRANSMIT = 8'h40; 95 | localparam REG_WRITE = 8'h80; 96 | localparam REG_READ = 8'hC0; 97 | 98 | //----------------------------------------------------------------- 99 | // UTMI Mode Select 100 | //----------------------------------------------------------------- 101 | reg mode_update_q; 102 | reg [1:0] xcvrselect_q; 103 | reg termselect_q; 104 | reg [1:0] opmode_q; 105 | reg phy_reset_q; 106 | reg mode_write_q; 107 | 108 | // Detect register write completion 109 | wire mode_complete_w = (state_q == STATE_REG && 110 | mode_write_q && 111 | ulpi_nxt_i && 112 | !ulpi_dir_i); // Not interrupted by a Rx 113 | 114 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 115 | if (ulpi_rst_i) 116 | begin 117 | mode_update_q <= 1'b0; 118 | xcvrselect_q <= 2'b0; 119 | termselect_q <= 1'b0; 120 | opmode_q <= 2'b11; 121 | phy_reset_q <= 1'b1; 122 | end 123 | else 124 | begin 125 | xcvrselect_q <= utmi_xcvrselect_i; 126 | termselect_q <= utmi_termselect_i; 127 | opmode_q <= utmi_op_mode_i; 128 | 129 | if (mode_update_q && mode_complete_w) 130 | begin 131 | mode_update_q <= 1'b0; 132 | phy_reset_q <= 1'b0; 133 | end 134 | else if (opmode_q != utmi_op_mode_i || 135 | termselect_q != utmi_termselect_i || 136 | xcvrselect_q != utmi_xcvrselect_i) 137 | mode_update_q <= 1'b1; 138 | end 139 | 140 | //----------------------------------------------------------------- 141 | // UTMI OTG Control 142 | //----------------------------------------------------------------- 143 | reg otg_update_q; 144 | reg dppulldown_q; 145 | reg dmpulldown_q; 146 | reg otg_write_q; 147 | 148 | // Detect register write completion 149 | wire otg_complete_w = (state_q == STATE_REG && 150 | otg_write_q && 151 | ulpi_nxt_i && 152 | !ulpi_dir_i); // Not interrupted by a Rx 153 | 154 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 155 | if (ulpi_rst_i) 156 | begin 157 | otg_update_q <= 1'b0; 158 | dppulldown_q <= 1'b1; 159 | dmpulldown_q <= 1'b1; 160 | end 161 | else 162 | begin 163 | dppulldown_q <= utmi_dppulldown_i; 164 | dmpulldown_q <= utmi_dmpulldown_i; 165 | 166 | if (otg_update_q && otg_complete_w) 167 | otg_update_q <= 1'b0; 168 | else if (dppulldown_q != utmi_dppulldown_i || 169 | dmpulldown_q != utmi_dmpulldown_i) 170 | otg_update_q <= 1'b1; 171 | end 172 | 173 | //----------------------------------------------------------------- 174 | // Bus turnaround detect 175 | //----------------------------------------------------------------- 176 | reg ulpi_dir_q; 177 | 178 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 179 | if (ulpi_rst_i) 180 | ulpi_dir_q <= 1'b0; 181 | else 182 | ulpi_dir_q <= ulpi_dir_i; 183 | 184 | wire turnaround_w = ulpi_dir_q ^ ulpi_dir_i; 185 | 186 | //----------------------------------------------------------------- 187 | // Rx - Tx delay 188 | //----------------------------------------------------------------- 189 | localparam TX_DELAY_W = 3; 190 | localparam TX_START_DELAY = 3'd7; 191 | 192 | reg [TX_DELAY_W-1:0] tx_delay_q; 193 | 194 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 195 | if (ulpi_rst_i) 196 | tx_delay_q <= {TX_DELAY_W{1'b0}}; 197 | else if (utmi_rxactive_o) 198 | tx_delay_q <= TX_START_DELAY; 199 | else if (tx_delay_q != {TX_DELAY_W{1'b0}}) 200 | tx_delay_q <= tx_delay_q - 1; 201 | 202 | wire tx_delay_complete_w = (tx_delay_q == {TX_DELAY_W{1'b0}}); 203 | 204 | //----------------------------------------------------------------- 205 | // Tx Buffer - decouple UTMI Tx from PHY I/O 206 | //----------------------------------------------------------------- 207 | reg [7:0] tx_buffer_q[0:1]; 208 | reg tx_valid_q[0:1]; 209 | reg tx_wr_idx_q; 210 | reg tx_rd_idx_q; 211 | 212 | wire utmi_tx_ready_w; 213 | wire utmi_tx_accept_w; 214 | 215 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 216 | if (ulpi_rst_i) 217 | begin 218 | tx_buffer_q[0] <= 8'b0; 219 | tx_buffer_q[1] <= 8'b0; 220 | tx_valid_q[0] <= 1'b0; 221 | tx_valid_q[1] <= 1'b0; 222 | tx_wr_idx_q <= 1'b0; 223 | tx_rd_idx_q <= 1'b0; 224 | end 225 | else 226 | begin 227 | // Push 228 | if (utmi_txvalid_i && utmi_txready_o) 229 | begin 230 | tx_buffer_q[tx_wr_idx_q] <= utmi_data_out_i; 231 | tx_valid_q[tx_wr_idx_q] <= 1'b1; 232 | 233 | tx_wr_idx_q <= tx_wr_idx_q + 1'b1; 234 | end 235 | 236 | // Pop 237 | if (utmi_tx_ready_w && utmi_tx_accept_w) 238 | begin 239 | tx_valid_q[tx_rd_idx_q] <= 1'b0; 240 | tx_rd_idx_q <= tx_rd_idx_q + 1'b1; 241 | end 242 | end 243 | 244 | // Tx buffer space (only accept after Rx->Tx turnaround delay) 245 | assign utmi_txready_o = ~tx_valid_q[tx_wr_idx_q] & tx_delay_complete_w; 246 | 247 | assign utmi_tx_ready_w = tx_valid_q[tx_rd_idx_q]; 248 | 249 | wire [7:0] utmi_tx_data_w = tx_buffer_q[tx_rd_idx_q]; 250 | 251 | //----------------------------------------------------------------- 252 | // Implementation 253 | //----------------------------------------------------------------- 254 | 255 | // Xilinx placement pragmas: 256 | //synthesis attribute IOB of ulpi_data_q is "TRUE" 257 | //synthesis attribute IOB of ulpi_stp_q is "TRUE" 258 | 259 | reg [7:0] ulpi_data_q; 260 | reg ulpi_stp_q; 261 | reg [7:0] data_q; 262 | 263 | reg utmi_rxvalid_q; 264 | reg utmi_rxerror_q; 265 | reg utmi_rxactive_q; 266 | reg [1:0] utmi_linestate_q; 267 | reg [7:0] utmi_data_q; 268 | 269 | always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) 270 | if (ulpi_rst_i) 271 | begin 272 | state_q <= STATE_IDLE; 273 | ulpi_data_q <= 8'b0; 274 | data_q <= 8'b0; 275 | ulpi_stp_q <= 1'b1; 276 | 277 | utmi_rxvalid_q <= 1'b0; 278 | utmi_rxerror_q <= 1'b0; 279 | utmi_rxactive_q <= 1'b0; 280 | utmi_linestate_q <= 2'b0; 281 | utmi_data_q <= 8'b0; 282 | 283 | mode_write_q <= 1'b0; 284 | otg_write_q <= 1'b0; 285 | end 286 | else 287 | begin 288 | ulpi_stp_q <= 1'b0; 289 | utmi_rxvalid_q <= 1'b0; 290 | 291 | // Turnaround: Input + NXT - set RX_ACTIVE 292 | if (turnaround_w && ulpi_dir_i && ulpi_nxt_i) 293 | begin 294 | utmi_rxactive_q <= 1'b1; 295 | 296 | // Register write - abort 297 | if (state_q == STATE_REG) 298 | begin 299 | state_q <= STATE_IDLE; 300 | ulpi_data_q <= 8'b0; // IDLE 301 | end 302 | end 303 | // Turnaround: Input -> Output - reset RX_ACTIVE 304 | else if (turnaround_w && !ulpi_dir_i) 305 | begin 306 | utmi_rxactive_q <= 1'b0; 307 | 308 | // Register write - abort 309 | if (state_q == STATE_REG) 310 | begin 311 | state_q <= STATE_IDLE; 312 | ulpi_data_q <= 8'b0; // IDLE 313 | end 314 | end 315 | // Non-turnaround cycle 316 | else if (!turnaround_w) 317 | begin 318 | //----------------------------------------------------------------- 319 | // Input: RX_CMD (status) 320 | //----------------------------------------------------------------- 321 | if (ulpi_dir_i && !ulpi_nxt_i) 322 | begin 323 | // Phy status 324 | utmi_linestate_q <= ulpi_data_out_i[1:0]; 325 | 326 | case (ulpi_data_out_i[5:4]) 327 | 2'b00: 328 | begin 329 | utmi_rxactive_q <= 1'b0; 330 | utmi_rxerror_q <= 1'b0; 331 | end 332 | 2'b01: 333 | begin 334 | utmi_rxactive_q <= 1'b1; 335 | utmi_rxerror_q <= 1'b0; 336 | end 337 | 2'b11: 338 | begin 339 | utmi_rxactive_q <= 1'b1; 340 | utmi_rxerror_q <= 1'b1; 341 | end 342 | default: 343 | ; // HOST_DISCONNECTED 344 | endcase 345 | end 346 | //----------------------------------------------------------------- 347 | // Input: RX_DATA 348 | //----------------------------------------------------------------- 349 | else if (ulpi_dir_i && ulpi_nxt_i) 350 | begin 351 | utmi_rxvalid_q <= 1'b1; 352 | utmi_data_q <= ulpi_data_out_i; 353 | end 354 | //----------------------------------------------------------------- 355 | // Output 356 | //----------------------------------------------------------------- 357 | else if (!ulpi_dir_i) 358 | begin 359 | // IDLE: Pending mode update 360 | if ((state_q == STATE_IDLE) && mode_update_q) 361 | begin 362 | data_q <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q}; 363 | ulpi_data_q <= REG_FUNC_CTRL; 364 | 365 | otg_write_q <= 1'b0; 366 | mode_write_q <= 1'b1; 367 | 368 | state_q <= STATE_CMD; 369 | end 370 | // IDLE: Pending OTG control update 371 | else if ((state_q == STATE_IDLE) && otg_update_q) 372 | begin 373 | data_q <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0}; 374 | ulpi_data_q <= REG_OTG_CTRL; 375 | 376 | otg_write_q <= 1'b1; 377 | mode_write_q <= 1'b0; 378 | 379 | state_q <= STATE_CMD; 380 | end 381 | // IDLE: Pending transmit 382 | else if ((state_q == STATE_IDLE) && utmi_tx_ready_w) 383 | begin 384 | ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]}; 385 | state_q <= STATE_DATA; 386 | end 387 | // Command 388 | else if ((state_q == STATE_CMD) && ulpi_nxt_i) 389 | begin 390 | // Write Register 391 | state_q <= STATE_REG; 392 | ulpi_data_q <= data_q; 393 | end 394 | // Data (register write) 395 | else if (state_q == STATE_REG && ulpi_nxt_i) 396 | begin 397 | state_q <= STATE_IDLE; 398 | ulpi_data_q <= 8'b0; // IDLE 399 | ulpi_stp_q <= 1'b1; 400 | 401 | otg_write_q <= 1'b0; 402 | mode_write_q <= 1'b0; 403 | end 404 | // Data 405 | else if (state_q == STATE_DATA && ulpi_nxt_i) 406 | begin 407 | // End of packet 408 | if (!utmi_tx_ready_w) 409 | begin 410 | state_q <= STATE_IDLE; 411 | ulpi_data_q <= 8'b0; // IDLE 412 | ulpi_stp_q <= 1'b1; 413 | end 414 | else 415 | begin 416 | state_q <= STATE_DATA; 417 | ulpi_data_q <= utmi_tx_data_w; 418 | end 419 | end 420 | end 421 | end 422 | end 423 | 424 | // Accept from buffer 425 | assign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w) && !ulpi_dir_i) || 426 | (state_q == STATE_DATA && ulpi_nxt_i && !ulpi_dir_i); 427 | 428 | //----------------------------------------------------------------- 429 | // Assignments 430 | //----------------------------------------------------------------- 431 | // ULPI Interface 432 | assign ulpi_data_in_o = ulpi_data_q; 433 | assign ulpi_stp_o = ulpi_stp_q; 434 | 435 | // UTMI Interface 436 | assign utmi_linestate_o = utmi_linestate_q; 437 | assign utmi_data_in_o = utmi_data_q; 438 | assign utmi_rxerror_o = utmi_rxerror_q; 439 | assign utmi_rxactive_o = utmi_rxactive_q; 440 | assign utmi_rxvalid_o = utmi_rxvalid_q; 441 | 442 | 443 | 444 | endmodule 445 | -------------------------------------------------------------------------------- /src_v/usb_cdc_core.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usb_cdc_core 40 | ( 41 | // Inputs 42 | input clk_i 43 | ,input rst_i 44 | ,input enable_i 45 | ,input [ 7:0] utmi_data_in_i 46 | ,input utmi_txready_i 47 | ,input utmi_rxvalid_i 48 | ,input utmi_rxactive_i 49 | ,input utmi_rxerror_i 50 | ,input [ 1:0] utmi_linestate_i 51 | ,input inport_valid_i 52 | ,input [ 7:0] inport_data_i 53 | ,input outport_accept_i 54 | 55 | // Outputs 56 | ,output [ 7:0] utmi_data_out_o 57 | ,output utmi_txvalid_o 58 | ,output [ 1:0] utmi_op_mode_o 59 | ,output [ 1:0] utmi_xcvrselect_o 60 | ,output utmi_termselect_o 61 | ,output utmi_dppulldown_o 62 | ,output utmi_dmpulldown_o 63 | ,output inport_accept_o 64 | ,output outport_valid_o 65 | ,output [ 7:0] outport_data_o 66 | ); 67 | 68 | 69 | 70 | 71 | parameter USB_SPEED_HS = "False"; // True or False 72 | 73 | //----------------------------------------------------------------- 74 | // Defines 75 | //----------------------------------------------------------------- 76 | // Device class 77 | `define DEV_CLASS_RESERVED 8'h00 78 | `define DEV_CLASS_AUDIO 8'h01 79 | `define DEV_CLASS_COMMS 8'h02 80 | `define DEV_CLASS_HID 8'h03 81 | `define DEV_CLASS_MONITOR 8'h04 82 | `define DEV_CLASS_PHY_IF 8'h05 83 | `define DEV_CLASS_POWER 8'h06 84 | `define DEV_CLASS_PRINTER 8'h07 85 | `define DEV_CLASS_STORAGE 8'h08 86 | `define DEV_CLASS_HUB 8'h09 87 | `define DEV_CLASS_TMC 8'hFE 88 | `define DEV_CLASS_VENDOR_CUSTOM 8'hFF 89 | 90 | // Standard requests (via SETUP packets) 91 | `define REQ_GET_STATUS 8'h00 92 | `define REQ_CLEAR_FEATURE 8'h01 93 | `define REQ_SET_FEATURE 8'h03 94 | `define REQ_SET_ADDRESS 8'h05 95 | `define REQ_GET_DESCRIPTOR 8'h06 96 | `define REQ_SET_DESCRIPTOR 8'h07 97 | `define REQ_GET_CONFIGURATION 8'h08 98 | `define REQ_SET_CONFIGURATION 8'h09 99 | `define REQ_GET_INTERFACE 8'h0A 100 | `define REQ_SET_INTERFACE 8'h0B 101 | `define REQ_SYNC_FRAME 8'h0C 102 | 103 | // Descriptor types 104 | `define DESC_DEVICE 8'h01 105 | `define DESC_CONFIGURATION 8'h02 106 | `define DESC_STRING 8'h03 107 | `define DESC_INTERFACE 8'h04 108 | `define DESC_ENDPOINT 8'h05 109 | `define DESC_DEV_QUALIFIER 8'h06 110 | `define DESC_OTHER_SPEED_CONF 8'h07 111 | `define DESC_IF_POWER 8'h08 112 | 113 | // Endpoints 114 | `define ENDPOINT_DIR_MASK 8'h80 115 | `define ENDPOINT_DIR_R 7 116 | `define ENDPOINT_DIR_IN 1'b1 117 | `define ENDPOINT_DIR_OUT 1'b0 118 | `define ENDPOINT_ADDR_MASK 8'h7F 119 | `define ENDPOINT_TYPE_MASK 8'h3 120 | `define ENDPOINT_TYPE_CONTROL 0 121 | `define ENDPOINT_TYPE_ISO 1 122 | `define ENDPOINT_TYPE_BULK 2 123 | `define ENDPOINT_TYPE_INTERRUPT 3 124 | 125 | // Device Requests (bmRequestType) 126 | `define USB_RECIPIENT_MASK 8'h1F 127 | `define USB_RECIPIENT_DEVICE 8'h00 128 | `define USB_RECIPIENT_INTERFACE 8'h01 129 | `define USB_RECIPIENT_ENDPOINT 8'h02 130 | `define USB_REQUEST_TYPE_MASK 8'h60 131 | `define USB_STANDARD_REQUEST 8'h00 132 | `define USB_CLASS_REQUEST 8'h20 133 | `define USB_VENDOR_REQUEST 8'h40 134 | 135 | // USB device addresses are 7-bits 136 | `define USB_ADDRESS_MASK 8'h7F 137 | 138 | // USB Feature Selectors 139 | `define USB_FEATURE_ENDPOINT_STATE 16'h0000 140 | `define USB_FEATURE_REMOTE_WAKEUP 16'h0001 141 | `define USB_FEATURE_TEST_MODE 16'h0002 142 | 143 | // String Descriptors 144 | `define UNICODE_LANGUAGE_STR_ID 8'd0 145 | `define MANUFACTURER_STR_ID 8'd1 146 | `define PRODUCT_NAME_STR_ID 8'd2 147 | `define SERIAL_NUM_STR_ID 8'd3 148 | 149 | `define CDC_ENDPOINT_BULK_OUT 1 150 | `define CDC_ENDPOINT_BULK_IN 2 151 | `define CDC_ENDPOINT_INTR_IN 3 152 | 153 | `define CDC_SEND_ENCAPSULATED_COMMAND 8'h00 154 | `define CDC_GET_ENCAPSULATED_RESPONSE 8'h01 155 | `define CDC_GET_LINE_CODING 8'h21 156 | `define CDC_SET_LINE_CODING 8'h20 157 | `define CDC_SET_CONTROL_LINE_STATE 8'h22 158 | `define CDC_SEND_BREAK 8'h23 159 | 160 | // Descriptor ROM offsets / sizes 161 | `define ROM_DESC_DEVICE_ADDR 8'd0 162 | `define ROM_DESC_DEVICE_SIZE 16'd18 163 | `define ROM_DESC_CONF_ADDR 8'd18 164 | `define ROM_DESC_CONF_SIZE 16'd67 165 | `define ROM_DESC_STR_LANG_ADDR 8'd85 166 | `define ROM_DESC_STR_LANG_SIZE 16'd4 167 | `define ROM_DESC_STR_MAN_ADDR 8'd89 168 | `define ROM_DESC_STR_MAN_SIZE 16'd30 169 | `define ROM_DESC_STR_PROD_ADDR 8'd119 170 | `define ROM_DESC_STR_PROD_SIZE 16'd30 171 | `define ROM_DESC_STR_SERIAL_ADDR 8'd149 172 | `define ROM_DESC_STR_SERIAL_SIZE 16'd14 173 | `define ROM_CDC_LINE_CODING_ADDR 8'd163 174 | `define ROM_CDC_LINE_CODING_SIZE 16'd7 175 | 176 | //----------------------------------------------------------------- 177 | // Wires 178 | //----------------------------------------------------------------- 179 | wire usb_reset_w; 180 | reg [6:0] device_addr_q; 181 | 182 | wire usb_ep0_tx_rd_w; 183 | wire [7:0] usb_ep0_tx_data_w; 184 | wire usb_ep0_tx_empty_w; 185 | 186 | wire usb_ep0_rx_wr_w; 187 | wire [7:0] usb_ep0_rx_data_w; 188 | wire usb_ep0_rx_full_w; 189 | wire usb_ep1_tx_rd_w; 190 | wire [7:0] usb_ep1_tx_data_w; 191 | wire usb_ep1_tx_empty_w; 192 | 193 | wire usb_ep1_rx_wr_w; 194 | wire [7:0] usb_ep1_rx_data_w; 195 | wire usb_ep1_rx_full_w; 196 | wire usb_ep2_tx_rd_w; 197 | wire [7:0] usb_ep2_tx_data_w; 198 | wire usb_ep2_tx_empty_w; 199 | 200 | wire usb_ep2_rx_wr_w; 201 | wire [7:0] usb_ep2_rx_data_w; 202 | wire usb_ep2_rx_full_w; 203 | wire usb_ep3_tx_rd_w; 204 | wire [7:0] usb_ep3_tx_data_w; 205 | wire usb_ep3_tx_empty_w; 206 | 207 | wire usb_ep3_rx_wr_w; 208 | wire [7:0] usb_ep3_rx_data_w; 209 | wire usb_ep3_rx_full_w; 210 | 211 | // Rx SIE Interface (shared) 212 | wire rx_strb_w; 213 | wire [7:0] rx_data_w; 214 | wire rx_last_w; 215 | wire rx_crc_err_w; 216 | 217 | // EP0 Rx SIE Interface 218 | wire ep0_rx_space_w; 219 | wire ep0_rx_valid_w; 220 | wire ep0_rx_setup_w; 221 | 222 | // EP0 Tx SIE Interface 223 | wire ep0_tx_ready_w; 224 | wire ep0_tx_data_valid_w; 225 | wire ep0_tx_data_strb_w; 226 | wire [7:0] ep0_tx_data_w; 227 | wire ep0_tx_data_last_w; 228 | wire ep0_tx_data_accept_w; 229 | wire ep0_tx_stall_w; 230 | // EP1 Rx SIE Interface 231 | wire ep1_rx_space_w; 232 | wire ep1_rx_valid_w; 233 | wire ep1_rx_setup_w; 234 | 235 | // EP1 Tx SIE Interface 236 | wire ep1_tx_ready_w; 237 | wire ep1_tx_data_valid_w; 238 | wire ep1_tx_data_strb_w; 239 | wire [7:0] ep1_tx_data_w; 240 | wire ep1_tx_data_last_w; 241 | wire ep1_tx_data_accept_w; 242 | wire ep1_tx_stall_w; 243 | // EP2 Rx SIE Interface 244 | wire ep2_rx_space_w; 245 | wire ep2_rx_valid_w; 246 | wire ep2_rx_setup_w; 247 | 248 | // EP2 Tx SIE Interface 249 | wire ep2_tx_ready_w; 250 | wire ep2_tx_data_valid_w; 251 | wire ep2_tx_data_strb_w; 252 | wire [7:0] ep2_tx_data_w; 253 | wire ep2_tx_data_last_w; 254 | wire ep2_tx_data_accept_w; 255 | wire ep2_tx_stall_w; 256 | // EP3 Rx SIE Interface 257 | wire ep3_rx_space_w; 258 | wire ep3_rx_valid_w; 259 | wire ep3_rx_setup_w; 260 | 261 | // EP3 Tx SIE Interface 262 | wire ep3_tx_ready_w; 263 | wire ep3_tx_data_valid_w; 264 | wire ep3_tx_data_strb_w; 265 | wire [7:0] ep3_tx_data_w; 266 | wire ep3_tx_data_last_w; 267 | wire ep3_tx_data_accept_w; 268 | wire ep3_tx_stall_w; 269 | 270 | wire utmi_chirp_en_w; 271 | wire usb_hs_w; 272 | 273 | //----------------------------------------------------------------- 274 | // Transceiver Control (high speed) 275 | //----------------------------------------------------------------- 276 | generate 277 | if (USB_SPEED_HS == "True") 278 | begin 279 | 280 | localparam STATE_W = 3; 281 | localparam STATE_IDLE = 3'd0; 282 | localparam STATE_WAIT_RST = 3'd1; 283 | localparam STATE_SEND_CHIRP_K = 3'd2; 284 | localparam STATE_WAIT_CHIRP_JK = 3'd3; 285 | localparam STATE_FULLSPEED = 3'd4; 286 | localparam STATE_HIGHSPEED = 3'd5; 287 | reg [STATE_W-1:0] state_q; 288 | reg [STATE_W-1:0] next_state_r; 289 | 290 | // 60MHz clock rate 291 | `define USB_RST_W 20 292 | reg [`USB_RST_W-1:0] usb_rst_time_q; 293 | reg [7:0] chirp_count_q; 294 | reg [1:0] last_linestate_q; 295 | 296 | localparam DETACH_TIME = 20'd60000; // 1ms -> T0 297 | localparam ATTACH_FS_TIME = 20'd180000; // T0 + 3ms = T1 298 | localparam CHIRPK_TIME = 20'd246000; // T1 + ~1ms 299 | localparam HS_RESET_TIME = 20'd600000; // T0 + 10ms = T9 300 | localparam HS_CHIRP_COUNT = 8'd5; 301 | 302 | reg [ 1:0] utmi_op_mode_r; 303 | reg [ 1:0] utmi_xcvrselect_r; 304 | reg utmi_termselect_r; 305 | reg utmi_dppulldown_r; 306 | reg utmi_dmpulldown_r; 307 | 308 | always @ * 309 | begin 310 | next_state_r = state_q; 311 | 312 | // Default - disconnect 313 | utmi_op_mode_r = 2'd1; 314 | utmi_xcvrselect_r = 2'd0; 315 | utmi_termselect_r = 1'b0; 316 | utmi_dppulldown_r = 1'b0; 317 | utmi_dmpulldown_r = 1'b0; 318 | 319 | case (state_q) 320 | STATE_IDLE: 321 | begin 322 | // Detached 323 | if (enable_i && usb_rst_time_q >= DETACH_TIME) 324 | next_state_r = STATE_WAIT_RST; 325 | end 326 | STATE_WAIT_RST: 327 | begin 328 | // Assert FS mode, check for SE0 (T0) 329 | utmi_op_mode_r = 2'd0; 330 | utmi_xcvrselect_r = 2'd1; 331 | utmi_termselect_r = 1'b1; 332 | utmi_dppulldown_r = 1'b0; 333 | utmi_dmpulldown_r = 1'b0; 334 | 335 | // Wait for SE0 (T1), send device chirp K 336 | if (usb_rst_time_q >= ATTACH_FS_TIME) 337 | next_state_r = STATE_SEND_CHIRP_K; 338 | end 339 | STATE_SEND_CHIRP_K: 340 | begin 341 | // Send chirp K 342 | utmi_op_mode_r = 2'd2; 343 | utmi_xcvrselect_r = 2'd0; 344 | utmi_termselect_r = 1'b1; 345 | utmi_dppulldown_r = 1'b0; 346 | utmi_dmpulldown_r = 1'b0; 347 | 348 | // End of device chirp K (T2) 349 | if (usb_rst_time_q >= CHIRPK_TIME) 350 | next_state_r = STATE_WAIT_CHIRP_JK; 351 | end 352 | STATE_WAIT_CHIRP_JK: 353 | begin 354 | // Stop sending chirp K and wait for downstream port chirps 355 | utmi_op_mode_r = 2'd2; 356 | utmi_xcvrselect_r = 2'd0; 357 | utmi_termselect_r = 1'b1; 358 | utmi_dppulldown_r = 1'b0; 359 | utmi_dmpulldown_r = 1'b0; 360 | 361 | // Required number of chirps detected, move to HS mode (T7) 362 | if (chirp_count_q >= HS_CHIRP_COUNT) 363 | next_state_r = STATE_HIGHSPEED; 364 | // Time out waiting for chirps, fallback to FS mode 365 | else if (usb_rst_time_q >= HS_RESET_TIME) 366 | next_state_r = STATE_FULLSPEED; 367 | end 368 | STATE_FULLSPEED: 369 | begin 370 | utmi_op_mode_r = 2'd0; 371 | utmi_xcvrselect_r = 2'd1; 372 | utmi_termselect_r = 1'b1; 373 | utmi_dppulldown_r = 1'b0; 374 | utmi_dmpulldown_r = 1'b0; 375 | 376 | // USB reset detected... 377 | if (usb_rst_time_q >= HS_RESET_TIME && usb_reset_w) 378 | next_state_r = STATE_WAIT_RST; 379 | end 380 | STATE_HIGHSPEED: 381 | begin 382 | // Enter HS mode 383 | utmi_op_mode_r = 2'd0; 384 | utmi_xcvrselect_r = 2'd0; 385 | utmi_termselect_r = 1'b0; 386 | utmi_dppulldown_r = 1'b0; 387 | utmi_dmpulldown_r = 1'b0; 388 | 389 | // Long SE0 - could be reset or suspend 390 | // TODO: Should revert to FS mode and check... 391 | if (usb_rst_time_q >= HS_RESET_TIME && usb_reset_w) 392 | next_state_r = STATE_WAIT_RST; 393 | end 394 | default: 395 | ; 396 | endcase 397 | end 398 | 399 | // Update state 400 | always @ (posedge clk_i or posedge rst_i) 401 | if (rst_i) 402 | state_q <= STATE_IDLE; 403 | else 404 | state_q <= next_state_r; 405 | 406 | // Time since T0 (start of HS reset) 407 | always @ (posedge clk_i or posedge rst_i) 408 | if (rst_i) 409 | usb_rst_time_q <= `USB_RST_W'b0; 410 | // Entering wait for reset state 411 | else if (next_state_r == STATE_WAIT_RST && state_q != STATE_WAIT_RST) 412 | usb_rst_time_q <= `USB_RST_W'b0; 413 | // Waiting for reset, reset count on line state toggle 414 | else if (state_q == STATE_WAIT_RST && (utmi_linestate_i != 2'b00)) 415 | usb_rst_time_q <= `USB_RST_W'b0; 416 | else if (usb_rst_time_q != {(`USB_RST_W){1'b1}}) 417 | usb_rst_time_q <= usb_rst_time_q + `USB_RST_W'd1; 418 | 419 | always @ (posedge clk_i or posedge rst_i) 420 | if (rst_i) 421 | last_linestate_q <= 2'b0; 422 | else 423 | last_linestate_q <= utmi_linestate_i; 424 | 425 | // Chirp counter 426 | always @ (posedge clk_i or posedge rst_i) 427 | if (rst_i) 428 | chirp_count_q <= 8'b0; 429 | else if (state_q == STATE_SEND_CHIRP_K) 430 | chirp_count_q <= 8'b0; 431 | else if (state_q == STATE_WAIT_CHIRP_JK && (last_linestate_q != utmi_linestate_i) && chirp_count_q != 8'hFF) 432 | chirp_count_q <= chirp_count_q + 8'd1; 433 | 434 | assign utmi_op_mode_o = utmi_op_mode_r; 435 | assign utmi_xcvrselect_o = utmi_xcvrselect_r; 436 | assign utmi_termselect_o = utmi_termselect_r; 437 | assign utmi_dppulldown_o = utmi_dppulldown_r; 438 | assign utmi_dmpulldown_o = utmi_dmpulldown_r; 439 | 440 | assign utmi_chirp_en_w = (state_q == STATE_SEND_CHIRP_K); 441 | assign usb_hs_w = (state_q == STATE_HIGHSPEED); 442 | 443 | end 444 | else 445 | begin 446 | //----------------------------------------------------------------- 447 | // Transceiver Control 448 | //----------------------------------------------------------------- 449 | reg [ 1:0] utmi_op_mode_r; 450 | reg [ 1:0] utmi_xcvrselect_r; 451 | reg utmi_termselect_r; 452 | reg utmi_dppulldown_r; 453 | reg utmi_dmpulldown_r; 454 | 455 | always @ * 456 | begin 457 | if (enable_i) 458 | begin 459 | utmi_op_mode_r = 2'd0; 460 | utmi_xcvrselect_r = 2'd1; 461 | utmi_termselect_r = 1'b1; 462 | utmi_dppulldown_r = 1'b0; 463 | utmi_dmpulldown_r = 1'b0; 464 | end 465 | else 466 | begin 467 | utmi_op_mode_r = 2'd1; 468 | utmi_xcvrselect_r = 2'd0; 469 | utmi_termselect_r = 1'b0; 470 | utmi_dppulldown_r = 1'b0; 471 | utmi_dmpulldown_r = 1'b0; 472 | end 473 | end 474 | 475 | assign utmi_op_mode_o = utmi_op_mode_r; 476 | assign utmi_xcvrselect_o = utmi_xcvrselect_r; 477 | assign utmi_termselect_o = utmi_termselect_r; 478 | assign utmi_dppulldown_o = utmi_dppulldown_r; 479 | assign utmi_dmpulldown_o = utmi_dmpulldown_r; 480 | 481 | assign utmi_chirp_en_w = 1'b0; 482 | assign usb_hs_w = 1'b0; 483 | 484 | end 485 | endgenerate 486 | 487 | //----------------------------------------------------------------- 488 | // Core 489 | //----------------------------------------------------------------- 490 | usbf_device_core 491 | u_core 492 | ( 493 | .clk_i(clk_i), 494 | .rst_i(rst_i), 495 | 496 | .intr_o(), 497 | 498 | // UTMI interface 499 | .utmi_data_o(utmi_data_out_o), 500 | .utmi_data_i(utmi_data_in_i), 501 | .utmi_txvalid_o(utmi_txvalid_o), 502 | .utmi_txready_i(utmi_txready_i), 503 | .utmi_rxvalid_i(utmi_rxvalid_i), 504 | .utmi_rxactive_i(utmi_rxactive_i), 505 | .utmi_rxerror_i(utmi_rxerror_i), 506 | .utmi_linestate_i(utmi_linestate_i), 507 | 508 | .reg_chirp_en_i(utmi_chirp_en_w), 509 | .reg_int_en_sof_i(1'b0), 510 | 511 | .reg_dev_addr_i(device_addr_q), 512 | 513 | // Rx SIE Interface (shared) 514 | .rx_strb_o(rx_strb_w), 515 | .rx_data_o(rx_data_w), 516 | .rx_last_o(rx_last_w), 517 | .rx_crc_err_o(rx_crc_err_w), 518 | 519 | // EP0 Config 520 | .ep0_iso_i(1'b0), 521 | .ep0_stall_i(ep0_tx_stall_w), 522 | .ep0_cfg_int_rx_i(1'b0), 523 | .ep0_cfg_int_tx_i(1'b0), 524 | 525 | // EP0 Rx SIE Interface 526 | .ep0_rx_setup_o(ep0_rx_setup_w), 527 | .ep0_rx_valid_o(ep0_rx_valid_w), 528 | .ep0_rx_space_i(ep0_rx_space_w), 529 | 530 | // EP0 Tx SIE Interface 531 | .ep0_tx_ready_i(ep0_tx_ready_w), 532 | .ep0_tx_data_valid_i(ep0_tx_data_valid_w), 533 | .ep0_tx_data_strb_i(ep0_tx_data_strb_w), 534 | .ep0_tx_data_i(ep0_tx_data_w), 535 | .ep0_tx_data_last_i(ep0_tx_data_last_w), 536 | .ep0_tx_data_accept_o(ep0_tx_data_accept_w), 537 | 538 | // EP1 Config 539 | .ep1_iso_i(1'b0), 540 | .ep1_stall_i(ep1_tx_stall_w), 541 | .ep1_cfg_int_rx_i(1'b0), 542 | .ep1_cfg_int_tx_i(1'b0), 543 | 544 | // EP1 Rx SIE Interface 545 | .ep1_rx_setup_o(ep1_rx_setup_w), 546 | .ep1_rx_valid_o(ep1_rx_valid_w), 547 | .ep1_rx_space_i(ep1_rx_space_w), 548 | 549 | // EP1 Tx SIE Interface 550 | .ep1_tx_ready_i(ep1_tx_ready_w), 551 | .ep1_tx_data_valid_i(ep1_tx_data_valid_w), 552 | .ep1_tx_data_strb_i(ep1_tx_data_strb_w), 553 | .ep1_tx_data_i(ep1_tx_data_w), 554 | .ep1_tx_data_last_i(ep1_tx_data_last_w), 555 | .ep1_tx_data_accept_o(ep1_tx_data_accept_w), 556 | 557 | // EP2 Config 558 | .ep2_iso_i(1'b0), 559 | .ep2_stall_i(ep2_tx_stall_w), 560 | .ep2_cfg_int_rx_i(1'b0), 561 | .ep2_cfg_int_tx_i(1'b0), 562 | 563 | // EP2 Rx SIE Interface 564 | .ep2_rx_setup_o(ep2_rx_setup_w), 565 | .ep2_rx_valid_o(ep2_rx_valid_w), 566 | .ep2_rx_space_i(ep2_rx_space_w), 567 | 568 | // EP2 Tx SIE Interface 569 | .ep2_tx_ready_i(ep2_tx_ready_w), 570 | .ep2_tx_data_valid_i(ep2_tx_data_valid_w), 571 | .ep2_tx_data_strb_i(ep2_tx_data_strb_w), 572 | .ep2_tx_data_i(ep2_tx_data_w), 573 | .ep2_tx_data_last_i(ep2_tx_data_last_w), 574 | .ep2_tx_data_accept_o(ep2_tx_data_accept_w), 575 | 576 | // EP3 Config 577 | .ep3_iso_i(1'b0), 578 | .ep3_stall_i(ep3_tx_stall_w), 579 | .ep3_cfg_int_rx_i(1'b0), 580 | .ep3_cfg_int_tx_i(1'b0), 581 | 582 | // EP3 Rx SIE Interface 583 | .ep3_rx_setup_o(ep3_rx_setup_w), 584 | .ep3_rx_valid_o(ep3_rx_valid_w), 585 | .ep3_rx_space_i(ep3_rx_space_w), 586 | 587 | // EP3 Tx SIE Interface 588 | .ep3_tx_ready_i(ep3_tx_ready_w), 589 | .ep3_tx_data_valid_i(ep3_tx_data_valid_w), 590 | .ep3_tx_data_strb_i(ep3_tx_data_strb_w), 591 | .ep3_tx_data_i(ep3_tx_data_w), 592 | .ep3_tx_data_last_i(ep3_tx_data_last_w), 593 | .ep3_tx_data_accept_o(ep3_tx_data_accept_w), 594 | 595 | // Status 596 | .reg_sts_rst_clr_i(1'b1), 597 | .reg_sts_rst_o(usb_reset_w), 598 | .reg_sts_frame_num_o() 599 | ); 600 | 601 | assign ep0_rx_space_w = 1'b1; 602 | 603 | //----------------------------------------------------------------- 604 | // USB: Setup packet capture (limited to 8 bytes for USB-FS) 605 | //----------------------------------------------------------------- 606 | reg [7:0] setup_packet_q[0:7]; 607 | reg [2:0] setup_wr_idx_q; 608 | reg setup_frame_q; 609 | reg setup_valid_q; 610 | reg setup_data_q; 611 | reg status_ready_q; // STATUS response received 612 | 613 | always @ (posedge clk_i or posedge rst_i) 614 | if (rst_i) 615 | begin 616 | setup_packet_q[0] <= 8'b0; 617 | setup_packet_q[1] <= 8'b0; 618 | setup_packet_q[2] <= 8'b0; 619 | setup_packet_q[3] <= 8'b0; 620 | setup_packet_q[4] <= 8'b0; 621 | setup_packet_q[5] <= 8'b0; 622 | setup_packet_q[6] <= 8'b0; 623 | setup_packet_q[7] <= 8'b0; 624 | setup_wr_idx_q <= 3'b0; 625 | setup_valid_q <= 1'b0; 626 | setup_frame_q <= 1'b0; 627 | setup_data_q <= 1'b0; 628 | status_ready_q <= 1'b0; 629 | end 630 | // SETUP token received 631 | else if (ep0_rx_setup_w) 632 | begin 633 | setup_packet_q[0] <= 8'b0; 634 | setup_packet_q[1] <= 8'b0; 635 | setup_packet_q[2] <= 8'b0; 636 | setup_packet_q[3] <= 8'b0; 637 | setup_packet_q[4] <= 8'b0; 638 | setup_packet_q[5] <= 8'b0; 639 | setup_packet_q[6] <= 8'b0; 640 | setup_packet_q[7] <= 8'b0; 641 | setup_wr_idx_q <= 3'b0; 642 | setup_valid_q <= 1'b0; 643 | setup_frame_q <= 1'b1; 644 | setup_data_q <= 1'b0; 645 | status_ready_q <= 1'b0; 646 | end 647 | // Valid DATA for setup frame 648 | else if (ep0_rx_valid_w && rx_strb_w) 649 | begin 650 | setup_packet_q[setup_wr_idx_q] <= rx_data_w; 651 | setup_wr_idx_q <= setup_wr_idx_q + 3'd1; 652 | setup_valid_q <= setup_frame_q && rx_last_w; 653 | setup_data_q <= !setup_frame_q && rx_last_w; 654 | if (rx_last_w) 655 | setup_frame_q <= 1'b0; 656 | end 657 | // Detect STATUS stage (ACK for SETUP GET requests) 658 | // TODO: Not quite correct .... 659 | else if (ep0_rx_valid_w && !rx_strb_w && rx_last_w) 660 | begin 661 | setup_valid_q <= 1'b0; 662 | status_ready_q <= 1'b1; 663 | end 664 | else 665 | setup_valid_q <= 1'b0; 666 | 667 | //----------------------------------------------------------------- 668 | // SETUP request decode 669 | //----------------------------------------------------------------- 670 | wire [7:0] bmRequestType_w = setup_packet_q[0]; 671 | wire [7:0] bRequest_w = setup_packet_q[1]; 672 | wire [15:0] wValue_w = {setup_packet_q[3], setup_packet_q[2]}; 673 | wire [15:0] wIndex_w = {setup_packet_q[5], setup_packet_q[4]}; 674 | wire [15:0] wLength = {setup_packet_q[7], setup_packet_q[6]}; 675 | 676 | wire setup_get_w = setup_valid_q && (bmRequestType_w[`ENDPOINT_DIR_R] == `ENDPOINT_DIR_IN); 677 | wire setup_set_w = setup_valid_q && (bmRequestType_w[`ENDPOINT_DIR_R] == `ENDPOINT_DIR_OUT); 678 | wire setup_no_data_w = setup_set_w && (wLength == 16'b0); 679 | 680 | // For REQ_GET_DESCRIPTOR 681 | wire [7:0] bDescriptorType_w = setup_packet_q[3]; 682 | wire [7:0] bDescriptorIndex_w = setup_packet_q[2]; 683 | 684 | //----------------------------------------------------------------- 685 | // Process setup request 686 | //----------------------------------------------------------------- 687 | reg ctrl_stall_r; // Send STALL 688 | reg ctrl_ack_r; // Send STATUS (ZLP) 689 | reg [15:0] ctrl_get_len_r; 690 | 691 | reg [7:0] desc_addr_r; 692 | 693 | reg addressed_q; 694 | reg addressed_r; 695 | reg [6:0] device_addr_r; 696 | 697 | reg configured_q; 698 | reg configured_r; 699 | 700 | reg set_with_data_q; 701 | reg set_with_data_r; 702 | wire data_status_zlp_w; 703 | 704 | always @ * 705 | begin 706 | ctrl_stall_r = 1'b0; 707 | ctrl_get_len_r = 16'b0; 708 | ctrl_ack_r = 1'b0; 709 | desc_addr_r = 8'b0; 710 | device_addr_r = device_addr_q; 711 | addressed_r = addressed_q; 712 | configured_r = configured_q; 713 | set_with_data_r = set_with_data_q; 714 | 715 | if (setup_valid_q) 716 | begin 717 | set_with_data_r = 1'b0; 718 | 719 | case (bmRequestType_w & `USB_REQUEST_TYPE_MASK) 720 | `USB_STANDARD_REQUEST: 721 | begin 722 | case (bRequest_w) 723 | `REQ_GET_STATUS: 724 | begin 725 | $display("GET_STATUS"); 726 | end 727 | `REQ_CLEAR_FEATURE: 728 | begin 729 | $display("CLEAR_FEATURE"); 730 | ctrl_ack_r = setup_set_w && setup_no_data_w; 731 | end 732 | `REQ_SET_FEATURE: 733 | begin 734 | $display("SET_FEATURE"); 735 | ctrl_ack_r = setup_set_w && setup_no_data_w; 736 | end 737 | `REQ_SET_ADDRESS: 738 | begin 739 | $display("SET_ADDRESS: Set device address %d", wValue_w[6:0]); 740 | ctrl_ack_r = setup_set_w && setup_no_data_w; 741 | device_addr_r = wValue_w[6:0]; 742 | addressed_r = 1'b1; 743 | end 744 | `REQ_GET_DESCRIPTOR: 745 | begin 746 | $display("GET_DESCRIPTOR: Type %d", bDescriptorType_w); 747 | 748 | case (bDescriptorType_w) 749 | `DESC_DEVICE: 750 | begin 751 | desc_addr_r = `ROM_DESC_DEVICE_ADDR; 752 | ctrl_get_len_r = `ROM_DESC_DEVICE_SIZE; 753 | end 754 | `DESC_CONFIGURATION: 755 | begin 756 | desc_addr_r = `ROM_DESC_CONF_ADDR; 757 | ctrl_get_len_r = `ROM_DESC_CONF_SIZE; 758 | end 759 | `DESC_STRING: 760 | begin 761 | case (bDescriptorIndex_w) 762 | `UNICODE_LANGUAGE_STR_ID: 763 | begin 764 | desc_addr_r = `ROM_DESC_STR_LANG_ADDR; 765 | ctrl_get_len_r = `ROM_DESC_STR_LANG_SIZE; 766 | end 767 | `MANUFACTURER_STR_ID: 768 | begin 769 | desc_addr_r = `ROM_DESC_STR_MAN_ADDR; 770 | ctrl_get_len_r = `ROM_DESC_STR_MAN_SIZE; 771 | end 772 | `PRODUCT_NAME_STR_ID: 773 | begin 774 | desc_addr_r = `ROM_DESC_STR_PROD_ADDR; 775 | ctrl_get_len_r = `ROM_DESC_STR_PROD_SIZE; 776 | end 777 | `SERIAL_NUM_STR_ID: 778 | begin 779 | desc_addr_r = `ROM_DESC_STR_SERIAL_ADDR; 780 | ctrl_get_len_r = `ROM_DESC_STR_SERIAL_SIZE; 781 | end 782 | default: 783 | ; 784 | endcase 785 | end 786 | default: 787 | ; 788 | endcase 789 | end 790 | `REQ_GET_CONFIGURATION: 791 | begin 792 | $display("GET_CONF"); 793 | end 794 | `REQ_SET_CONFIGURATION: 795 | begin 796 | $display("SET_CONF: Configuration %x", wValue_w); 797 | 798 | if (wValue_w == 16'd0) 799 | begin 800 | configured_r = 1'b0; 801 | ctrl_ack_r = setup_set_w && setup_no_data_w; 802 | end 803 | // Only support one configuration for now 804 | else if (wValue_w == 16'd1) 805 | begin 806 | configured_r = 1'b1; 807 | ctrl_ack_r = setup_set_w && setup_no_data_w; 808 | end 809 | else 810 | ctrl_stall_r = 1'b1; 811 | end 812 | `REQ_GET_INTERFACE: 813 | begin 814 | $display("GET_INTERFACE"); 815 | ctrl_stall_r = 1'b1; 816 | end 817 | `REQ_SET_INTERFACE: 818 | begin 819 | $display("SET_INTERFACE: %x %x", wValue_w, wIndex_w); 820 | if (wValue_w == 16'd0 && wIndex_w == 16'd0) 821 | ctrl_ack_r = setup_set_w && setup_no_data_w; 822 | else 823 | ctrl_stall_r = 1'b1; 824 | end 825 | default: 826 | begin 827 | ctrl_stall_r = 1'b1; 828 | end 829 | endcase 830 | end 831 | `USB_VENDOR_REQUEST: 832 | begin 833 | // None supported 834 | ctrl_stall_r = 1'b1; 835 | end 836 | `USB_CLASS_REQUEST: 837 | begin 838 | case (bRequest_w) 839 | `CDC_GET_LINE_CODING: 840 | begin 841 | $display("CDC_GET_LINE_CODING"); 842 | desc_addr_r = `ROM_CDC_LINE_CODING_ADDR; 843 | ctrl_get_len_r = `ROM_CDC_LINE_CODING_SIZE; 844 | end 845 | default: 846 | begin 847 | ctrl_ack_r = setup_set_w && setup_no_data_w; 848 | set_with_data_r = setup_set_w && !setup_no_data_w; 849 | end 850 | endcase 851 | end 852 | default: 853 | begin 854 | ctrl_stall_r = 1'b1; 855 | end 856 | endcase 857 | end 858 | else if (data_status_zlp_w) 859 | set_with_data_r = 1'b0; 860 | end 861 | 862 | always @ (posedge clk_i or posedge rst_i) 863 | if (rst_i) 864 | begin 865 | device_addr_q <= 7'b0; 866 | addressed_q <= 1'b0; 867 | configured_q <= 1'b0; 868 | set_with_data_q <= 1'b0; 869 | end 870 | else if (usb_reset_w) 871 | begin 872 | device_addr_q <= 7'b0; 873 | addressed_q <= 1'b0; 874 | configured_q <= 1'b0; 875 | set_with_data_q <= 1'b0; 876 | end 877 | else 878 | begin 879 | device_addr_q <= device_addr_r; 880 | addressed_q <= addressed_r; 881 | configured_q <= configured_r; 882 | set_with_data_q <= set_with_data_r; 883 | end 884 | 885 | //----------------------------------------------------------------- 886 | // SETUP response 887 | //----------------------------------------------------------------- 888 | reg ctrl_sending_q; 889 | reg [15:0] ctrl_send_idx_q; 890 | reg [15:0] ctrl_send_len_q; 891 | wire ctrl_send_zlp_w = ctrl_sending_q && (ctrl_send_len_q != wLength); 892 | 893 | reg ctrl_sending_r; 894 | reg [15:0] ctrl_send_idx_r; 895 | reg [15:0] ctrl_send_len_r; 896 | 897 | reg ctrl_txvalid_q; 898 | reg [7:0] ctrl_txdata_q; 899 | reg ctrl_txstrb_q; 900 | reg ctrl_txlast_q; 901 | reg ctrl_txstall_q; 902 | 903 | reg ctrl_txvalid_r; 904 | reg [7:0] ctrl_txdata_r; 905 | reg ctrl_txstrb_r; 906 | reg ctrl_txlast_r; 907 | reg ctrl_txstall_r; 908 | 909 | wire ctrl_send_accept_w = ep0_tx_data_accept_w || !ep0_tx_data_valid_w; 910 | 911 | reg [7:0] desc_addr_q; 912 | wire[7:0] desc_data_w; 913 | 914 | always @ * 915 | begin 916 | ctrl_sending_r = ctrl_sending_q; 917 | ctrl_send_idx_r = ctrl_send_idx_q; 918 | ctrl_send_len_r = ctrl_send_len_q; 919 | 920 | ctrl_txvalid_r = ctrl_txvalid_q; 921 | ctrl_txdata_r = ctrl_txdata_q; 922 | ctrl_txstrb_r = ctrl_txstrb_q; 923 | ctrl_txlast_r = ctrl_txlast_q; 924 | ctrl_txstall_r = ctrl_txstall_q; 925 | 926 | // New SETUP request 927 | if (setup_valid_q) 928 | begin 929 | // Send STALL 930 | if (ctrl_stall_r) 931 | begin 932 | ctrl_txvalid_r = 1'b1; 933 | ctrl_txstrb_r = 1'b0; 934 | ctrl_txlast_r = 1'b1; 935 | ctrl_txstall_r = 1'b1; 936 | end 937 | // Send STATUS response (ZLP) 938 | else if (ctrl_ack_r) 939 | begin 940 | ctrl_txvalid_r = 1'b1; 941 | ctrl_txstrb_r = 1'b0; 942 | ctrl_txlast_r = 1'b1; 943 | ctrl_txstall_r = 1'b0; 944 | end 945 | else 946 | begin 947 | ctrl_sending_r = setup_get_w && !ctrl_stall_r; 948 | ctrl_send_idx_r = 16'b0; 949 | ctrl_send_len_r = ctrl_get_len_r; 950 | ctrl_txstall_r = 1'b0; 951 | end 952 | end 953 | // Abort control send when STATUS received 954 | else if (status_ready_q) 955 | begin 956 | ctrl_sending_r = 1'b0; 957 | ctrl_send_idx_r = 16'b0; 958 | ctrl_send_len_r = 16'b0; 959 | 960 | ctrl_txvalid_r = 1'b0; 961 | end 962 | // Send STATUS response (ZLP) 963 | else if (set_with_data_q && setup_data_q) 964 | begin 965 | ctrl_txvalid_r = 1'b1; 966 | ctrl_txstrb_r = 1'b0; 967 | ctrl_txlast_r = 1'b1; 968 | ctrl_txstall_r = 1'b0; 969 | end 970 | else if (ctrl_sending_r && ctrl_send_accept_w) 971 | begin 972 | // TODO: Send ZLP on exact multiple lengths... 973 | ctrl_txvalid_r = 1'b1; 974 | ctrl_txdata_r = desc_data_w; 975 | ctrl_txstrb_r = 1'b1; 976 | ctrl_txlast_r = usb_hs_w ? (ctrl_send_idx_r[5:0] == 6'b111111) : (ctrl_send_idx_r[2:0] == 3'b111); 977 | 978 | // Increment send index 979 | ctrl_send_idx_r = ctrl_send_idx_r + 16'd1; 980 | 981 | // TODO: Detect need for ZLP 982 | if (ctrl_send_idx_r == wLength) 983 | begin 984 | ctrl_sending_r = 1'b0; 985 | ctrl_txlast_r = 1'b1; 986 | end 987 | end 988 | else if (ctrl_send_accept_w) 989 | ctrl_txvalid_r = 1'b0; 990 | end 991 | 992 | assign data_status_zlp_w = set_with_data_q && setup_data_q && ctrl_send_accept_w; 993 | 994 | always @ (posedge clk_i or posedge rst_i) 995 | if (rst_i) 996 | begin 997 | ctrl_sending_q <= 1'b0; 998 | ctrl_send_idx_q <= 16'b0; 999 | ctrl_send_len_q <= 16'b0; 1000 | ctrl_txvalid_q <= 1'b0; 1001 | ctrl_txdata_q <= 8'b0; 1002 | ctrl_txstrb_q <= 1'b0; 1003 | ctrl_txlast_q <= 1'b0; 1004 | ctrl_txstall_q <= 1'b0; 1005 | desc_addr_q <= 8'b0; 1006 | end 1007 | else if (usb_reset_w) 1008 | begin 1009 | ctrl_sending_q <= 1'b0; 1010 | ctrl_send_idx_q <= 16'b0; 1011 | ctrl_send_len_q <= 16'b0; 1012 | ctrl_txvalid_q <= 1'b0; 1013 | ctrl_txdata_q <= 8'b0; 1014 | ctrl_txstrb_q <= 1'b0; 1015 | ctrl_txlast_q <= 1'b0; 1016 | ctrl_txstall_q <= 1'b0; 1017 | desc_addr_q <= 8'b0; 1018 | end 1019 | else 1020 | begin 1021 | ctrl_sending_q <= ctrl_sending_r; 1022 | ctrl_send_idx_q <= ctrl_send_idx_r; 1023 | ctrl_send_len_q <= ctrl_send_len_r; 1024 | ctrl_txvalid_q <= ctrl_txvalid_r; 1025 | ctrl_txdata_q <= ctrl_txdata_r; 1026 | ctrl_txstrb_q <= ctrl_txstrb_r; 1027 | ctrl_txlast_q <= ctrl_txlast_r; 1028 | ctrl_txstall_q <= ctrl_txstall_r; 1029 | 1030 | if (setup_valid_q) 1031 | desc_addr_q <= desc_addr_r; 1032 | else if (ctrl_sending_r && ctrl_send_accept_w) 1033 | desc_addr_q <= desc_addr_q + 8'd1; 1034 | end 1035 | 1036 | assign ep0_tx_ready_w = ctrl_txvalid_q; 1037 | assign ep0_tx_data_valid_w = ctrl_txvalid_q; 1038 | assign ep0_tx_data_strb_w = ctrl_txstrb_q; 1039 | assign ep0_tx_data_w = ctrl_txdata_q; 1040 | assign ep0_tx_data_last_w = ctrl_txlast_q; 1041 | assign ep0_tx_stall_w = ctrl_txstall_q; 1042 | 1043 | //----------------------------------------------------------------- 1044 | // Descriptor ROM 1045 | //----------------------------------------------------------------- 1046 | usb_desc_rom 1047 | u_rom 1048 | ( 1049 | .hs_i(usb_hs_w), 1050 | .addr_i(desc_addr_q), 1051 | .data_o(desc_data_w) 1052 | ); 1053 | 1054 | //----------------------------------------------------------------- 1055 | // Unused Endpoints 1056 | //----------------------------------------------------------------- 1057 | assign ep1_tx_ready_w = 1'b0; 1058 | assign ep1_tx_data_valid_w = 1'b0; 1059 | assign ep1_tx_data_strb_w = 1'b0; 1060 | assign ep1_tx_data_w = 8'b0; 1061 | assign ep1_tx_data_last_w = 1'b0; 1062 | assign ep1_tx_stall_w = 1'b0; 1063 | assign ep3_tx_ready_w = 1'b0; 1064 | assign ep3_tx_data_valid_w = 1'b0; 1065 | assign ep3_tx_data_strb_w = 1'b0; 1066 | assign ep3_tx_data_w = 8'b0; 1067 | assign ep3_tx_data_last_w = 1'b0; 1068 | assign ep3_tx_stall_w = 1'b0; 1069 | 1070 | assign ep2_rx_space_w = 1'b0; 1071 | assign ep3_rx_space_w = 1'b0; 1072 | 1073 | //----------------------------------------------------------------- 1074 | // Stream I/O 1075 | //----------------------------------------------------------------- 1076 | reg inport_valid_q; 1077 | reg [7:0] inport_data_q; 1078 | reg [10:0] inport_cnt_q; 1079 | 1080 | always @ (posedge clk_i or posedge rst_i) 1081 | if (rst_i) 1082 | begin 1083 | inport_valid_q <= 1'b0; 1084 | inport_data_q <= 8'b0; 1085 | end 1086 | else if (inport_accept_o) 1087 | begin 1088 | inport_valid_q <= inport_valid_i; 1089 | inport_data_q <= inport_data_i; 1090 | end 1091 | 1092 | wire [10:0] max_packet_w = usb_hs_w ? 11'd511 : 11'd63; 1093 | wire inport_last_w = !inport_valid_i || (inport_cnt_q == max_packet_w); 1094 | 1095 | always @ (posedge clk_i or posedge rst_i) 1096 | if (rst_i) 1097 | inport_cnt_q <= 11'b0; 1098 | else if (inport_last_w && ep2_tx_data_accept_w) 1099 | inport_cnt_q <= 11'b0; 1100 | else if (inport_valid_q && ep2_tx_data_accept_w) 1101 | inport_cnt_q <= inport_cnt_q + 11'd1; 1102 | 1103 | assign ep2_tx_data_valid_w = inport_valid_q; 1104 | assign ep2_tx_data_w = inport_data_q; 1105 | assign ep2_tx_ready_w = ep2_tx_data_valid_w; 1106 | assign ep2_tx_data_strb_w = ep2_tx_data_valid_w; 1107 | assign ep2_tx_data_last_w = inport_last_w; 1108 | assign inport_accept_o = !inport_valid_q | ep2_tx_data_accept_w; 1109 | 1110 | assign outport_valid_o = ep1_rx_valid_w && rx_strb_w; 1111 | assign outport_data_o = rx_data_w; 1112 | assign ep1_rx_space_w = outport_accept_i; 1113 | 1114 | 1115 | 1116 | endmodule 1117 | -------------------------------------------------------------------------------- /src_v/usb_cdc_top.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usb_cdc_top 40 | //----------------------------------------------------------------- 41 | // Params 42 | //----------------------------------------------------------------- 43 | #( 44 | parameter BAUDRATE = 1000000 45 | ) 46 | //----------------------------------------------------------------- 47 | // Ports 48 | //----------------------------------------------------------------- 49 | ( 50 | // Inputs 51 | input clk_i 52 | ,input rst_i 53 | ,input [ 7:0] ulpi_data_out_i 54 | ,input ulpi_dir_i 55 | ,input ulpi_nxt_i 56 | ,input tx_i 57 | 58 | // Outputs 59 | ,output [ 7:0] ulpi_data_in_o 60 | ,output ulpi_stp_o 61 | ,output rx_o 62 | ); 63 | 64 | wire [ 7:0] utmi_data_out_w; 65 | wire [ 7:0] usb_rx_data_w; 66 | wire usb_tx_accept_w; 67 | wire enable_w = 1'h1; 68 | wire [ 1:0] utmi_xcvrselect_w; 69 | wire utmi_termselect_w; 70 | wire utmi_rxvalid_w; 71 | wire [ 1:0] utmi_op_mode_w; 72 | wire [ 7:0] utmi_data_in_w; 73 | wire utmi_rxerror_w; 74 | wire utmi_rxactive_w; 75 | wire [ 1:0] utmi_linestate_w; 76 | wire usb_tx_valid_w; 77 | wire usb_rx_accept_w; 78 | wire utmi_dppulldown_w; 79 | wire [ 7:0] usb_tx_data_w; 80 | wire usb_rx_valid_w; 81 | wire utmi_txready_w; 82 | wire utmi_txvalid_w; 83 | wire utmi_dmpulldown_w; 84 | 85 | 86 | usb_cdc_core 87 | u_usb 88 | ( 89 | // Inputs 90 | .clk_i(clk_i) 91 | ,.rst_i(rst_i) 92 | ,.enable_i(enable_w) 93 | ,.utmi_data_in_i(utmi_data_in_w) 94 | ,.utmi_txready_i(utmi_txready_w) 95 | ,.utmi_rxvalid_i(utmi_rxvalid_w) 96 | ,.utmi_rxactive_i(utmi_rxactive_w) 97 | ,.utmi_rxerror_i(utmi_rxerror_w) 98 | ,.utmi_linestate_i(utmi_linestate_w) 99 | ,.inport_valid_i(usb_tx_valid_w) 100 | ,.inport_data_i(usb_tx_data_w) 101 | ,.outport_accept_i(usb_rx_accept_w) 102 | 103 | // Outputs 104 | ,.utmi_data_out_o(utmi_data_out_w) 105 | ,.utmi_txvalid_o(utmi_txvalid_w) 106 | ,.utmi_op_mode_o(utmi_op_mode_w) 107 | ,.utmi_xcvrselect_o(utmi_xcvrselect_w) 108 | ,.utmi_termselect_o(utmi_termselect_w) 109 | ,.utmi_dppulldown_o(utmi_dppulldown_w) 110 | ,.utmi_dmpulldown_o(utmi_dmpulldown_w) 111 | ,.inport_accept_o(usb_tx_accept_w) 112 | ,.outport_valid_o(usb_rx_valid_w) 113 | ,.outport_data_o(usb_rx_data_w) 114 | ); 115 | 116 | 117 | ulpi_wrapper 118 | u_usb_phy 119 | ( 120 | // Inputs 121 | .ulpi_clk60_i(clk_i) 122 | ,.ulpi_rst_i(rst_i) 123 | ,.ulpi_data_out_i(ulpi_data_out_i) 124 | ,.ulpi_dir_i(ulpi_dir_i) 125 | ,.ulpi_nxt_i(ulpi_nxt_i) 126 | ,.utmi_data_out_i(utmi_data_out_w) 127 | ,.utmi_txvalid_i(utmi_txvalid_w) 128 | ,.utmi_op_mode_i(utmi_op_mode_w) 129 | ,.utmi_xcvrselect_i(utmi_xcvrselect_w) 130 | ,.utmi_termselect_i(utmi_termselect_w) 131 | ,.utmi_dppulldown_i(utmi_dppulldown_w) 132 | ,.utmi_dmpulldown_i(utmi_dmpulldown_w) 133 | 134 | // Outputs 135 | ,.ulpi_data_in_o(ulpi_data_in_o) 136 | ,.ulpi_stp_o(ulpi_stp_o) 137 | ,.utmi_data_in_o(utmi_data_in_w) 138 | ,.utmi_txready_o(utmi_txready_w) 139 | ,.utmi_rxvalid_o(utmi_rxvalid_w) 140 | ,.utmi_rxactive_o(utmi_rxactive_w) 141 | ,.utmi_rxerror_o(utmi_rxerror_w) 142 | ,.utmi_linestate_o(utmi_linestate_w) 143 | ); 144 | 145 | 146 | //----------------------------------------------------------------- 147 | // Output FIFO 148 | //----------------------------------------------------------------- 149 | wire tx_valid_w; 150 | wire [7:0] tx_data_w; 151 | wire tx_accept_w; 152 | 153 | usb_cdc_fifo 154 | #( 155 | .WIDTH(8), 156 | .DEPTH(128), 157 | .ADDR_W(7) 158 | ) 159 | u_fifo_tx 160 | ( 161 | .clk_i(clk_i), 162 | .rst_i(rst_i), 163 | 164 | // In 165 | .push_i(tx_valid_w), 166 | .data_in_i(tx_data_w), 167 | .accept_o(tx_accept_w), 168 | 169 | // Out 170 | .pop_i(usb_tx_accept_w), 171 | .data_out_o(usb_tx_data_w), 172 | .valid_o(usb_tx_valid_w) 173 | ); 174 | 175 | //----------------------------------------------------------------- 176 | // Input FIFO 177 | //----------------------------------------------------------------- 178 | wire rx_valid_w; 179 | wire [7:0] rx_data_w; 180 | wire rx_accept_w; 181 | 182 | usb_cdc_fifo 183 | #( 184 | .WIDTH(8), 185 | .DEPTH(64), 186 | .ADDR_W(6) 187 | ) 188 | u_fifo_rx 189 | ( 190 | .clk_i(clk_i), 191 | .rst_i(rst_i), 192 | 193 | // In 194 | .push_i(usb_rx_valid_w), 195 | .data_in_i(usb_rx_data_w), 196 | .accept_o(usb_rx_accept_w), 197 | 198 | // Out 199 | .pop_i(rx_accept_w), 200 | .data_out_o(rx_data_w), 201 | .valid_o(rx_valid_w) 202 | ); 203 | 204 | //----------------------------------------------------------------- 205 | // Registers 206 | //----------------------------------------------------------------- 207 | 208 | // Configuration 209 | localparam STOP_BITS = 1'b0; // 0 = 1, 1 = 2 210 | localparam CLK_FREQ = 60000000; 211 | localparam BIT_DIV = (CLK_FREQ / BAUDRATE) - 1; 212 | 213 | localparam START_BIT = 4'd0; 214 | localparam STOP_BIT0 = 4'd9; 215 | localparam STOP_BIT1 = 4'd10; 216 | 217 | // Xilinx placement pragmas: 218 | //synthesis attribute IOB of txd_q is "TRUE" 219 | 220 | // TX Signals 221 | reg tx_busy_q; 222 | reg [3:0] tx_bits_q; 223 | reg [31:0] tx_count_q; 224 | reg [7:0] tx_shift_reg_q; 225 | reg txd_q; 226 | 227 | // RX Signals 228 | reg rxd_q; 229 | reg [7:0] rx_data_q; 230 | reg [3:0] rx_bits_q; 231 | reg [31:0] rx_count_q; 232 | reg [7:0] rx_shift_reg_q; 233 | reg rx_ready_q; 234 | reg rx_busy_q; 235 | 236 | reg rx_err_q; 237 | 238 | //----------------------------------------------------------------- 239 | // Re-sync RXD 240 | //----------------------------------------------------------------- 241 | reg rxd_ms_q; 242 | 243 | always @ (posedge clk_i or posedge rst_i) 244 | if (rst_i) 245 | begin 246 | rxd_ms_q <= 1'b1; 247 | rxd_q <= 1'b1; 248 | end 249 | else 250 | begin 251 | rxd_ms_q <= tx_i; 252 | rxd_q <= rxd_ms_q; 253 | end 254 | 255 | //----------------------------------------------------------------- 256 | // RX Clock Divider 257 | //----------------------------------------------------------------- 258 | wire rx_sample_w = (rx_count_q == 32'b0); 259 | 260 | always @ (posedge clk_i or posedge rst_i) 261 | if (rst_i) 262 | rx_count_q <= 32'b0; 263 | else 264 | begin 265 | // Inactive 266 | if (!rx_busy_q) 267 | rx_count_q <= {1'b0, BIT_DIV[31:1]}; 268 | // Rx bit timer 269 | else if (rx_count_q != 0) 270 | rx_count_q <= (rx_count_q - 1); 271 | // Active 272 | else if (rx_sample_w) 273 | begin 274 | // Last bit? 275 | if ((rx_bits_q == STOP_BIT0 && !STOP_BITS) || (rx_bits_q == STOP_BIT1 && STOP_BITS)) 276 | rx_count_q <= 32'b0; 277 | else 278 | rx_count_q <= BIT_DIV; 279 | end 280 | end 281 | 282 | //----------------------------------------------------------------- 283 | // RX Shift Register 284 | //----------------------------------------------------------------- 285 | always @ (posedge clk_i or posedge rst_i) 286 | if (rst_i) 287 | begin 288 | rx_shift_reg_q <= 8'h00; 289 | rx_busy_q <= 1'b0; 290 | end 291 | // Rx busy 292 | else if (rx_busy_q && rx_sample_w) 293 | begin 294 | // Last bit? 295 | if (rx_bits_q == STOP_BIT0 && !STOP_BITS) 296 | rx_busy_q <= 1'b0; 297 | else if (rx_bits_q == STOP_BIT1 && STOP_BITS) 298 | rx_busy_q <= 1'b0; 299 | else if (rx_bits_q == START_BIT) 300 | begin 301 | // Start bit should still be low as sampling mid 302 | // way through start bit, so if high, error! 303 | if (rxd_q) 304 | rx_busy_q <= 1'b0; 305 | end 306 | // Rx shift register 307 | else 308 | rx_shift_reg_q <= {rxd_q, rx_shift_reg_q[7:1]}; 309 | end 310 | // Start bit? 311 | else if (!rx_busy_q && rxd_q == 1'b0) 312 | begin 313 | rx_shift_reg_q <= 8'h00; 314 | rx_busy_q <= 1'b1; 315 | end 316 | 317 | always @ (posedge clk_i or posedge rst_i) 318 | if (rst_i) 319 | rx_bits_q <= START_BIT; 320 | else if (rx_sample_w && rx_busy_q) 321 | begin 322 | if ((rx_bits_q == STOP_BIT1 && STOP_BITS) || (rx_bits_q == STOP_BIT0 && !STOP_BITS)) 323 | rx_bits_q <= START_BIT; 324 | else 325 | rx_bits_q <= rx_bits_q + 4'd1; 326 | end 327 | else if (!rx_busy_q && (BIT_DIV == 32'b0)) 328 | rx_bits_q <= START_BIT + 4'd1; 329 | else if (!rx_busy_q) 330 | rx_bits_q <= START_BIT; 331 | 332 | //----------------------------------------------------------------- 333 | // RX Data 334 | //----------------------------------------------------------------- 335 | always @ (posedge clk_i or posedge rst_i) 336 | if (rst_i) 337 | begin 338 | rx_ready_q <= 1'b0; 339 | rx_data_q <= 8'h00; 340 | rx_err_q <= 1'b0; 341 | end 342 | else 343 | begin 344 | // If reading data, reset data state 345 | if (tx_accept_w) 346 | begin 347 | rx_ready_q <= 1'b0; 348 | rx_err_q <= 1'b0; 349 | end 350 | 351 | if (rx_busy_q && rx_sample_w) 352 | begin 353 | // Stop bit 354 | if ((rx_bits_q == STOP_BIT1 && STOP_BITS) || (rx_bits_q == STOP_BIT0 && !STOP_BITS)) 355 | begin 356 | // RXD should be still high 357 | if (rxd_q) 358 | begin 359 | rx_data_q <= rx_shift_reg_q; 360 | rx_ready_q <= 1'b1; 361 | end 362 | // Bad Stop bit - wait for a full bit period 363 | // before allowing start bit detection again 364 | else 365 | begin 366 | rx_ready_q <= 1'b0; 367 | rx_data_q <= 8'h00; 368 | rx_err_q <= 1'b1; 369 | end 370 | end 371 | // Mid start bit sample - if high then error 372 | else if (rx_bits_q == START_BIT && rxd_q) 373 | rx_err_q <= 1'b1; 374 | end 375 | end 376 | 377 | assign tx_data_w = rx_data_q; 378 | assign tx_valid_w = rx_ready_q; 379 | 380 | //----------------------------------------------------------------- 381 | // TX Clock Divider 382 | //----------------------------------------------------------------- 383 | wire tx_sample_w = (tx_count_q == 32'b0); 384 | 385 | always @ (posedge clk_i or posedge rst_i) 386 | if (rst_i) 387 | tx_count_q <= 32'b0; 388 | else 389 | begin 390 | // Idle 391 | if (!tx_busy_q) 392 | tx_count_q <= BIT_DIV; 393 | // Tx bit timer 394 | else if (tx_count_q != 0) 395 | tx_count_q <= (tx_count_q - 1); 396 | else if (tx_sample_w) 397 | tx_count_q <= BIT_DIV; 398 | end 399 | 400 | //----------------------------------------------------------------- 401 | // TX Shift Register 402 | //----------------------------------------------------------------- 403 | reg tx_complete_q; 404 | 405 | always @ (posedge clk_i or posedge rst_i) 406 | if (rst_i) 407 | begin 408 | tx_shift_reg_q <= 8'h00; 409 | tx_busy_q <= 1'b0; 410 | tx_complete_q <= 1'b0; 411 | end 412 | // Tx busy 413 | else if (tx_busy_q) 414 | begin 415 | // Shift tx data 416 | if (tx_bits_q != START_BIT && tx_sample_w) 417 | tx_shift_reg_q <= {1'b0, tx_shift_reg_q[7:1]}; 418 | 419 | // Last bit? 420 | if (tx_bits_q == STOP_BIT0 && tx_sample_w && !STOP_BITS) 421 | begin 422 | tx_busy_q <= 1'b0; 423 | tx_complete_q <= 1'b1; 424 | end 425 | else if (tx_bits_q == STOP_BIT1 && tx_sample_w && STOP_BITS) 426 | begin 427 | tx_busy_q <= 1'b0; 428 | tx_complete_q <= 1'b1; 429 | end 430 | end 431 | // Buffer data to transmit 432 | else if (rx_valid_w) 433 | begin 434 | tx_shift_reg_q <= rx_data_w; 435 | tx_busy_q <= 1'b1; 436 | tx_complete_q <= 1'b0; 437 | end 438 | else 439 | tx_complete_q <= 1'b0; 440 | 441 | assign rx_accept_w = ~tx_busy_q; 442 | 443 | always @ (posedge clk_i or posedge rst_i) 444 | if (rst_i) 445 | tx_bits_q <= 4'd0; 446 | else if (tx_sample_w && tx_busy_q) 447 | begin 448 | if ((tx_bits_q == STOP_BIT1 && STOP_BITS) || (tx_bits_q == STOP_BIT0 && !STOP_BITS)) 449 | tx_bits_q <= START_BIT; 450 | else 451 | tx_bits_q <= tx_bits_q + 4'd1; 452 | end 453 | 454 | //----------------------------------------------------------------- 455 | // UART Tx Pin 456 | //----------------------------------------------------------------- 457 | reg txd_r; 458 | 459 | always @ * 460 | begin 461 | txd_r = 1'b1; 462 | 463 | if (tx_busy_q) 464 | begin 465 | // Start bit (TXD = L) 466 | if (tx_bits_q == START_BIT) 467 | txd_r = 1'b0; 468 | // Stop bits (TXD = H) 469 | else if (tx_bits_q == STOP_BIT0 || tx_bits_q == STOP_BIT1) 470 | txd_r = 1'b1; 471 | // Data bits 472 | else 473 | txd_r = tx_shift_reg_q[0]; 474 | end 475 | end 476 | 477 | always @ (posedge clk_i or posedge rst_i) 478 | if (rst_i) 479 | txd_q <= 1'b1; 480 | else 481 | txd_q <= txd_r; 482 | 483 | assign rx_o = txd_q; 484 | 485 | 486 | endmodule 487 | 488 | module usb_cdc_fifo 489 | //----------------------------------------------------------------- 490 | // Params 491 | //----------------------------------------------------------------- 492 | #( 493 | parameter WIDTH = 8, 494 | parameter DEPTH = 4, 495 | parameter ADDR_W = 2 496 | ) 497 | //----------------------------------------------------------------- 498 | // Ports 499 | //----------------------------------------------------------------- 500 | ( 501 | // Inputs 502 | input clk_i 503 | ,input rst_i 504 | ,input [WIDTH-1:0] data_in_i 505 | ,input push_i 506 | ,input pop_i 507 | 508 | // Outputs 509 | ,output [WIDTH-1:0] data_out_o 510 | ,output accept_o 511 | ,output valid_o 512 | ); 513 | 514 | //----------------------------------------------------------------- 515 | // Local Params 516 | //----------------------------------------------------------------- 517 | localparam COUNT_W = ADDR_W + 1; 518 | 519 | //----------------------------------------------------------------- 520 | // Registers 521 | //----------------------------------------------------------------- 522 | reg [WIDTH-1:0] ram_q[DEPTH-1:0]; 523 | reg [ADDR_W-1:0] rd_ptr_q; 524 | reg [ADDR_W-1:0] wr_ptr_q; 525 | reg [COUNT_W-1:0] count_q; 526 | 527 | //----------------------------------------------------------------- 528 | // Sequential 529 | //----------------------------------------------------------------- 530 | always @ (posedge clk_i ) 531 | if (rst_i) 532 | begin 533 | count_q <= {(COUNT_W) {1'b0}}; 534 | rd_ptr_q <= {(ADDR_W) {1'b0}}; 535 | wr_ptr_q <= {(ADDR_W) {1'b0}}; 536 | end 537 | else 538 | begin 539 | // Push 540 | if (push_i & accept_o) 541 | begin 542 | ram_q[wr_ptr_q] <= data_in_i; 543 | wr_ptr_q <= wr_ptr_q + 1; 544 | end 545 | 546 | // Pop 547 | if (pop_i & valid_o) 548 | rd_ptr_q <= rd_ptr_q + 1; 549 | 550 | // Count up 551 | if ((push_i & accept_o) & ~(pop_i & valid_o)) 552 | count_q <= count_q + 1; 553 | // Count down 554 | else if (~(push_i & accept_o) & (pop_i & valid_o)) 555 | count_q <= count_q - 1; 556 | end 557 | 558 | //------------------------------------------------------------------- 559 | // Combinatorial 560 | //------------------------------------------------------------------- 561 | /* verilator lint_off WIDTH */ 562 | assign valid_o = (count_q != 0); 563 | assign accept_o = (count_q != DEPTH); 564 | /* verilator lint_on WIDTH */ 565 | 566 | assign data_out_o = ram_q[rd_ptr_q]; 567 | 568 | 569 | 570 | 571 | endmodule 572 | -------------------------------------------------------------------------------- /src_v/usb_desc_rom.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | module usb_desc_rom 39 | ( 40 | input hs_i, 41 | input [7:0] addr_i, 42 | output [7:0] data_o 43 | ); 44 | 45 | reg [7:0] desc_rom_r; 46 | 47 | always @ * 48 | begin 49 | case (addr_i) 50 | 8'd0: desc_rom_r = 8'h12; 51 | 8'd1: desc_rom_r = 8'h01; 52 | 8'd2: desc_rom_r = 8'h00; 53 | 8'd3: desc_rom_r = 8'h02; 54 | 8'd4: desc_rom_r = 8'h02; 55 | 8'd5: desc_rom_r = 8'h00; 56 | 8'd6: desc_rom_r = 8'h00; 57 | 8'd7: desc_rom_r = hs_i ? 8'h40 : 8'h08; 58 | 8'd8: desc_rom_r = 8'h50; // VID_L 59 | 8'd9: desc_rom_r = 8'h1d; // VID_H 60 | 8'd10: desc_rom_r = 8'h49; // PID_L 61 | 8'd11: desc_rom_r = 8'h61; // PID_H 62 | 8'd12: desc_rom_r = 8'h01; 63 | 8'd13: desc_rom_r = 8'h01; 64 | 8'd14: desc_rom_r = 8'h00; 65 | 8'd15: desc_rom_r = 8'h00; 66 | 8'd16: desc_rom_r = 8'h00; 67 | 8'd17: desc_rom_r = 8'h01; 68 | 8'd18: desc_rom_r = 8'h09; 69 | 8'd19: desc_rom_r = 8'h02; 70 | 8'd20: desc_rom_r = 8'h43; 71 | 8'd21: desc_rom_r = 8'h00; 72 | 8'd22: desc_rom_r = 8'h02; 73 | 8'd23: desc_rom_r = 8'h01; 74 | 8'd24: desc_rom_r = 8'h00; 75 | 8'd25: desc_rom_r = 8'h80; 76 | 8'd26: desc_rom_r = 8'h32; 77 | 8'd27: desc_rom_r = 8'h09; 78 | 8'd28: desc_rom_r = 8'h04; 79 | 8'd29: desc_rom_r = 8'h00; 80 | 8'd30: desc_rom_r = 8'h00; 81 | 8'd31: desc_rom_r = 8'h01; 82 | 8'd32: desc_rom_r = 8'h02; 83 | 8'd33: desc_rom_r = 8'h02; 84 | 8'd34: desc_rom_r = 8'h01; 85 | 8'd35: desc_rom_r = 8'h00; 86 | 8'd36: desc_rom_r = 8'h05; 87 | 8'd37: desc_rom_r = 8'h24; 88 | 8'd38: desc_rom_r = 8'h00; 89 | 8'd39: desc_rom_r = 8'h10; 90 | 8'd40: desc_rom_r = 8'h01; 91 | 8'd41: desc_rom_r = 8'h05; 92 | 8'd42: desc_rom_r = 8'h24; 93 | 8'd43: desc_rom_r = 8'h01; 94 | 8'd44: desc_rom_r = 8'h03; 95 | 8'd45: desc_rom_r = 8'h01; 96 | 8'd46: desc_rom_r = 8'h04; 97 | 8'd47: desc_rom_r = 8'h24; 98 | 8'd48: desc_rom_r = 8'h02; 99 | 8'd49: desc_rom_r = 8'h06; 100 | 8'd50: desc_rom_r = 8'h05; 101 | 8'd51: desc_rom_r = 8'h24; 102 | 8'd52: desc_rom_r = 8'h06; 103 | 8'd53: desc_rom_r = 8'h00; 104 | 8'd54: desc_rom_r = 8'h01; 105 | 8'd55: desc_rom_r = 8'h07; 106 | 8'd56: desc_rom_r = 8'h05; 107 | 8'd57: desc_rom_r = 8'h83; 108 | 8'd58: desc_rom_r = 8'h03; 109 | 8'd59: desc_rom_r = 8'h40; 110 | 8'd60: desc_rom_r = 8'h00; 111 | 8'd61: desc_rom_r = 8'h02; 112 | 8'd62: desc_rom_r = 8'h09; 113 | 8'd63: desc_rom_r = 8'h04; 114 | 8'd64: desc_rom_r = 8'h01; 115 | 8'd65: desc_rom_r = 8'h00; 116 | 8'd66: desc_rom_r = 8'h02; 117 | 8'd67: desc_rom_r = 8'h0a; 118 | 8'd68: desc_rom_r = 8'h00; 119 | 8'd69: desc_rom_r = 8'h00; 120 | 8'd70: desc_rom_r = 8'h00; 121 | 8'd71: desc_rom_r = 8'h07; 122 | 8'd72: desc_rom_r = 8'h05; 123 | 8'd73: desc_rom_r = 8'h01; 124 | 8'd74: desc_rom_r = 8'h02; 125 | 8'd75: desc_rom_r = hs_i ? 8'h00 : 8'h40; 126 | 8'd76: desc_rom_r = hs_i ? 8'h02 : 8'h00; 127 | 8'd77: desc_rom_r = 8'h00; 128 | 8'd78: desc_rom_r = 8'h07; 129 | 8'd79: desc_rom_r = 8'h05; 130 | 8'd80: desc_rom_r = 8'h82; 131 | 8'd81: desc_rom_r = 8'h02; 132 | 8'd82: desc_rom_r = hs_i ? 8'h00 : 8'h40; 133 | 8'd83: desc_rom_r = hs_i ? 8'h02 : 8'h00; 134 | 8'd84: desc_rom_r = 8'h00; 135 | 8'd85: desc_rom_r = 8'h04; 136 | 8'd86: desc_rom_r = 8'h03; 137 | 8'd87: desc_rom_r = 8'h09; 138 | 8'd88: desc_rom_r = 8'h04; 139 | 8'd89: desc_rom_r = 8'h1e; 140 | 8'd90: desc_rom_r = 8'h03; 141 | 8'd91: desc_rom_r = 8'h55; 142 | 8'd92: desc_rom_r = 8'h00; 143 | 8'd93: desc_rom_r = 8'h4c; 144 | 8'd94: desc_rom_r = 8'h00; 145 | 8'd95: desc_rom_r = 8'h54; 146 | 8'd96: desc_rom_r = 8'h00; 147 | 8'd97: desc_rom_r = 8'h52; 148 | 8'd98: desc_rom_r = 8'h00; 149 | 8'd99: desc_rom_r = 8'h41; 150 | 8'd100: desc_rom_r = 8'h00; 151 | 8'd101: desc_rom_r = 8'h2d; 152 | 8'd102: desc_rom_r = 8'h00; 153 | 8'd103: desc_rom_r = 8'h45; 154 | 8'd104: desc_rom_r = 8'h00; 155 | 8'd105: desc_rom_r = 8'h4d; 156 | 8'd106: desc_rom_r = 8'h00; 157 | 8'd107: desc_rom_r = 8'h42; 158 | 8'd108: desc_rom_r = 8'h00; 159 | 8'd109: desc_rom_r = 8'h45; 160 | 8'd110: desc_rom_r = 8'h00; 161 | 8'd111: desc_rom_r = 8'h44; 162 | 8'd112: desc_rom_r = 8'h00; 163 | 8'd113: desc_rom_r = 8'h44; 164 | 8'd114: desc_rom_r = 8'h00; 165 | 8'd115: desc_rom_r = 8'h45; 166 | 8'd116: desc_rom_r = 8'h00; 167 | 8'd117: desc_rom_r = 8'h44; 168 | 8'd118: desc_rom_r = 8'h00; 169 | 8'd119: desc_rom_r = 8'h1e; 170 | 8'd120: desc_rom_r = 8'h03; 171 | 8'd121: desc_rom_r = 8'h55; 172 | 8'd122: desc_rom_r = 8'h00; 173 | 8'd123: desc_rom_r = 8'h53; 174 | 8'd124: desc_rom_r = 8'h00; 175 | 8'd125: desc_rom_r = 8'h42; 176 | 8'd126: desc_rom_r = 8'h00; 177 | 8'd127: desc_rom_r = 8'h20; 178 | 8'd128: desc_rom_r = 8'h00; 179 | 8'd129: desc_rom_r = 8'h44; 180 | 8'd130: desc_rom_r = 8'h00; 181 | 8'd131: desc_rom_r = 8'h45; 182 | 8'd132: desc_rom_r = 8'h00; 183 | 8'd133: desc_rom_r = 8'h4d; 184 | 8'd134: desc_rom_r = 8'h00; 185 | 8'd135: desc_rom_r = 8'h4f; 186 | 8'd136: desc_rom_r = 8'h00; 187 | 8'd137: desc_rom_r = 8'h20; 188 | 8'd138: desc_rom_r = 8'h00; 189 | 8'd139: desc_rom_r = 8'h20; 190 | 8'd140: desc_rom_r = 8'h00; 191 | 8'd141: desc_rom_r = 8'h20; 192 | 8'd142: desc_rom_r = 8'h00; 193 | 8'd143: desc_rom_r = 8'h20; 194 | 8'd144: desc_rom_r = 8'h00; 195 | 8'd145: desc_rom_r = 8'h20; 196 | 8'd146: desc_rom_r = 8'h00; 197 | 8'd147: desc_rom_r = 8'h20; 198 | 8'd148: desc_rom_r = 8'h00; 199 | 8'd149: desc_rom_r = 8'h0e; 200 | 8'd150: desc_rom_r = 8'h03; 201 | 8'd151: desc_rom_r = 8'h30; 202 | 8'd152: desc_rom_r = 8'h00; 203 | 8'd153: desc_rom_r = 8'h30; 204 | 8'd154: desc_rom_r = 8'h00; 205 | 8'd155: desc_rom_r = 8'h30; 206 | 8'd156: desc_rom_r = 8'h00; 207 | 8'd157: desc_rom_r = 8'h30; 208 | 8'd158: desc_rom_r = 8'h00; 209 | 8'd159: desc_rom_r = 8'h30; 210 | 8'd160: desc_rom_r = 8'h00; 211 | 8'd161: desc_rom_r = 8'h30; 212 | 8'd162: desc_rom_r = 8'h00; 213 | 8'd163: desc_rom_r = 8'h00; 214 | 8'd164: desc_rom_r = 8'hc2; 215 | 8'd165: desc_rom_r = 8'h01; 216 | 8'd166: desc_rom_r = 8'h00; 217 | 8'd167: desc_rom_r = 8'h00; 218 | 8'd168: desc_rom_r = 8'h00; 219 | 8'd169: desc_rom_r = 8'h08; 220 | default: desc_rom_r = 8'h00; 221 | endcase 222 | end 223 | 224 | assign data_o = desc_rom_r; 225 | 226 | endmodule 227 | -------------------------------------------------------------------------------- /src_v/usbf_crc16.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usbf_crc16 40 | ( 41 | // Inputs 42 | input [ 15:0] crc_in_i 43 | ,input [ 7:0] din_i 44 | 45 | // Outputs 46 | ,output [ 15:0] crc_out_o 47 | ); 48 | 49 | 50 | 51 | //----------------------------------------------------------------- 52 | // Logic 53 | //----------------------------------------------------------------- 54 | assign crc_out_o[15] = din_i[0] ^ din_i[1] ^ din_i[2] ^ din_i[3] ^ din_i[4] ^ din_i[5] ^ din_i[6] ^ din_i[7] ^ 55 | crc_in_i[7] ^ crc_in_i[6] ^ crc_in_i[5] ^ crc_in_i[4] ^ crc_in_i[3] ^ crc_in_i[2] ^ crc_in_i[1] ^ crc_in_i[0]; 56 | assign crc_out_o[14] = din_i[0] ^ din_i[1] ^ din_i[2] ^ din_i[3] ^ din_i[4] ^ din_i[5] ^ din_i[6] ^ 57 | crc_in_i[6] ^ crc_in_i[5] ^ crc_in_i[4] ^ crc_in_i[3] ^ crc_in_i[2] ^ crc_in_i[1] ^ crc_in_i[0]; 58 | assign crc_out_o[13] = din_i[6] ^ din_i[7] ^ 59 | crc_in_i[7] ^ crc_in_i[6]; 60 | assign crc_out_o[12] = din_i[5] ^ din_i[6] ^ 61 | crc_in_i[6] ^ crc_in_i[5]; 62 | assign crc_out_o[11] = din_i[4] ^ din_i[5] ^ 63 | crc_in_i[5] ^ crc_in_i[4]; 64 | assign crc_out_o[10] = din_i[3] ^ din_i[4] ^ 65 | crc_in_i[4] ^ crc_in_i[3]; 66 | assign crc_out_o[9] = din_i[2] ^ din_i[3] ^ 67 | crc_in_i[3] ^ crc_in_i[2]; 68 | assign crc_out_o[8] = din_i[1] ^ din_i[2] ^ 69 | crc_in_i[2] ^ crc_in_i[1]; 70 | assign crc_out_o[7] = din_i[0] ^ din_i[1] ^ 71 | crc_in_i[15] ^ crc_in_i[1] ^ crc_in_i[0]; 72 | assign crc_out_o[6] = din_i[0] ^ 73 | crc_in_i[14] ^ crc_in_i[0]; 74 | assign crc_out_o[5] = crc_in_i[13]; 75 | assign crc_out_o[4] = crc_in_i[12]; 76 | assign crc_out_o[3] = crc_in_i[11]; 77 | assign crc_out_o[2] = crc_in_i[10]; 78 | assign crc_out_o[1] = crc_in_i[9]; 79 | assign crc_out_o[0] = din_i[0] ^ din_i[1] ^ din_i[2] ^ din_i[3] ^ din_i[4] ^ din_i[5] ^ din_i[6] ^ din_i[7] ^ 80 | crc_in_i[8] ^ crc_in_i[7] ^ crc_in_i[6] ^ crc_in_i[5] ^ crc_in_i[4] ^ crc_in_i[3] ^ crc_in_i[2] ^ crc_in_i[1] ^ crc_in_i[0]; 81 | 82 | 83 | endmodule 84 | -------------------------------------------------------------------------------- /src_v/usbf_defs.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | //----------------------------------------------------------------- 39 | // Definitions 40 | //----------------------------------------------------------------- 41 | 42 | // Tokens 43 | `define PID_OUT 8'hE1 44 | `define PID_IN 8'h69 45 | `define PID_SOF 8'hA5 46 | `define PID_SETUP 8'h2D 47 | 48 | // Data 49 | `define PID_DATA0 8'hC3 50 | `define PID_DATA1 8'h4B 51 | `define PID_DATA2 8'h87 52 | `define PID_MDATA 8'h0F 53 | 54 | // Handshake 55 | `define PID_ACK 8'hD2 56 | `define PID_NAK 8'h5A 57 | `define PID_STALL 8'h1E 58 | `define PID_NYET 8'h96 59 | 60 | // Special 61 | `define PID_PRE 8'h3C 62 | `define PID_ERR 8'h3C 63 | `define PID_SPLIT 8'h78 64 | `define PID_PING 8'hB4 65 | -------------------------------------------------------------------------------- /src_v/usbf_device_core.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usbf_device_core 40 | ( 41 | // Inputs 42 | input clk_i 43 | ,input rst_i 44 | ,input [ 7:0] utmi_data_i 45 | ,input utmi_txready_i 46 | ,input utmi_rxvalid_i 47 | ,input utmi_rxactive_i 48 | ,input utmi_rxerror_i 49 | ,input [ 1:0] utmi_linestate_i 50 | ,input ep0_stall_i 51 | ,input ep0_iso_i 52 | ,input ep0_cfg_int_rx_i 53 | ,input ep0_cfg_int_tx_i 54 | ,input ep0_rx_space_i 55 | ,input ep0_tx_ready_i 56 | ,input ep0_tx_data_valid_i 57 | ,input ep0_tx_data_strb_i 58 | ,input [ 7:0] ep0_tx_data_i 59 | ,input ep0_tx_data_last_i 60 | ,input ep1_stall_i 61 | ,input ep1_iso_i 62 | ,input ep1_cfg_int_rx_i 63 | ,input ep1_cfg_int_tx_i 64 | ,input ep1_rx_space_i 65 | ,input ep1_tx_ready_i 66 | ,input ep1_tx_data_valid_i 67 | ,input ep1_tx_data_strb_i 68 | ,input [ 7:0] ep1_tx_data_i 69 | ,input ep1_tx_data_last_i 70 | ,input ep2_stall_i 71 | ,input ep2_iso_i 72 | ,input ep2_cfg_int_rx_i 73 | ,input ep2_cfg_int_tx_i 74 | ,input ep2_rx_space_i 75 | ,input ep2_tx_ready_i 76 | ,input ep2_tx_data_valid_i 77 | ,input ep2_tx_data_strb_i 78 | ,input [ 7:0] ep2_tx_data_i 79 | ,input ep2_tx_data_last_i 80 | ,input ep3_stall_i 81 | ,input ep3_iso_i 82 | ,input ep3_cfg_int_rx_i 83 | ,input ep3_cfg_int_tx_i 84 | ,input ep3_rx_space_i 85 | ,input ep3_tx_ready_i 86 | ,input ep3_tx_data_valid_i 87 | ,input ep3_tx_data_strb_i 88 | ,input [ 7:0] ep3_tx_data_i 89 | ,input ep3_tx_data_last_i 90 | ,input reg_chirp_en_i 91 | ,input reg_int_en_sof_i 92 | ,input reg_sts_rst_clr_i 93 | ,input [ 6:0] reg_dev_addr_i 94 | 95 | // Outputs 96 | ,output intr_o 97 | ,output [ 7:0] utmi_data_o 98 | ,output utmi_txvalid_o 99 | ,output rx_strb_o 100 | ,output [ 7:0] rx_data_o 101 | ,output rx_last_o 102 | ,output rx_crc_err_o 103 | ,output ep0_rx_setup_o 104 | ,output ep0_rx_valid_o 105 | ,output ep0_tx_data_accept_o 106 | ,output ep1_rx_setup_o 107 | ,output ep1_rx_valid_o 108 | ,output ep1_tx_data_accept_o 109 | ,output ep2_rx_setup_o 110 | ,output ep2_rx_valid_o 111 | ,output ep2_tx_data_accept_o 112 | ,output ep3_rx_setup_o 113 | ,output ep3_rx_valid_o 114 | ,output ep3_tx_data_accept_o 115 | ,output reg_sts_rst_o 116 | ,output [ 10:0] reg_sts_frame_num_o 117 | ); 118 | 119 | 120 | 121 | //----------------------------------------------------------------- 122 | // Defines: 123 | //----------------------------------------------------------------- 124 | `include "usbf_defs.v" 125 | 126 | `define USB_RESET_CNT_W 15 127 | 128 | localparam STATE_W = 3; 129 | localparam STATE_RX_IDLE = 3'd0; 130 | localparam STATE_RX_DATA = 3'd1; 131 | localparam STATE_RX_DATA_READY = 3'd2; 132 | localparam STATE_RX_DATA_IGNORE = 3'd3; 133 | localparam STATE_TX_DATA = 3'd4; 134 | localparam STATE_TX_DATA_COMPLETE = 3'd5; 135 | localparam STATE_TX_HANDSHAKE = 3'd6; 136 | localparam STATE_TX_CHIRP = 3'd7; 137 | reg [STATE_W-1:0] state_q; 138 | 139 | //----------------------------------------------------------------- 140 | // Reset detection 141 | //----------------------------------------------------------------- 142 | reg [`USB_RESET_CNT_W-1:0] se0_cnt_q; 143 | 144 | always @ (posedge clk_i or posedge rst_i) 145 | if (rst_i) 146 | se0_cnt_q <= `USB_RESET_CNT_W'b0; 147 | else if (utmi_linestate_i == 2'b0) 148 | begin 149 | if (!se0_cnt_q[`USB_RESET_CNT_W-1]) 150 | se0_cnt_q <= se0_cnt_q + `USB_RESET_CNT_W'd1; 151 | end 152 | else 153 | se0_cnt_q <= `USB_RESET_CNT_W'b0; 154 | 155 | wire usb_rst_w = se0_cnt_q[`USB_RESET_CNT_W-1]; 156 | 157 | //----------------------------------------------------------------- 158 | // Wire / Regs 159 | //----------------------------------------------------------------- 160 | `define USB_FRAME_W 11 161 | wire [`USB_FRAME_W-1:0] frame_num_w; 162 | 163 | wire frame_valid_w; 164 | 165 | `define USB_DEV_W 7 166 | wire [`USB_DEV_W-1:0] token_dev_w; 167 | 168 | `define USB_EP_W 4 169 | wire [`USB_EP_W-1:0] token_ep_w; 170 | 171 | `define USB_PID_W 8 172 | wire [`USB_PID_W-1:0] token_pid_w; 173 | 174 | wire token_valid_w; 175 | 176 | wire rx_data_valid_w; 177 | wire rx_data_complete_w; 178 | 179 | wire rx_handshake_w; 180 | 181 | reg tx_data_valid_r; 182 | reg tx_data_strb_r; 183 | reg [7:0] tx_data_r; 184 | reg tx_data_last_r; 185 | wire tx_data_accept_w; 186 | 187 | reg tx_valid_q; 188 | reg [7:0] tx_pid_q; 189 | wire tx_accept_w; 190 | 191 | reg rx_space_q; 192 | reg rx_space_r; 193 | reg tx_ready_r; 194 | reg out_data_bit_r; 195 | reg in_data_bit_r; 196 | 197 | reg ep_stall_r; 198 | reg ep_iso_r; 199 | 200 | reg rx_enable_q; 201 | reg rx_setup_q; 202 | 203 | reg ep0_out_data_bit_q; 204 | reg ep0_in_data_bit_q; 205 | reg ep1_out_data_bit_q; 206 | reg ep1_in_data_bit_q; 207 | reg ep2_out_data_bit_q; 208 | reg ep2_in_data_bit_q; 209 | reg ep3_out_data_bit_q; 210 | reg ep3_in_data_bit_q; 211 | 212 | reg [`USB_DEV_W-1:0] current_addr_q; 213 | 214 | //----------------------------------------------------------------- 215 | // SIE - TX 216 | //----------------------------------------------------------------- 217 | usbf_sie_tx 218 | u_sie_tx 219 | ( 220 | .clk_i(clk_i), 221 | .rst_i(rst_i), 222 | 223 | .enable_i(~usb_rst_w), 224 | .chirp_i(reg_chirp_en_i), 225 | 226 | // UTMI Interface 227 | .utmi_data_o(utmi_data_o), 228 | .utmi_txvalid_o(utmi_txvalid_o), 229 | .utmi_txready_i(utmi_txready_i), 230 | 231 | // Request 232 | .tx_valid_i(tx_valid_q), 233 | .tx_pid_i(tx_pid_q), 234 | .tx_accept_o(tx_accept_w), 235 | 236 | // Data 237 | .data_valid_i(tx_data_valid_r), 238 | .data_strb_i(tx_data_strb_r), 239 | .data_i(tx_data_r), 240 | .data_last_i(tx_data_last_r), 241 | .data_accept_o(tx_data_accept_w) 242 | ); 243 | 244 | always @ * 245 | begin 246 | tx_data_valid_r = 1'b0; 247 | tx_data_strb_r = 1'b0; 248 | tx_data_r = 8'b0; 249 | tx_data_last_r = 1'b0; 250 | 251 | case (token_ep_w) 252 | 4'd0: 253 | begin 254 | tx_data_valid_r = ep0_tx_data_valid_i; 255 | tx_data_strb_r = ep0_tx_data_strb_i; 256 | tx_data_r = ep0_tx_data_i; 257 | tx_data_last_r = ep0_tx_data_last_i; 258 | end 259 | 4'd1: 260 | begin 261 | tx_data_valid_r = ep1_tx_data_valid_i; 262 | tx_data_strb_r = ep1_tx_data_strb_i; 263 | tx_data_r = ep1_tx_data_i; 264 | tx_data_last_r = ep1_tx_data_last_i; 265 | end 266 | 4'd2: 267 | begin 268 | tx_data_valid_r = ep2_tx_data_valid_i; 269 | tx_data_strb_r = ep2_tx_data_strb_i; 270 | tx_data_r = ep2_tx_data_i; 271 | tx_data_last_r = ep2_tx_data_last_i; 272 | end 273 | 4'd3: 274 | begin 275 | tx_data_valid_r = ep3_tx_data_valid_i; 276 | tx_data_strb_r = ep3_tx_data_strb_i; 277 | tx_data_r = ep3_tx_data_i; 278 | tx_data_last_r = ep3_tx_data_last_i; 279 | end 280 | default: 281 | ; 282 | endcase 283 | end 284 | 285 | assign ep0_tx_data_accept_o = tx_data_accept_w & (token_ep_w == 4'd0); 286 | assign ep1_tx_data_accept_o = tx_data_accept_w & (token_ep_w == 4'd1); 287 | assign ep2_tx_data_accept_o = tx_data_accept_w & (token_ep_w == 4'd2); 288 | assign ep3_tx_data_accept_o = tx_data_accept_w & (token_ep_w == 4'd3); 289 | 290 | always @ * 291 | begin 292 | rx_space_r = 1'b0; 293 | tx_ready_r = 1'b0; 294 | out_data_bit_r = 1'b0; 295 | in_data_bit_r = 1'b0; 296 | 297 | ep_stall_r = 1'b0; 298 | ep_iso_r = 1'b0; 299 | 300 | case (token_ep_w) 301 | 4'd0: 302 | begin 303 | rx_space_r = ep0_rx_space_i; 304 | tx_ready_r = ep0_tx_ready_i; 305 | out_data_bit_r= ep0_out_data_bit_q; 306 | in_data_bit_r = ep0_in_data_bit_q; 307 | ep_stall_r = ep0_stall_i; 308 | ep_iso_r = ep0_iso_i; 309 | end 310 | 4'd1: 311 | begin 312 | rx_space_r = ep1_rx_space_i; 313 | tx_ready_r = ep1_tx_ready_i; 314 | out_data_bit_r= ep1_out_data_bit_q; 315 | in_data_bit_r = ep1_in_data_bit_q; 316 | ep_stall_r = ep1_stall_i; 317 | ep_iso_r = ep1_iso_i; 318 | end 319 | 4'd2: 320 | begin 321 | rx_space_r = ep2_rx_space_i; 322 | tx_ready_r = ep2_tx_ready_i; 323 | out_data_bit_r= ep2_out_data_bit_q; 324 | in_data_bit_r = ep2_in_data_bit_q; 325 | ep_stall_r = ep2_stall_i; 326 | ep_iso_r = ep2_iso_i; 327 | end 328 | 4'd3: 329 | begin 330 | rx_space_r = ep3_rx_space_i; 331 | tx_ready_r = ep3_tx_ready_i; 332 | out_data_bit_r= ep3_out_data_bit_q; 333 | in_data_bit_r = ep3_in_data_bit_q; 334 | ep_stall_r = ep3_stall_i; 335 | ep_iso_r = ep3_iso_i; 336 | end 337 | default: 338 | ; 339 | endcase 340 | end 341 | 342 | always @ (posedge clk_i or posedge rst_i) 343 | if (rst_i) 344 | rx_space_q <= 1'b0; 345 | else if (state_q == STATE_RX_IDLE) 346 | rx_space_q <= rx_space_r; 347 | 348 | //----------------------------------------------------------------- 349 | // SIE - RX 350 | //----------------------------------------------------------------- 351 | usbf_sie_rx 352 | u_sie_rx 353 | ( 354 | .clk_i(clk_i), 355 | .rst_i(rst_i), 356 | 357 | .enable_i(~usb_rst_w && ~reg_chirp_en_i), 358 | 359 | // UTMI Interface 360 | .utmi_data_i(utmi_data_i), 361 | .utmi_rxvalid_i(utmi_rxvalid_i), 362 | .utmi_rxactive_i(utmi_rxactive_i), 363 | 364 | .current_addr_i(current_addr_q), 365 | 366 | .pid_o(token_pid_w), 367 | 368 | .frame_valid_o(frame_valid_w), 369 | .frame_number_o(reg_sts_frame_num_o), 370 | 371 | .token_valid_o(token_valid_w), 372 | .token_addr_o(token_dev_w), 373 | .token_ep_o(token_ep_w), 374 | .token_crc_err_o(), 375 | 376 | .handshake_valid_o(rx_handshake_w), 377 | 378 | .data_valid_o(rx_data_valid_w), 379 | .data_strb_o(rx_strb_o), 380 | .data_o(rx_data_o), 381 | .data_last_o(rx_last_o), 382 | 383 | .data_complete_o(rx_data_complete_w), 384 | .data_crc_err_o(rx_crc_err_o) 385 | ); 386 | 387 | assign ep0_rx_valid_o = rx_enable_q & rx_data_valid_w & (token_ep_w == 4'd0); 388 | assign ep0_rx_setup_o = rx_setup_q & (token_ep_w == 4'd0); 389 | assign ep1_rx_valid_o = rx_enable_q & rx_data_valid_w & (token_ep_w == 4'd1); 390 | assign ep1_rx_setup_o = rx_setup_q & (token_ep_w == 4'd0); 391 | assign ep2_rx_valid_o = rx_enable_q & rx_data_valid_w & (token_ep_w == 4'd2); 392 | assign ep2_rx_setup_o = rx_setup_q & (token_ep_w == 4'd0); 393 | assign ep3_rx_valid_o = rx_enable_q & rx_data_valid_w & (token_ep_w == 4'd3); 394 | assign ep3_rx_setup_o = rx_setup_q & (token_ep_w == 4'd0); 395 | 396 | //----------------------------------------------------------------- 397 | // Next state 398 | //----------------------------------------------------------------- 399 | reg [STATE_W-1:0] next_state_r; 400 | 401 | always @ * 402 | begin 403 | next_state_r = state_q; 404 | 405 | //----------------------------------------- 406 | // State Machine 407 | //----------------------------------------- 408 | case (state_q) 409 | 410 | //----------------------------------------- 411 | // IDLE 412 | //----------------------------------------- 413 | STATE_RX_IDLE : 414 | begin 415 | // Token received (OUT, IN, SETUP, PING) 416 | if (token_valid_w) 417 | begin 418 | //------------------------------- 419 | // IN transfer (device -> host) 420 | //------------------------------- 421 | if (token_pid_w == `PID_IN) 422 | begin 423 | // Stalled endpoint? 424 | if (ep_stall_r) 425 | next_state_r = STATE_TX_HANDSHAKE; 426 | // Some data to TX? 427 | else if (tx_ready_r) 428 | next_state_r = STATE_TX_DATA; 429 | // No data to TX 430 | else 431 | next_state_r = STATE_TX_HANDSHAKE; 432 | end 433 | //------------------------------- 434 | // PING transfer (device -> host) 435 | //------------------------------- 436 | else if (token_pid_w == `PID_PING) 437 | begin 438 | next_state_r = STATE_TX_HANDSHAKE; 439 | end 440 | //------------------------------- 441 | // OUT transfer (host -> device) 442 | //------------------------------- 443 | else if (token_pid_w == `PID_OUT) 444 | begin 445 | // Stalled endpoint? 446 | if (ep_stall_r) 447 | next_state_r = STATE_RX_DATA_IGNORE; 448 | // Some space to rx 449 | else if (rx_space_r) 450 | next_state_r = STATE_RX_DATA; 451 | // No rx space, ignore receive 452 | else 453 | next_state_r = STATE_RX_DATA_IGNORE; 454 | end 455 | //------------------------------- 456 | // SETUP transfer (host -> device) 457 | //------------------------------- 458 | else if (token_pid_w == `PID_SETUP) 459 | begin 460 | // Some space to rx 461 | if (rx_space_r) 462 | next_state_r = STATE_RX_DATA; 463 | // No rx space, ignore receive 464 | else 465 | next_state_r = STATE_RX_DATA_IGNORE; 466 | end 467 | end 468 | else if (reg_chirp_en_i) 469 | next_state_r = STATE_TX_CHIRP; 470 | end 471 | 472 | //----------------------------------------- 473 | // RX_DATA 474 | //----------------------------------------- 475 | STATE_RX_DATA : 476 | begin 477 | // TODO: Exit data state handling? 478 | 479 | // TODO: Sort out ISO data bit handling 480 | // Check for expected DATAx PID 481 | if ((token_pid_w == `PID_DATA0 && out_data_bit_r && !ep_iso_r) || 482 | (token_pid_w == `PID_DATA1 && !out_data_bit_r && !ep_iso_r)) 483 | next_state_r = STATE_RX_DATA_IGNORE; 484 | // Receive complete 485 | else if (rx_data_valid_w && rx_last_o) 486 | next_state_r = STATE_RX_DATA_READY; 487 | end 488 | //----------------------------------------- 489 | // RX_DATA_IGNORE 490 | //----------------------------------------- 491 | STATE_RX_DATA_IGNORE : 492 | begin 493 | // Receive complete 494 | if (rx_data_valid_w && rx_last_o) 495 | next_state_r = STATE_RX_DATA_READY; 496 | end 497 | //----------------------------------------- 498 | // RX_DATA_READY 499 | //----------------------------------------- 500 | STATE_RX_DATA_READY : 501 | begin 502 | if (rx_data_complete_w) 503 | begin 504 | // No response on CRC16 error 505 | if (rx_crc_err_o) 506 | next_state_r = STATE_RX_IDLE; 507 | // ISO endpoint, no response? 508 | else if (ep_iso_r) 509 | next_state_r = STATE_RX_IDLE; 510 | else 511 | next_state_r = STATE_TX_HANDSHAKE; 512 | end 513 | end 514 | //----------------------------------------- 515 | // TX_DATA 516 | //----------------------------------------- 517 | STATE_TX_DATA : 518 | begin 519 | if (!tx_valid_q || tx_accept_w) 520 | if (tx_data_valid_r && tx_data_last_r && tx_data_accept_w) 521 | next_state_r = STATE_TX_DATA_COMPLETE; 522 | end 523 | //----------------------------------------- 524 | // TX_HANDSHAKE 525 | //----------------------------------------- 526 | STATE_TX_DATA_COMPLETE : 527 | begin 528 | next_state_r = STATE_RX_IDLE; 529 | end 530 | //----------------------------------------- 531 | // TX_HANDSHAKE 532 | //----------------------------------------- 533 | STATE_TX_HANDSHAKE : 534 | begin 535 | if (tx_accept_w) 536 | next_state_r = STATE_RX_IDLE; 537 | end 538 | //----------------------------------------- 539 | // TX_CHIRP 540 | //----------------------------------------- 541 | STATE_TX_CHIRP : 542 | begin 543 | if (!reg_chirp_en_i) 544 | next_state_r = STATE_RX_IDLE; 545 | end 546 | 547 | default : 548 | ; 549 | 550 | endcase 551 | 552 | //----------------------------------------- 553 | // USB Bus Reset (HOST->DEVICE) 554 | //----------------------------------------- 555 | if (usb_rst_w && !reg_chirp_en_i) 556 | next_state_r = STATE_RX_IDLE; 557 | end 558 | 559 | // Update state 560 | always @ (posedge clk_i or posedge rst_i) 561 | if (rst_i) 562 | state_q <= STATE_RX_IDLE; 563 | else 564 | state_q <= next_state_r; 565 | 566 | //----------------------------------------------------------------- 567 | // Response 568 | //----------------------------------------------------------------- 569 | reg tx_valid_r; 570 | reg [7:0] tx_pid_r; 571 | 572 | always @ * 573 | begin 574 | tx_valid_r = 1'b0; 575 | tx_pid_r = 8'b0; 576 | 577 | case (state_q) 578 | //----------------------------------------- 579 | // IDLE 580 | //----------------------------------------- 581 | STATE_RX_IDLE : 582 | begin 583 | // Token received (OUT, IN, SETUP, PING) 584 | if (token_valid_w) 585 | begin 586 | //------------------------------- 587 | // IN transfer (device -> host) 588 | //------------------------------- 589 | if (token_pid_w == `PID_IN) 590 | begin 591 | // Stalled endpoint? 592 | if (ep_stall_r) 593 | begin 594 | tx_valid_r = 1'b1; 595 | tx_pid_r = `PID_STALL; 596 | end 597 | // Some data to TX? 598 | else if (tx_ready_r) 599 | begin 600 | tx_valid_r = 1'b1; 601 | // TODO: Handle MDATA for ISOs 602 | tx_pid_r = in_data_bit_r ? `PID_DATA1 : `PID_DATA0; 603 | end 604 | // No data to TX 605 | else 606 | begin 607 | tx_valid_r = 1'b1; 608 | tx_pid_r = `PID_NAK; 609 | end 610 | end 611 | //------------------------------- 612 | // PING transfer (device -> host) 613 | //------------------------------- 614 | else if (token_pid_w == `PID_PING) 615 | begin 616 | // Stalled endpoint? 617 | if (ep_stall_r) 618 | begin 619 | tx_valid_r = 1'b1; 620 | tx_pid_r = `PID_STALL; 621 | end 622 | // Data ready to RX 623 | else if (rx_space_r) 624 | begin 625 | tx_valid_r = 1'b1; 626 | tx_pid_r = `PID_ACK; 627 | end 628 | // No data to TX 629 | else 630 | begin 631 | tx_valid_r = 1'b1; 632 | tx_pid_r = `PID_NAK; 633 | end 634 | end 635 | end 636 | end 637 | 638 | //----------------------------------------- 639 | // RX_DATA_READY 640 | //----------------------------------------- 641 | STATE_RX_DATA_READY : 642 | begin 643 | // Receive complete 644 | if (rx_data_complete_w) 645 | begin 646 | // No response on CRC16 error 647 | if (rx_crc_err_o) 648 | ; 649 | // ISO endpoint, no response? 650 | else if (ep_iso_r) 651 | ; 652 | // Send STALL? 653 | else if (ep_stall_r) 654 | begin 655 | tx_valid_r = 1'b1; 656 | tx_pid_r = `PID_STALL; 657 | end 658 | // DATAx bit mismatch 659 | else if ( (token_pid_w == `PID_DATA0 && out_data_bit_r) || 660 | (token_pid_w == `PID_DATA1 && !out_data_bit_r) ) 661 | begin 662 | // Ack transfer to resync 663 | tx_valid_r = 1'b1; 664 | tx_pid_r = `PID_ACK; 665 | end 666 | // Send NAK 667 | else if (!rx_space_q) 668 | begin 669 | tx_valid_r = 1'b1; 670 | tx_pid_r = `PID_NAK; 671 | end 672 | // TODO: USB 2.0, no more buffer space, return NYET 673 | else 674 | begin 675 | tx_valid_r = 1'b1; 676 | tx_pid_r = `PID_ACK; 677 | end 678 | end 679 | end 680 | 681 | //----------------------------------------- 682 | // TX_CHIRP 683 | //----------------------------------------- 684 | STATE_TX_CHIRP : 685 | begin 686 | tx_valid_r = 1'b1; 687 | tx_pid_r = 8'b0; 688 | end 689 | 690 | default : 691 | ; 692 | 693 | endcase 694 | end 695 | 696 | always @ (posedge clk_i or posedge rst_i) 697 | if (rst_i) 698 | tx_valid_q <= 1'b0; 699 | else if (!tx_valid_q || tx_accept_w) 700 | tx_valid_q <= tx_valid_r; 701 | 702 | always @ (posedge clk_i or posedge rst_i) 703 | if (rst_i) 704 | tx_pid_q <= 8'b0; 705 | else if (!tx_valid_q || tx_accept_w) 706 | tx_pid_q <= tx_pid_r; 707 | 708 | //----------------------------------------------------------------- 709 | // Receive enable 710 | //----------------------------------------------------------------- 711 | always @ (posedge clk_i or posedge rst_i) 712 | if (rst_i) 713 | rx_enable_q <= 1'b0; 714 | else if (usb_rst_w ||reg_chirp_en_i) 715 | rx_enable_q <= 1'b0; 716 | else 717 | rx_enable_q <= (state_q == STATE_RX_DATA); 718 | 719 | //----------------------------------------------------------------- 720 | // Receive SETUP: Pulse on SETUP packet receive 721 | //----------------------------------------------------------------- 722 | always @ (posedge clk_i or posedge rst_i) 723 | if (rst_i) 724 | rx_setup_q <= 1'b0; 725 | else if (usb_rst_w ||reg_chirp_en_i) 726 | rx_setup_q <= 1'b0; 727 | else if ((state_q == STATE_RX_IDLE) && token_valid_w && (token_pid_w == `PID_SETUP) && (token_ep_w == 4'd0)) 728 | rx_setup_q <= 1'b1; 729 | else 730 | rx_setup_q <= 1'b0; 731 | 732 | //----------------------------------------------------------------- 733 | // Set Address 734 | //----------------------------------------------------------------- 735 | reg addr_update_pending_q; 736 | 737 | wire ep0_tx_zlp_w = ep0_tx_data_valid_i && (ep0_tx_data_strb_i == 1'b0) && 738 | ep0_tx_data_last_i && ep0_tx_data_accept_o; 739 | 740 | reg sent_status_zlp_q; 741 | 742 | always @ (posedge clk_i or posedge rst_i) 743 | if (rst_i) 744 | sent_status_zlp_q <= 1'b0; 745 | else if (usb_rst_w) 746 | sent_status_zlp_q <= 1'b0; 747 | else if (ep0_tx_zlp_w) 748 | sent_status_zlp_q <= 1'b1; 749 | else if (rx_handshake_w) 750 | sent_status_zlp_q <= 1'b0; 751 | 752 | always @ (posedge clk_i or posedge rst_i) 753 | if (rst_i) 754 | addr_update_pending_q <= 1'b0; 755 | else if ((sent_status_zlp_q && addr_update_pending_q && rx_handshake_w && token_pid_w == `PID_ACK) || usb_rst_w) 756 | addr_update_pending_q <= 1'b0; 757 | // TODO: Use write strobe 758 | else if (reg_dev_addr_i != current_addr_q) 759 | addr_update_pending_q <= 1'b1; 760 | 761 | always @ (posedge clk_i or posedge rst_i) 762 | if (rst_i) 763 | current_addr_q <= `USB_DEV_W'b0; 764 | else if (usb_rst_w) 765 | current_addr_q <= `USB_DEV_W'b0; 766 | else if (sent_status_zlp_q && addr_update_pending_q && rx_handshake_w && token_pid_w == `PID_ACK) 767 | current_addr_q <= reg_dev_addr_i; 768 | 769 | //----------------------------------------------------------------- 770 | // Endpoint data bit toggle 771 | //----------------------------------------------------------------- 772 | reg new_out_bit_r; 773 | reg new_in_bit_r; 774 | 775 | always @ * 776 | begin 777 | new_out_bit_r = out_data_bit_r; 778 | new_in_bit_r = in_data_bit_r; 779 | 780 | case (state_q) 781 | //----------------------------------------- 782 | // RX_DATA_READY 783 | //----------------------------------------- 784 | STATE_RX_DATA_READY : 785 | begin 786 | // Receive complete 787 | if (rx_data_complete_w) 788 | begin 789 | // No toggle on CRC16 error 790 | if (rx_crc_err_o) 791 | ; 792 | // ISO endpoint, no response? 793 | else if (ep_iso_r) 794 | ; // TODO: HS handling 795 | // STALL? 796 | else if (ep_stall_r) 797 | ; 798 | // DATAx bit mismatch 799 | else if ( (token_pid_w == `PID_DATA0 && out_data_bit_r) || 800 | (token_pid_w == `PID_DATA1 && !out_data_bit_r) ) 801 | ; 802 | // NAKd 803 | else if (!rx_space_q) 804 | ; 805 | // Data accepted - toggle data bit 806 | else 807 | new_out_bit_r = !out_data_bit_r; 808 | end 809 | end 810 | //----------------------------------------- 811 | // RX_IDLE 812 | //----------------------------------------- 813 | STATE_RX_IDLE : 814 | begin 815 | // Token received (OUT, IN, SETUP, PING) 816 | if (token_valid_w) 817 | begin 818 | // SETUP packets always start with DATA0 819 | if (token_pid_w == `PID_SETUP) 820 | begin 821 | new_out_bit_r = 1'b0; 822 | new_in_bit_r = 1'b1; 823 | end 824 | end 825 | // ACK received 826 | else if (rx_handshake_w && token_pid_w == `PID_ACK) 827 | begin 828 | new_in_bit_r = !in_data_bit_r; 829 | end 830 | end 831 | default: 832 | ; 833 | endcase 834 | end 835 | 836 | always @ (posedge clk_i or posedge rst_i) 837 | if (rst_i) 838 | begin 839 | ep0_out_data_bit_q <= 1'b0; 840 | ep0_in_data_bit_q <= 1'b0; 841 | end 842 | else if (usb_rst_w) 843 | begin 844 | ep0_out_data_bit_q <= 1'b0; 845 | ep0_in_data_bit_q <= 1'b0; 846 | end 847 | else if (token_ep_w == 4'd0) 848 | begin 849 | ep0_out_data_bit_q <= new_out_bit_r; 850 | ep0_in_data_bit_q <= new_in_bit_r; 851 | end 852 | always @ (posedge clk_i or posedge rst_i) 853 | if (rst_i) 854 | begin 855 | ep1_out_data_bit_q <= 1'b0; 856 | ep1_in_data_bit_q <= 1'b0; 857 | end 858 | else if (usb_rst_w) 859 | begin 860 | ep1_out_data_bit_q <= 1'b0; 861 | ep1_in_data_bit_q <= 1'b0; 862 | end 863 | else if (token_ep_w == 4'd1) 864 | begin 865 | ep1_out_data_bit_q <= new_out_bit_r; 866 | ep1_in_data_bit_q <= new_in_bit_r; 867 | end 868 | always @ (posedge clk_i or posedge rst_i) 869 | if (rst_i) 870 | begin 871 | ep2_out_data_bit_q <= 1'b0; 872 | ep2_in_data_bit_q <= 1'b0; 873 | end 874 | else if (usb_rst_w) 875 | begin 876 | ep2_out_data_bit_q <= 1'b0; 877 | ep2_in_data_bit_q <= 1'b0; 878 | end 879 | else if (token_ep_w == 4'd2) 880 | begin 881 | ep2_out_data_bit_q <= new_out_bit_r; 882 | ep2_in_data_bit_q <= new_in_bit_r; 883 | end 884 | always @ (posedge clk_i or posedge rst_i) 885 | if (rst_i) 886 | begin 887 | ep3_out_data_bit_q <= 1'b0; 888 | ep3_in_data_bit_q <= 1'b0; 889 | end 890 | else if (usb_rst_w) 891 | begin 892 | ep3_out_data_bit_q <= 1'b0; 893 | ep3_in_data_bit_q <= 1'b0; 894 | end 895 | else if (token_ep_w == 4'd3) 896 | begin 897 | ep3_out_data_bit_q <= new_out_bit_r; 898 | ep3_in_data_bit_q <= new_in_bit_r; 899 | end 900 | 901 | //----------------------------------------------------------------- 902 | // Reset event 903 | //----------------------------------------------------------------- 904 | reg rst_event_q; 905 | 906 | always @ (posedge clk_i or posedge rst_i) 907 | if (rst_i) 908 | rst_event_q <= 1'b0; 909 | else if (usb_rst_w) 910 | rst_event_q <= 1'b1; 911 | else if (reg_sts_rst_clr_i) 912 | rst_event_q <= 1'b0; 913 | 914 | assign reg_sts_rst_o = rst_event_q; 915 | 916 | //----------------------------------------------------------------- 917 | // Interrupts 918 | //----------------------------------------------------------------- 919 | reg intr_q; 920 | 921 | reg cfg_int_rx_r; 922 | reg cfg_int_tx_r; 923 | 924 | always @ * 925 | begin 926 | cfg_int_rx_r = 1'b0; 927 | cfg_int_tx_r = 1'b0; 928 | 929 | case (token_ep_w) 930 | 4'd0: 931 | begin 932 | cfg_int_rx_r = ep0_cfg_int_rx_i; 933 | cfg_int_tx_r = ep0_cfg_int_tx_i; 934 | end 935 | 4'd1: 936 | begin 937 | cfg_int_rx_r = ep1_cfg_int_rx_i; 938 | cfg_int_tx_r = ep1_cfg_int_tx_i; 939 | end 940 | 4'd2: 941 | begin 942 | cfg_int_rx_r = ep2_cfg_int_rx_i; 943 | cfg_int_tx_r = ep2_cfg_int_tx_i; 944 | end 945 | 4'd3: 946 | begin 947 | cfg_int_rx_r = ep3_cfg_int_rx_i; 948 | cfg_int_tx_r = ep3_cfg_int_tx_i; 949 | end 950 | default: 951 | ; 952 | endcase 953 | end 954 | 955 | always @ (posedge clk_i or posedge rst_i) 956 | if (rst_i) 957 | intr_q <= 1'b0; 958 | // SOF 959 | else if (frame_valid_w && reg_int_en_sof_i) 960 | intr_q <= 1'b1; 961 | // Reset event 962 | else if (!rst_event_q && usb_rst_w) 963 | intr_q <= 1'b1; 964 | // Rx ready 965 | else if (state_q == STATE_RX_DATA_READY && rx_space_q && cfg_int_rx_r) 966 | intr_q <= 1'b1; 967 | // Tx complete 968 | else if (state_q == STATE_TX_DATA_COMPLETE && cfg_int_tx_r) 969 | intr_q <= 1'b1; 970 | else 971 | intr_q <= 1'b0; 972 | 973 | assign intr_o = intr_q; 974 | 975 | //------------------------------------------------------------------- 976 | // Debug 977 | //------------------------------------------------------------------- 978 | `ifdef verilator 979 | /* verilator lint_off WIDTH */ 980 | reg [79:0] dbg_state; 981 | 982 | always @ * 983 | begin 984 | dbg_state = "-"; 985 | 986 | case (state_q) 987 | STATE_RX_IDLE: dbg_state = "IDLE"; 988 | STATE_RX_DATA: dbg_state = "RX_DATA"; 989 | STATE_RX_DATA_READY: dbg_state = "RX_DATA_READY"; 990 | STATE_RX_DATA_IGNORE: dbg_state = "RX_IGNORE"; 991 | STATE_TX_DATA: dbg_state = "TX_DATA"; 992 | STATE_TX_DATA_COMPLETE: dbg_state = "TX_DATA_COMPLETE"; 993 | STATE_TX_HANDSHAKE: dbg_state = "TX_HANDSHAKE"; 994 | STATE_TX_CHIRP: dbg_state = "CHIRP"; 995 | endcase 996 | end 997 | 998 | reg [79:0] dbg_pid; 999 | reg [7:0] dbg_pid_r; 1000 | always @ * 1001 | begin 1002 | dbg_pid = "-"; 1003 | 1004 | if (tx_valid_q && tx_accept_w) 1005 | dbg_pid_r = tx_pid_q; 1006 | else if (token_valid_w || rx_handshake_w || rx_data_valid_w) 1007 | dbg_pid_r = token_pid_w; 1008 | else 1009 | dbg_pid_r = 8'b0; 1010 | 1011 | case (dbg_pid_r) 1012 | // Token 1013 | `PID_OUT: 1014 | dbg_pid = "OUT"; 1015 | `PID_IN: 1016 | dbg_pid = "IN"; 1017 | `PID_SOF: 1018 | dbg_pid = "SOF"; 1019 | `PID_SETUP: 1020 | dbg_pid = "SETUP"; 1021 | `PID_PING: 1022 | dbg_pid = "PING"; 1023 | // Data 1024 | `PID_DATA0: 1025 | dbg_pid = "DATA0"; 1026 | `PID_DATA1: 1027 | dbg_pid = "DATA1"; 1028 | `PID_DATA2: 1029 | dbg_pid = "DATA2"; 1030 | `PID_MDATA: 1031 | dbg_pid = "MDATA"; 1032 | // Handshake 1033 | `PID_ACK: 1034 | dbg_pid = "ACK"; 1035 | `PID_NAK: 1036 | dbg_pid = "NAK"; 1037 | `PID_STALL: 1038 | dbg_pid = "STALL"; 1039 | `PID_NYET: 1040 | dbg_pid = "NYET"; 1041 | // Special 1042 | `PID_PRE: 1043 | dbg_pid = "PRE/ERR"; 1044 | `PID_SPLIT: 1045 | dbg_pid = "SPLIT"; 1046 | default: 1047 | ; 1048 | endcase 1049 | end 1050 | /* verilator lint_on WIDTH */ 1051 | `endif 1052 | 1053 | 1054 | endmodule 1055 | -------------------------------------------------------------------------------- /src_v/usbf_sie_rx.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usbf_sie_rx 40 | ( 41 | // Inputs 42 | input clk_i 43 | ,input rst_i 44 | ,input enable_i 45 | ,input [ 7:0] utmi_data_i 46 | ,input utmi_rxvalid_i 47 | ,input utmi_rxactive_i 48 | ,input [ 6:0] current_addr_i 49 | 50 | // Outputs 51 | ,output [ 7:0] pid_o 52 | ,output frame_valid_o 53 | ,output [ 10:0] frame_number_o 54 | ,output token_valid_o 55 | ,output [ 6:0] token_addr_o 56 | ,output [ 3:0] token_ep_o 57 | ,output token_crc_err_o 58 | ,output handshake_valid_o 59 | ,output data_valid_o 60 | ,output data_strb_o 61 | ,output [ 7:0] data_o 62 | ,output data_last_o 63 | ,output data_crc_err_o 64 | ,output data_complete_o 65 | ); 66 | 67 | 68 | 69 | //----------------------------------------------------------------- 70 | // Defines: 71 | //----------------------------------------------------------------- 72 | `include "usbf_defs.v" 73 | 74 | localparam STATE_W = 4; 75 | localparam STATE_RX_IDLE = 4'd0; 76 | localparam STATE_RX_TOKEN2 = 4'd1; 77 | localparam STATE_RX_TOKEN3 = 4'd2; 78 | localparam STATE_RX_TOKEN_COMPLETE = 4'd3; 79 | localparam STATE_RX_SOF2 = 4'd4; 80 | localparam STATE_RX_SOF3 = 4'd5; 81 | localparam STATE_RX_DATA = 4'd6; 82 | localparam STATE_RX_DATA_COMPLETE = 4'd7; 83 | localparam STATE_RX_IGNORED = 4'd8; 84 | reg [STATE_W-1:0] state_q; 85 | 86 | //----------------------------------------------------------------- 87 | // Wire / Regs 88 | //----------------------------------------------------------------- 89 | `define USB_FRAME_W 11 90 | reg [`USB_FRAME_W-1:0] frame_num_q; 91 | 92 | `define USB_DEV_W 7 93 | reg [`USB_DEV_W-1:0] token_dev_q; 94 | 95 | `define USB_EP_W 4 96 | reg [`USB_EP_W-1:0] token_ep_q; 97 | 98 | `define USB_PID_W 8 99 | reg [`USB_PID_W-1:0] token_pid_q; 100 | 101 | //----------------------------------------------------------------- 102 | // Data delay (to strip the CRC16 trailing bytes) 103 | //----------------------------------------------------------------- 104 | reg [31:0] data_buffer_q; 105 | reg [3:0] data_valid_q; 106 | reg [3:0] rx_active_q; 107 | 108 | wire shift_en_w = (utmi_rxvalid_i & utmi_rxactive_i) || !utmi_rxactive_i; 109 | 110 | always @ (posedge clk_i or posedge rst_i) 111 | if (rst_i) 112 | data_buffer_q <= 32'b0; 113 | else if (shift_en_w) 114 | data_buffer_q <= {utmi_data_i, data_buffer_q[31:8]}; 115 | 116 | always @ (posedge clk_i or posedge rst_i) 117 | if (rst_i) 118 | data_valid_q <= 4'b0; 119 | else if (shift_en_w) 120 | data_valid_q <= {(utmi_rxvalid_i & utmi_rxactive_i), data_valid_q[3:1]}; 121 | else 122 | data_valid_q <= {data_valid_q[3:1], 1'b0}; 123 | 124 | reg [1:0] data_crc_q; 125 | always @ (posedge clk_i or posedge rst_i) 126 | if (rst_i) 127 | data_crc_q <= 2'b0; 128 | else if (shift_en_w) 129 | data_crc_q <= {!utmi_rxactive_i, data_crc_q[1]}; 130 | 131 | always @ (posedge clk_i or posedge rst_i) 132 | if (rst_i) 133 | rx_active_q <= 4'b0; 134 | else 135 | rx_active_q <= {utmi_rxactive_i, rx_active_q[3:1]}; 136 | 137 | wire [7:0] data_w = data_buffer_q[7:0]; 138 | wire data_ready_w = data_valid_q[0]; 139 | wire crc_byte_w = data_crc_q[0]; 140 | wire rx_active_w = rx_active_q[0]; 141 | 142 | wire address_match_w = (token_dev_q == current_addr_i); 143 | 144 | //----------------------------------------------------------------- 145 | // Next state 146 | //----------------------------------------------------------------- 147 | reg [STATE_W-1:0] next_state_r; 148 | 149 | always @ * 150 | begin 151 | next_state_r = state_q; 152 | 153 | case (state_q) 154 | 155 | //----------------------------------------- 156 | // IDLE 157 | //----------------------------------------- 158 | STATE_RX_IDLE : 159 | begin 160 | if (data_ready_w) 161 | begin 162 | // Decode PID 163 | case (data_w) 164 | 165 | `PID_OUT, `PID_IN, `PID_SETUP, `PID_PING: 166 | next_state_r = STATE_RX_TOKEN2; 167 | 168 | `PID_SOF: 169 | next_state_r = STATE_RX_SOF2; 170 | 171 | `PID_DATA0, `PID_DATA1, `PID_DATA2, `PID_MDATA: 172 | begin 173 | next_state_r = STATE_RX_DATA; 174 | end 175 | 176 | `PID_ACK, `PID_NAK, `PID_STALL, `PID_NYET: 177 | next_state_r = STATE_RX_IDLE; 178 | 179 | default : // SPLIT / ERR 180 | next_state_r = STATE_RX_IGNORED; 181 | endcase 182 | end 183 | end 184 | 185 | //----------------------------------------- 186 | // RX_IGNORED: Unknown / unsupported 187 | //----------------------------------------- 188 | STATE_RX_IGNORED : 189 | begin 190 | // Wait until the end of the packet 191 | if (!rx_active_w) 192 | next_state_r = STATE_RX_IDLE; 193 | end 194 | 195 | //----------------------------------------- 196 | // SOF (BYTE 2) 197 | //----------------------------------------- 198 | STATE_RX_SOF2 : 199 | begin 200 | if (data_ready_w) 201 | next_state_r = STATE_RX_SOF3; 202 | else if (!rx_active_w) 203 | next_state_r = STATE_RX_IDLE; 204 | end 205 | 206 | //----------------------------------------- 207 | // SOF (BYTE 3) 208 | //----------------------------------------- 209 | STATE_RX_SOF3 : 210 | begin 211 | if (data_ready_w || !rx_active_w) 212 | next_state_r = STATE_RX_IDLE; 213 | end 214 | 215 | //----------------------------------------- 216 | // TOKEN (IN/OUT/SETUP) (Address/Endpoint) 217 | //----------------------------------------- 218 | STATE_RX_TOKEN2 : 219 | begin 220 | if (data_ready_w) 221 | next_state_r = STATE_RX_TOKEN3; 222 | else if (!rx_active_w) 223 | next_state_r = STATE_RX_IDLE; 224 | end 225 | 226 | //----------------------------------------- 227 | // TOKEN (IN/OUT/SETUP) (Endpoint/CRC) 228 | //----------------------------------------- 229 | STATE_RX_TOKEN3 : 230 | begin 231 | if (data_ready_w) 232 | next_state_r = STATE_RX_TOKEN_COMPLETE; 233 | else if (!rx_active_w) 234 | next_state_r = STATE_RX_IDLE; 235 | end 236 | 237 | //----------------------------------------- 238 | // RX_TOKEN_COMPLETE 239 | //----------------------------------------- 240 | STATE_RX_TOKEN_COMPLETE : 241 | begin 242 | next_state_r = STATE_RX_IDLE; 243 | end 244 | 245 | //----------------------------------------- 246 | // RX_DATA 247 | //----------------------------------------- 248 | STATE_RX_DATA : 249 | begin 250 | // Receive complete 251 | if (crc_byte_w) 252 | next_state_r = STATE_RX_DATA_COMPLETE; 253 | end 254 | 255 | //----------------------------------------- 256 | // RX_DATA_COMPLETE 257 | //----------------------------------------- 258 | STATE_RX_DATA_COMPLETE : 259 | begin 260 | if (!rx_active_w) 261 | next_state_r = STATE_RX_IDLE; 262 | end 263 | 264 | default : 265 | ; 266 | 267 | endcase 268 | end 269 | 270 | // Update state 271 | always @ (posedge clk_i or posedge rst_i) 272 | if (rst_i) 273 | state_q <= STATE_RX_IDLE; 274 | else if (!enable_i) 275 | state_q <= STATE_RX_IDLE; 276 | else 277 | state_q <= next_state_r; 278 | 279 | //----------------------------------------------------------------- 280 | // Handshake: 281 | //----------------------------------------------------------------- 282 | reg handshake_valid_q; 283 | 284 | always @ (posedge clk_i or posedge rst_i) 285 | if (rst_i) 286 | handshake_valid_q <= 1'b0; 287 | else if (state_q == STATE_RX_IDLE && data_ready_w) 288 | begin 289 | case (data_w) 290 | `PID_ACK, `PID_NAK, `PID_STALL, `PID_NYET: 291 | handshake_valid_q <= address_match_w; 292 | default : 293 | handshake_valid_q <= 1'b0; 294 | endcase 295 | end 296 | else 297 | handshake_valid_q <= 1'b0; 298 | 299 | assign handshake_valid_o = handshake_valid_q; 300 | 301 | //----------------------------------------------------------------- 302 | // SOF: Frame number 303 | //----------------------------------------------------------------- 304 | always @ (posedge clk_i or posedge rst_i) 305 | if (rst_i) 306 | frame_num_q <= `USB_FRAME_W'b0; 307 | else if (state_q == STATE_RX_SOF2 && data_ready_w) 308 | frame_num_q <= {3'b0, data_w}; 309 | else if (state_q == STATE_RX_SOF3 && data_ready_w) 310 | frame_num_q <= {data_w[2:0], frame_num_q[7:0]}; 311 | else if (!enable_i) 312 | frame_num_q <= `USB_FRAME_W'b0; 313 | 314 | assign frame_number_o = frame_num_q; 315 | 316 | reg frame_valid_q; 317 | 318 | always @ (posedge clk_i or posedge rst_i) 319 | if (rst_i) 320 | frame_valid_q <= 1'b0; 321 | else 322 | frame_valid_q <= (state_q == STATE_RX_SOF3 && data_ready_w); 323 | 324 | assign frame_valid_o = frame_valid_q; 325 | 326 | //----------------------------------------------------------------- 327 | // Token: PID 328 | //----------------------------------------------------------------- 329 | always @ (posedge clk_i or posedge rst_i) 330 | if (rst_i) 331 | token_pid_q <= `USB_PID_W'b0; 332 | else if (state_q == STATE_RX_IDLE && data_ready_w) 333 | token_pid_q <= data_w; 334 | else if (!enable_i) 335 | token_pid_q <= `USB_PID_W'b0; 336 | 337 | assign pid_o = token_pid_q; 338 | 339 | reg token_valid_q; 340 | 341 | always @ (posedge clk_i or posedge rst_i) 342 | if (rst_i) 343 | token_valid_q <= 1'b0; 344 | else 345 | token_valid_q <= (state_q == STATE_RX_TOKEN_COMPLETE) && address_match_w; 346 | 347 | assign token_valid_o = token_valid_q; 348 | 349 | //----------------------------------------------------------------- 350 | // Token: Device Address 351 | //----------------------------------------------------------------- 352 | always @ (posedge clk_i or posedge rst_i) 353 | if (rst_i) 354 | token_dev_q <= `USB_DEV_W'b0; 355 | else if (state_q == STATE_RX_TOKEN2 && data_ready_w) 356 | token_dev_q <= data_w[6:0]; 357 | else if (!enable_i) 358 | token_dev_q <= `USB_DEV_W'b0; 359 | 360 | assign token_addr_o = token_dev_q; 361 | 362 | //----------------------------------------------------------------- 363 | // Token: Endpoint 364 | //----------------------------------------------------------------- 365 | always @ (posedge clk_i or posedge rst_i) 366 | if (rst_i) 367 | token_ep_q <= `USB_EP_W'b0; 368 | else if (state_q == STATE_RX_TOKEN2 && data_ready_w) 369 | token_ep_q[0] <= data_w[7]; 370 | else if (state_q == STATE_RX_TOKEN3 && data_ready_w) 371 | token_ep_q[3:1] <= data_w[2:0]; 372 | else if (!enable_i) 373 | token_ep_q <= `USB_EP_W'b0; 374 | 375 | assign token_ep_o = token_ep_q; 376 | assign token_crc_err_o = 1'b0; 377 | 378 | wire [7:0] input_data_w = data_w; 379 | wire input_ready_w = state_q == STATE_RX_DATA && data_ready_w && !crc_byte_w; 380 | 381 | //----------------------------------------------------------------- 382 | // CRC16: Generate CRC16 on incoming data bytes 383 | //----------------------------------------------------------------- 384 | reg [15:0] crc_sum_q; 385 | wire [15:0] crc_out_w; 386 | reg crc_err_q; 387 | 388 | usbf_crc16 389 | u_crc16 390 | ( 391 | .crc_in_i(crc_sum_q), 392 | .din_i(data_w), 393 | .crc_out_o(crc_out_w) 394 | ); 395 | 396 | always @ (posedge clk_i or posedge rst_i) 397 | if (rst_i) 398 | crc_sum_q <= 16'hFFFF; 399 | else if (state_q == STATE_RX_IDLE) 400 | crc_sum_q <= 16'hFFFF; 401 | else if (data_ready_w) 402 | crc_sum_q <= crc_out_w; 403 | 404 | always @ (posedge clk_i or posedge rst_i) 405 | if (rst_i) 406 | crc_err_q <= 1'b0; 407 | else if (state_q == STATE_RX_IDLE) 408 | crc_err_q <= 1'b0; 409 | else if (state_q == STATE_RX_DATA_COMPLETE && next_state_r == STATE_RX_IDLE) 410 | crc_err_q <= (crc_sum_q != 16'hB001); 411 | 412 | assign data_crc_err_o = crc_err_q; 413 | 414 | reg data_complete_q; 415 | 416 | always @ (posedge clk_i or posedge rst_i) 417 | if (rst_i) 418 | data_complete_q <= 1'b0; 419 | else if (state_q == STATE_RX_DATA_COMPLETE && next_state_r == STATE_RX_IDLE) 420 | data_complete_q <= 1'b1; 421 | else 422 | data_complete_q <= 1'b0; 423 | 424 | assign data_complete_o = data_complete_q; 425 | 426 | reg data_zlp_q; 427 | 428 | always @ (posedge clk_i or posedge rst_i) 429 | if (rst_i) 430 | data_zlp_q <= 1'b0; 431 | else if (state_q == STATE_RX_IDLE && next_state_r == STATE_RX_DATA) 432 | data_zlp_q <= 1'b1; 433 | else if (input_ready_w) 434 | data_zlp_q <= 1'b0; 435 | 436 | //----------------------------------------------------------------- 437 | // Data Output 438 | //----------------------------------------------------------------- 439 | reg valid_q; 440 | reg last_q; 441 | reg [7:0] data_q; 442 | reg mask_q; 443 | 444 | always @ (posedge clk_i or posedge rst_i) 445 | if (rst_i) 446 | begin 447 | valid_q <= 1'b0; 448 | data_q <= 8'b0; 449 | mask_q <= 1'b0; 450 | last_q <= 1'b0; 451 | end 452 | else 453 | begin 454 | valid_q <= input_ready_w || ((state_q == STATE_RX_DATA) && crc_byte_w && data_zlp_q); 455 | data_q <= input_data_w; 456 | mask_q <= input_ready_w; 457 | last_q <= (state_q == STATE_RX_DATA) && crc_byte_w; 458 | end 459 | 460 | // Data 461 | assign data_valid_o = valid_q; 462 | assign data_strb_o = mask_q; 463 | assign data_o = data_q; 464 | assign data_last_o = last_q | crc_byte_w; 465 | 466 | 467 | endmodule 468 | -------------------------------------------------------------------------------- /src_v/usbf_sie_tx.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // USB Serial Port 3 | // V0.1 4 | // Ultra-Embedded.com 5 | // Copyright 2020 6 | // 7 | // Email: admin@ultra-embedded.com 8 | // 9 | // License: LGPL 10 | //----------------------------------------------------------------- 11 | // 12 | // This source file may be used and distributed without 13 | // restriction provided that this copyright statement is not 14 | // removed from the file and that any derivative work contains 15 | // the original copyright notice and the associated disclaimer. 16 | // 17 | // This source file is free software; you can redistribute it 18 | // and/or modify it under the terms of the GNU Lesser General 19 | // Public License as published by the Free Software Foundation; 20 | // either version 2.1 of the License, or (at your option) any 21 | // later version. 22 | // 23 | // This source is distributed in the hope that it will be 24 | // useful, but WITHOUT ANY WARRANTY; without even the implied 25 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 26 | // PURPOSE. See the GNU Lesser General Public License for more 27 | // details. 28 | // 29 | // You should have received a copy of the GNU Lesser General 30 | // Public License along with this source; if not, write to the 31 | // Free Software Foundation, Inc., 59 Temple Place, Suite 330, 32 | // Boston, MA 02111-1307 USA 33 | //----------------------------------------------------------------- 34 | 35 | //----------------------------------------------------------------- 36 | // Generated File 37 | //----------------------------------------------------------------- 38 | 39 | module usbf_sie_tx 40 | ( 41 | // Inputs 42 | input clk_i 43 | ,input rst_i 44 | ,input enable_i 45 | ,input chirp_i 46 | ,input utmi_txready_i 47 | ,input tx_valid_i 48 | ,input [ 7:0] tx_pid_i 49 | ,input data_valid_i 50 | ,input data_strb_i 51 | ,input [ 7:0] data_i 52 | ,input data_last_i 53 | 54 | // Outputs 55 | ,output [ 7:0] utmi_data_o 56 | ,output utmi_txvalid_o 57 | ,output tx_accept_o 58 | ,output data_accept_o 59 | ); 60 | 61 | 62 | 63 | //----------------------------------------------------------------- 64 | // Defines: 65 | //----------------------------------------------------------------- 66 | `include "usbf_defs.v" 67 | 68 | localparam STATE_W = 3; 69 | localparam STATE_TX_IDLE = 3'd0; 70 | localparam STATE_TX_PID = 3'd1; 71 | localparam STATE_TX_DATA = 3'd2; 72 | localparam STATE_TX_CRC1 = 3'd3; 73 | localparam STATE_TX_CRC2 = 3'd4; 74 | localparam STATE_TX_DONE = 3'd5; 75 | localparam STATE_TX_CHIRP = 3'd6; 76 | 77 | reg [STATE_W-1:0] state_q; 78 | reg [STATE_W-1:0] next_state_r; 79 | 80 | //----------------------------------------------------------------- 81 | // Request Type 82 | //----------------------------------------------------------------- 83 | reg data_pid_q; 84 | reg data_zlp_q; 85 | 86 | always @ (posedge clk_i or posedge rst_i) 87 | if (rst_i) 88 | begin 89 | data_pid_q <= 1'b0; 90 | data_zlp_q <= 1'b0; 91 | end 92 | else if (!enable_i) 93 | begin 94 | data_pid_q <= 1'b0; 95 | data_zlp_q <= 1'b0; 96 | end 97 | else if (tx_valid_i && tx_accept_o) 98 | begin 99 | case (tx_pid_i) 100 | 101 | `PID_MDATA, `PID_DATA2, `PID_DATA0, `PID_DATA1: 102 | begin 103 | data_pid_q <= 1'b1; 104 | data_zlp_q <= data_valid_i && (data_strb_i == 1'b0) && data_last_i; 105 | end 106 | 107 | default : 108 | begin 109 | data_pid_q <= 1'b0; 110 | data_zlp_q <= 1'b0; 111 | end 112 | endcase 113 | end 114 | else if (next_state_r == STATE_TX_CRC1) 115 | begin 116 | data_pid_q <= 1'b0; 117 | data_zlp_q <= 1'b0; 118 | end 119 | 120 | assign tx_accept_o = (state_q == STATE_TX_IDLE); 121 | 122 | //----------------------------------------------------------------- 123 | // Next state 124 | //----------------------------------------------------------------- 125 | always @ * 126 | begin 127 | next_state_r = state_q; 128 | 129 | //----------------------------------------- 130 | // State Machine 131 | //----------------------------------------- 132 | case (state_q) 133 | 134 | //----------------------------------------- 135 | // IDLE 136 | //----------------------------------------- 137 | STATE_TX_IDLE : 138 | begin 139 | if (chirp_i) 140 | next_state_r = STATE_TX_CHIRP; 141 | else if (tx_valid_i) 142 | next_state_r = STATE_TX_PID; 143 | end 144 | 145 | //----------------------------------------- 146 | // TX_PID 147 | //----------------------------------------- 148 | STATE_TX_PID : 149 | begin 150 | // Data accepted 151 | if (utmi_txready_i) 152 | begin 153 | if (data_zlp_q) 154 | next_state_r = STATE_TX_CRC1; 155 | else if (data_pid_q) 156 | next_state_r = STATE_TX_DATA; 157 | else 158 | next_state_r = STATE_TX_DONE; 159 | end 160 | end 161 | 162 | //----------------------------------------- 163 | // TX_DATA 164 | //----------------------------------------- 165 | STATE_TX_DATA : 166 | begin 167 | // Data accepted 168 | if (utmi_txready_i) 169 | begin 170 | // Generate CRC16 at end of packet 171 | if (data_last_i) 172 | next_state_r = STATE_TX_CRC1; 173 | end 174 | end 175 | 176 | //----------------------------------------- 177 | // TX_CRC1 (first byte) 178 | //----------------------------------------- 179 | STATE_TX_CRC1 : 180 | begin 181 | // Data sent? 182 | if (utmi_txready_i) 183 | next_state_r = STATE_TX_CRC2; 184 | end 185 | 186 | //----------------------------------------- 187 | // TX_CRC (second byte) 188 | //----------------------------------------- 189 | STATE_TX_CRC2 : 190 | begin 191 | // Data sent? 192 | if (utmi_txready_i) 193 | next_state_r = STATE_TX_DONE; 194 | end 195 | 196 | //----------------------------------------- 197 | // TX_DONE 198 | //----------------------------------------- 199 | STATE_TX_DONE : 200 | begin 201 | // Data sent? 202 | if (!utmi_txvalid_o || utmi_txready_i) 203 | next_state_r = STATE_TX_IDLE; 204 | end 205 | 206 | //----------------------------------------- 207 | // TX_CHIRP 208 | //----------------------------------------- 209 | STATE_TX_CHIRP : 210 | begin 211 | if (!chirp_i) 212 | next_state_r = STATE_TX_IDLE; 213 | end 214 | 215 | default : 216 | ; 217 | 218 | endcase 219 | 220 | // USB reset but not chirping... 221 | if (!enable_i && !chirp_i) 222 | next_state_r = STATE_TX_IDLE; 223 | end 224 | 225 | // Update state 226 | always @ (posedge clk_i or posedge rst_i) 227 | if (rst_i) 228 | state_q <= STATE_TX_IDLE; 229 | else 230 | state_q <= next_state_r; 231 | 232 | //----------------------------------------------------------------- 233 | // Data Input 234 | //----------------------------------------------------------------- 235 | reg input_valid_r; 236 | reg [7:0] input_byte_r; 237 | reg input_last_r; 238 | always @ * 239 | begin 240 | input_valid_r = data_strb_i & data_pid_q; 241 | input_byte_r = data_i; 242 | input_last_r = data_last_i; 243 | end 244 | 245 | reg data_accept_r; 246 | always @ * 247 | begin 248 | if (state_q == STATE_TX_DATA) 249 | data_accept_r = utmi_txready_i; 250 | else if (state_q == STATE_TX_PID && data_zlp_q) 251 | data_accept_r = utmi_txready_i; 252 | else 253 | data_accept_r = 1'b0; 254 | end 255 | 256 | assign data_accept_o = data_accept_r; 257 | 258 | //----------------------------------------------------------------- 259 | // CRC16: Generate CRC16 on outgoing data 260 | //----------------------------------------------------------------- 261 | reg [15:0] crc_sum_q; 262 | wire [15:0] crc_out_w; 263 | reg crc_err_q; 264 | 265 | usbf_crc16 266 | u_crc16 267 | ( 268 | .crc_in_i(crc_sum_q), 269 | .din_i(utmi_data_o), 270 | .crc_out_o(crc_out_w) 271 | ); 272 | 273 | always @ (posedge clk_i or posedge rst_i) 274 | if (rst_i) 275 | crc_sum_q <= 16'hFFFF; 276 | else if (state_q == STATE_TX_IDLE) 277 | crc_sum_q <= 16'hFFFF; 278 | else if (state_q == STATE_TX_DATA && utmi_txvalid_o && utmi_txready_i) 279 | crc_sum_q <= crc_out_w; 280 | 281 | //----------------------------------------------------------------- 282 | // Output 283 | //----------------------------------------------------------------- 284 | reg valid_q; 285 | reg [7:0] data_q; 286 | 287 | always @ (posedge clk_i or posedge rst_i) 288 | if (rst_i) 289 | begin 290 | valid_q <= 1'b0; 291 | data_q <= 8'b0; 292 | end 293 | else if (!enable_i) 294 | begin 295 | valid_q <= 1'b0; 296 | data_q <= 8'b0; 297 | end 298 | else if (tx_valid_i && tx_accept_o) 299 | begin 300 | valid_q <= 1'b1; 301 | data_q <= tx_pid_i; 302 | end 303 | else if (utmi_txready_i) 304 | begin 305 | valid_q <= 1'b0; 306 | data_q <= 8'b0; 307 | end 308 | 309 | reg utmi_txvalid_r; 310 | reg [7:0] utmi_data_r; 311 | 312 | always @ * 313 | begin 314 | if (state_q == STATE_TX_CHIRP) 315 | begin 316 | utmi_txvalid_r = 1'b1; 317 | utmi_data_r = 8'b0; 318 | end 319 | else if (state_q == STATE_TX_CRC1) 320 | begin 321 | utmi_txvalid_r = 1'b1; 322 | utmi_data_r = crc_sum_q[7:0] ^ 8'hFF; 323 | end 324 | else if (state_q == STATE_TX_CRC2) 325 | begin 326 | utmi_txvalid_r = 1'b1; 327 | utmi_data_r = crc_sum_q[15:8] ^ 8'hFF; 328 | end 329 | else if (state_q == STATE_TX_DATA) 330 | begin 331 | utmi_txvalid_r = data_valid_i; 332 | utmi_data_r = data_i; 333 | end 334 | else 335 | begin 336 | utmi_txvalid_r = valid_q; 337 | utmi_data_r = data_q; 338 | end 339 | end 340 | 341 | assign utmi_txvalid_o = utmi_txvalid_r; 342 | assign utmi_data_o = utmi_data_r; 343 | 344 | 345 | endmodule 346 | --------------------------------------------------------------------------------