URL
https://opencores.org/ocsvn/usb_device_core/usb_device_core/trunk
Subversion Repositories usb_device_core
Compare Revisions
- This comparison shows the changes necessary to convert path
/usb_device_core
- from Rev 5 to Rev 4
- ↔ Reverse comparison
Rev 5 → Rev 4
/trunk/README.md
File deleted
/trunk/src_v/usbf_device_core.v
File deleted
/trunk/src_v/usbf_sie_rx.v
File deleted
/trunk/src_v/usbf_sie_tx.v
File deleted
/trunk/src_v/usbf_crc16.v
File deleted
/trunk/src_v/usbf_device.v
File deleted
/trunk/src_v/usbf_device_defs.v
File deleted
/trunk/src_v/usbf_defs.v
File deleted
/trunk/src_v/usbf_fifo.v
File deleted
/trunk/src_v/usbf_sie_ep.v
File deleted
/trunk/sw/usbf_defs.h
File deleted
/trunk/sw/usbf_hw.c
File deleted
\ No newline at end of file
/trunk/sw/usbf_hw.h
File deleted
/trunk/sw/example.c
File deleted
/trunk/sw/usb_defs.h
0,0 → 1,86
#ifndef __USB_DEFS_H__ |
#define __USB_DEFS_H__ |
|
//----------------------------------------------------------------- |
// Macros: |
//----------------------------------------------------------------- |
|
// For Big Endian CPUs |
#define USB_BYTE_SWAP16(n) ((((unsigned short)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8)) |
|
#define LO_BYTE(w) ((unsigned char)(w)) |
#define HI_BYTE(w) ((unsigned char)(((unsigned short)(w) >> 8) & 0xFF)) |
|
#define MIN(a,b) ((a)<=(b)?(a):(b)) |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
|
// Device class |
#define DEV_CLASS_RESERVED 0x00 |
#define DEV_CLASS_AUDIO 0x01 |
#define DEV_CLASS_COMMS 0x02 |
#define DEV_CLASS_HID 0x03 |
#define DEV_CLASS_MONITOR 0x04 |
#define DEV_CLASS_PHY_IF 0x05 |
#define DEV_CLASS_POWER 0x06 |
#define DEV_CLASS_PRINTER 0x07 |
#define DEV_CLASS_STORAGE 0x08 |
#define DEV_CLASS_HUB 0x09 |
#define DEV_CLASS_TMC 0xFE |
#define DEV_CLASS_VENDOR_CUSTOM 0xFF |
|
// Standard requests (via SETUP packets) |
#define REQ_GET_STATUS 0x00 |
#define REQ_CLEAR_FEATURE 0x01 |
#define REQ_SET_FEATURE 0x03 |
#define REQ_SET_ADDRESS 0x05 |
#define REQ_GET_DESCRIPTOR 0x06 |
#define REQ_SET_DESCRIPTOR 0x07 |
#define REQ_GET_CONFIGURATION 0x08 |
#define REQ_SET_CONFIGURATION 0x09 |
#define REQ_GET_INTERFACE 0x0A |
#define REQ_SET_INTERFACE 0x0B |
#define REQ_SYNC_FRAME 0x0C |
|
// Descriptor types |
#define DESC_DEVICE 0x01 |
#define DESC_CONFIGURATION 0x02 |
#define DESC_STRING 0x03 |
#define DESC_INTERFACE 0x04 |
#define DESC_ENDPOINT 0x05 |
#define DESC_DEV_QUALIFIER 0x06 |
#define DESC_OTHER_SPEED_CONF 0x07 |
#define DESC_IF_POWER 0x08 |
|
// Endpoints |
#define ENDPOINT_DIR_MASK (1 << 7) |
#define ENDPOINT_DIR_IN (1 << 7) |
#define ENDPOINT_DIR_OUT (0 << 7) |
#define ENDPOINT_ADDR_MASK (0x7F) |
#define ENDPOINT_TYPE_MASK (0x3) |
#define ENDPOINT_TYPE_CONTROL (0) |
#define ENDPOINT_TYPE_ISO (1) |
#define ENDPOINT_TYPE_BULK (2) |
#define ENDPOINT_TYPE_INTERRUPT (3) |
|
// Device Requests (bmRequestType) |
#define USB_RECIPIENT_MASK 0x1F |
#define USB_RECIPIENT_DEVICE 0x00 |
#define USB_RECIPIENT_INTERFACE 0x01 |
#define USB_RECIPIENT_ENDPOINT 0x02 |
#define USB_REQUEST_TYPE_MASK 0x60 |
#define USB_STANDARD_REQUEST 0x00 |
#define USB_CLASS_REQUEST 0x20 |
#define USB_VENDOR_REQUEST 0x40 |
|
// USB device addresses are 7-bits |
#define USB_ADDRESS_MASK 0x7F |
|
// USB Feature Selectors |
#define USB_FEATURE_ENDPOINT_STATE 0x0000 |
#define USB_FEATURE_REMOTE_WAKEUP 0x0001 |
#define USB_FEATURE_TEST_MODE 0x0002 |
|
#endif |
/trunk/sw/usb_log.h
5,8 → 5,8
// Defines: |
//----------------------------------------------------------------- |
#define USBLOG_HW_RESET 1 |
#define USBLOG_HW_CTRL 7 |
#define USBLOG_HW_DATA 9 |
#define USBLOG_HW_CTRL 9 |
#define USBLOG_HW_DATA 7 |
#define USBLOG_CONTROL 9 |
#define USBLOG_SETUP_DATA 9 |
#define USBLOG_SETUP 8 |
23,10 → 23,6
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
#ifdef HAS_USB_DEVICE_LOG |
extern int log_printf(int level, const char* ctrl1, ... ); |
#else |
static int log_printf(int level, const char* ctrl1, ... ) { return 0; } |
#endif |
|
#endif |
/trunk/sw/usb_desc_cdc.c
1,35 → 1,41
//----------------------------------------------------------------- |
// USB CDC Device SW |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for use in |
// closed source commercial applications please contact me for details. |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// This file is part of USB CDC Device SW. |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// USB CDC Device SW is free software; you can redistribute it and/or modify |
// it under the terms of the GNU General Public License as published by |
// the Free Software Foundation; either version 2 of the License, or |
// (at your option) any later version. |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// USB CDC Device SW is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// You should have received a copy of the GNU General Public License |
// along with USB CDC Device SW; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include <stdlib.h> |
#include "usbf_defs.h" |
#include "usb_defs.h" |
#include "usb_desc.h" |
#include "usb_log.h" |
|
37,7 → 43,7
// PID/VID: |
//----------------------------------------------------------------- |
#ifndef USB_DEV_VID |
#define USB_DEV_VID 0x9234 |
#define USB_DEV_VID 0x1234 |
#endif |
#ifndef USB_DEV_PID |
#define USB_DEV_PID 0x5678 |
50,13 → 56,8
|
// Descriptor defs |
#define SIZE_OF_DEVICE_DESCR 18 |
#define EP0_MAX_PACKET_SIZE 8 |
|
#ifdef USB_SPEED_HS |
#define EP0_MAX_PACKET_SIZE 64 |
#else |
#define EP0_MAX_PACKET_SIZE 8 |
#endif |
|
// Configuration descriptor |
#define NB_INTERFACE 2 |
#define CONF_NB 1 |
76,11 → 77,7
// Endpoint 3 descriptor (INTR-IN) |
#define ENDPOINT_ID_3 0x83 |
#define EP_ATTRIBUTES_3 0x03 |
#ifdef USB_SPEED_HS |
#define EP_SIZE_3 64 // TODO: Should be 512 for HS??? |
#else |
#define EP_SIZE_3 64 |
#endif |
#define EP_SIZE_3 64 |
#define EP_INTERVAL_3 2 |
|
// Interface 1 descriptor |
95,21 → 92,13
// Endpoint 1 descriptor |
#define ENDPOINT_ID_1 0x01 |
#define EP_ATTRIBUTES_1 0x02 |
#ifdef USB_SPEED_HS |
#define EP_SIZE_1 512 |
#else |
#define EP_SIZE_1 64 |
#endif |
#define EP_SIZE_1 64 |
#define EP_INTERVAL_1 0x00 |
|
// Endpoint 2 descriptor |
#define ENDPOINT_ID_2 0x82 |
#define EP_ATTRIBUTES_2 0x02 |
#ifdef USB_SPEED_HS |
#define EP_SIZE_2 512 |
#else |
#define EP_SIZE_2 64 |
#endif |
#define EP_SIZE_2 64 |
#define EP_INTERVAL_2 0x00 |
|
// String Descriptors |
/trunk/sw/hardware.h
0,0 → 1,17
#ifndef __HARDWARE_H__ |
#define __HARDWARE_H__ |
|
// NOTE: Update to match actual addresses in your system! |
|
#ifndef TIMER_HW_VAL |
// TODO: Update to match address of timer peripheral |
// Expected to return time in ms |
#define TIMER_HW_VAL (*((volatile unsigned int*) (0x12000100))) |
#endif |
|
#ifndef USB_FUNC_BASE |
// TODO: Update to match address of USB device core |
#define USB_FUNC_BASE 0x13000000 |
#endif |
|
#endif |
/trunk/sw/usb_cdc.c
1,39 → 1,44
//----------------------------------------------------------------- |
// USB CDC Device SW |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for use in |
// closed source commercial applications please contact me for details. |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// This file is part of USB CDC Device SW. |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// USB CDC Device SW is free software; you can redistribute it and/or modify |
// it under the terms of the GNU General Public License as published by |
// the Free Software Foundation; either version 2 of the License, or |
// (at your option) any later version. |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// USB CDC Device SW is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// You should have received a copy of the GNU General Public License |
// along with USB CDC Device SW; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include <stdlib.h> |
#include "usbf_defs.h" |
#include "usb_defs.h" |
#include "usb_cdc.h" |
#include "usb_log.h" |
#include "usb_device.h" |
#include "usbf_hw.h" |
|
//----------------------------------------------------------------- |
// Locals: |
55,11 → 60,11
//----------------------------------------------------------------- |
// cdc_get_line_coding: |
//----------------------------------------------------------------- |
static void cdc_get_line_coding(unsigned short wLength) |
static void cdc_get_line_coding(void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Get Line Coding\n"); |
|
usb_control_send( _line_coding, sizeof(_line_coding), wLength ); |
usb_control_send( _line_coding, sizeof(_line_coding) ); |
} |
//----------------------------------------------------------------- |
// cdc_set_control_line_state: |
87,7 → 92,7
//----------------------------------------------------------------- |
// cdc_get_encapsulated_response: |
//----------------------------------------------------------------- |
static void cdc_get_encapsulated_response (unsigned short wLength) |
static void cdc_get_encapsulated_response (void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Get encap\n"); |
|
94,9 → 99,9
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// usb_cdc_process_request: |
// cdc_process_request: |
//----------------------------------------------------------------- |
void usb_cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength) |
void cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength) |
{ |
switch ( req ) |
{ |
106,7 → 111,7
break; |
case CDC_GET_ENCAPSULATED_RESPONSE: |
log_printf(USBLOG_CDC_INFO, "CDC: Get encap\n"); |
cdc_get_encapsulated_response(wLength); |
cdc_get_encapsulated_response(); |
break; |
case CDC_SET_LINE_CODING: |
log_printf(USBLOG_CDC_INFO, "CDC: Set line coding\n"); |
114,7 → 119,7
break; |
case CDC_GET_LINE_CODING: |
log_printf(USBLOG_CDC_INFO, "CDC: Get line coding\n"); |
cdc_get_line_coding(wLength); |
cdc_get_line_coding(); |
break; |
case CDC_SET_CONTROL_LINE_STATE: |
log_printf(USBLOG_CDC_INFO, "CDC: Set line state\n"); |
131,9 → 136,9
} |
} |
//----------------------------------------------------------------- |
// usb_cdc_init: |
// cdc_init: |
//----------------------------------------------------------------- |
void usb_cdc_init(void) |
void cdc_init(void) |
{ |
_line_coding[0] = 0x00; // UART baud rate (32-bit word, LSB first) |
_line_coding[1] = 0xC2; |
/trunk/sw/main.c
0,0 → 1,67
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <stdio.h> |
#include "usb_uart.h" |
#include "usb_cdc.h" |
#include "usb_hw.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// CDC serial demo |
//----------------------------------------------------------------- |
int main(void) |
{ |
// Force detach |
usbhw_attach(0); |
timer_sleep(100); |
|
// USB init |
usb_init(0, cdc_process_request); |
usb_uart_init(); |
|
usbhw_attach(1); |
|
while (1) |
{ |
usbhw_service(); |
|
// Loopback |
if (usb_uart_haschar()) |
usb_uart_putchar(usb_uart_getchar()); |
} |
|
return 0; |
} |
/trunk/sw/usb_uart.c
1,39 → 1,46
//----------------------------------------------------------------- |
// USB CDC Device SW |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for use in |
// closed source commercial applications please contact me for details. |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// This file is part of USB CDC Device SW. |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// USB CDC Device SW is free software; you can redistribute it and/or modify |
// it under the terms of the GNU General Public License as published by |
// the Free Software Foundation; either version 2 of the License, or |
// (at your option) any later version. |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// USB CDC Device SW is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// You should have received a copy of the GNU General Public License |
// along with USB CDC Device SW; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include "usbf_hw.h" |
#include "usb_hw.h" |
#include "usb_cdc.h" |
#include "usb_device.h" |
#include "usb_uart.h" |
#include "usb_log.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// Defines: |
54,7 → 61,7
_tx_count = 0; |
_rx_count = 0; |
|
usb_cdc_init(); |
cdc_init(); |
} |
//----------------------------------------------------------------- |
// usb_uart_haschar: |
122,34 → 129,6
return count; |
} |
//----------------------------------------------------------------- |
// usb_uart_putblock: |
//----------------------------------------------------------------- |
int usb_uart_putblock(unsigned char *data, int length) |
{ |
int count = 0; |
|
do |
{ |
int chunk = length; |
|
// Wait until space available (or timeout) |
t_time tS = usbhw_timer_now(); |
while (!usbhw_has_tx_space(CDC_ENDPOINT_BULK_IN)) |
{ |
if (usbhw_timer_diff(usbhw_timer_now(), tS) > USB_UART_TX_TIMEOUT) |
return 0; |
} |
|
usbhw_load_tx_buffer(CDC_ENDPOINT_BULK_IN, data, chunk); |
|
count += chunk; |
data += chunk; |
} |
while (count < length); |
|
return length; |
} |
//----------------------------------------------------------------- |
// usb_uart_putchar: |
//----------------------------------------------------------------- |
int usb_uart_putchar(char data) |
158,10 → 137,10
usb_uart_putchar('\r'); |
|
// Wait until space available (or timeout) |
t_time tS = usbhw_timer_now(); |
t_time tS = timer_now(); |
while (!usbhw_has_tx_space(CDC_ENDPOINT_BULK_IN)) |
{ |
if (usbhw_timer_diff(usbhw_timer_now(), tS) > USB_UART_TX_TIMEOUT) |
if (timer_diff(timer_now(), tS) > USB_UART_TX_TIMEOUT) |
return 0; |
} |
|
189,12 → 168,12
// If multiple of endpoint size, send ZLP |
if ( _tx_count == EP2_MAX_PACKET_SIZE ) |
{ |
t_time tS = usbhw_timer_now(); |
t_time tS = timer_now(); |
|
// Wait for TX ready and then send ZLP |
while (!usbhw_has_tx_space(CDC_ENDPOINT_BULK_IN)) |
{ |
if (usbhw_timer_diff(usbhw_timer_now(), tS) > USB_UART_TX_TIMEOUT) |
if (timer_diff(timer_now(), tS) > USB_UART_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "UART: Flush timeout\n"); |
return ; |
/trunk/sw/timer.h
1,14 → 1,24
#ifndef __TIMER_H__ |
#define __TIMER_H__ |
|
#include "hardware.h" |
|
//----------------------------------------------------------------- |
// Types |
// Defines: |
//----------------------------------------------------------------- |
typedef unsigned long t_time; |
typedef unsigned long t_time; |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static t_time timer_now(void) { return TIMER_HW_VAL; } |
static long timer_diff(t_time a, t_time b) { return (long)(a - b); } |
static void timer_sleep(int timeMs) |
{ |
t_time t = timer_now(); |
|
// TODO: Implementation specific millisecond timer... |
static t_time timer_now(void) { return 0; } |
static void timer_sleep(int timeMs) { } |
while (timer_diff(timer_now(), t) < timeMs) |
; |
} |
|
#endif |
/trunk/sw/usb_cdc.h
18,15 → 18,7
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
#ifdef __cplusplus |
extern "C" { |
#endif |
void cdc_init( void ); |
void cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength); |
|
void usb_cdc_init( void ); |
void usb_cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength); |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif |
/trunk/sw/usb_hw.c
0,0 → 1,376
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include "usb_hw.h" |
#include "usb_log.h" |
#include "hardware.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define USB_FUNC_CTRL (*((volatile unsigned int*) (USB_FUNC_BASE + 0x00))) |
#define USB_FUNC_CTRL_ADDR_SET (1 << 8) |
#define USB_FUNC_CTRL_ADDR_MASK (0x7F) |
#define USB_FUNC_CTRL_ADDR_SHIFT 0 |
#define USB_FUNC_CTRL_INT_EN_TX (1 << 9) |
#define USB_FUNC_CTRL_INT_EN_RX (1 << 10) |
#define USB_FUNC_CTRL_INT_EN_SOF (1 << 11) |
#define USB_FUNC_CTRL_PULLUP_EN (1 << 12) |
#define USB_FUNC_STAT (*((volatile unsigned int*) (USB_FUNC_BASE + 0x00))) |
#define USB_STAT_BUS_RST (1 << 18) |
#define USB_LINESTATE_RXN (1 << 17) |
#define USB_LINESTATE_RXP (1 << 16) |
#define USB_FUNC_FRAME_COUNT 0x07FF |
|
#define USB_FUNC_EP(x) (*((volatile unsigned int*) (USB_FUNC_BASE + 0x04 + (4 * x)))) |
#define USB_FUNC_EP0 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x04))) |
#define USB_FUNC_EP1 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x08))) |
#define USB_FUNC_EP2 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x0C))) |
#define USB_FUNC_EP3 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x10))) |
#define USB_EP_TX_READY (1 << 16) |
#define USB_EP_COUNT_MASK 0xFFFF |
#define USB_EP_RX_AVAIL (1 << 17) |
#define USB_EP_RX_SETUP (1 << 18) |
#define USB_EP_RX_ACK (1 << 18) |
#define USB_EP_RX_CRC_ERR (1 << 19) |
#define USB_EP_STALL (1 << 20) |
#define USB_EP_TX_FLUSH (1 << 21) |
|
#define USB_FUNC_EP_DATA(x) (*((volatile unsigned int*) (USB_FUNC_BASE + 0x20 + (4 * x)))) |
#define USB_FUNC_EP0_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x20))) |
#define USB_FUNC_EP1_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x24))) |
#define USB_FUNC_EP2_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x28))) |
#define USB_FUNC_EP3_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x2C))) |
|
#define USB_FUNC_ENDPOINTS 4 |
|
#define MIN(a,b) ((a)<=(b)?(a):(b)) |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static unsigned int _tx_count[USB_FUNC_ENDPOINTS]; |
static int _configured; |
static int _attached; |
static int _endpoint_stalled[USB_FUNC_ENDPOINTS]; |
static FUNC_PTR _func_bus_reset; |
static FUNC_PTR _func_setup; |
static FUNC_PTR _func_ctrl_out; |
static unsigned int _pullup_enable; |
static unsigned int _ctrl_reg; |
|
//----------------------------------------------------------------- |
// usbhw_init: |
//----------------------------------------------------------------- |
void usbhw_init(FUNC_PTR bus_reset, FUNC_PTR on_setup, FUNC_PTR on_out) |
{ |
int i; |
|
for (i=0;i<USB_FUNC_ENDPOINTS;i++) |
{ |
_tx_count[i] = 0; |
_endpoint_stalled[i] = 0; |
} |
|
_configured = 0; |
_attached = 0; |
|
_ctrl_reg = 0; |
|
_func_bus_reset = bus_reset; |
_func_setup = on_setup; |
_func_ctrl_out = on_out; |
|
USB_FUNC_EP0 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP1 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP2 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP3 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
} |
//----------------------------------------------------------------- |
// usbhw_service: |
//----------------------------------------------------------------- |
void usbhw_service(void) |
{ |
unsigned int status; |
|
// Bus reset event |
if (USB_FUNC_STAT & USB_STAT_BUS_RST) |
{ |
// Ack bus reset by writing to CTRL register |
USB_FUNC_CTRL = _ctrl_reg; |
|
_configured = 0; |
|
log_printf(USBLOG_HW_RESET, " DEVICE: BUS RESET\n"); |
|
if (_func_bus_reset) |
_func_bus_reset(); |
} |
|
status = USB_FUNC_EP0; |
|
// SETUP packet received (EP0) |
if (status & USB_EP_RX_SETUP) |
{ |
log_printf(USBLOG_HW_CTRL, "USB: SETUP packet received\n"); |
|
if (_func_setup) |
_func_setup(); |
|
log_printf(USBLOG_HW_CTRL, "USB: SETUP packet processed\n"); |
} |
// OUT data received on EP0 |
else if (status & USB_EP_RX_AVAIL) |
{ |
log_printf(USBLOG_HW_CTRL, "USB: OUT packet received on EP0\n"); |
|
if (_func_ctrl_out) |
_func_ctrl_out(); |
} |
} |
//----------------------------------------------------------------- |
// usbhw_attach: |
//----------------------------------------------------------------- |
void usbhw_attach(int state) |
{ |
// Pull up D+ to Vdd |
if ( state ) |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: ATTACH\n"); |
_attached = 1; |
_ctrl_reg |= USB_FUNC_CTRL_PULLUP_EN; |
USB_FUNC_CTRL = _ctrl_reg; |
} |
// Disconnect pull-up to disconnect from bus |
else |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: DETACH\n"); |
_attached = 0; |
_ctrl_reg &= ~USB_FUNC_CTRL_PULLUP_EN; |
USB_FUNC_CTRL = _ctrl_reg; |
} |
} |
//----------------------------------------------------------------- |
// usbhw_is_configured: |
//----------------------------------------------------------------- |
int usbhw_is_configured(void) |
{ |
return _configured; |
} |
//----------------------------------------------------------------- |
// usbhw_is_attached: |
//----------------------------------------------------------------- |
int usbhw_is_attached(void) |
{ |
return _attached; |
} |
//----------------------------------------------------------------- |
// usbhw_set_configured: |
//----------------------------------------------------------------- |
void usbhw_set_configured(int configured) |
{ |
_configured = configured; |
} |
//----------------------------------------------------------------- |
// usbhw_set_address: |
//----------------------------------------------------------------- |
void usbhw_set_address(unsigned char addr) |
{ |
USB_FUNC_CTRL = (_attached ? USB_FUNC_CTRL_PULLUP_EN : 0) | |
USB_FUNC_CTRL_ADDR_SET | ((addr & USB_FUNC_CTRL_ADDR_MASK) >> USB_FUNC_CTRL_ADDR_SHIFT); |
} |
//----------------------------------------------------------------- |
// usbhw_is_endpoint_stalled: |
//----------------------------------------------------------------- |
int usbhw_is_endpoint_stalled(unsigned char endpoint) |
{ |
return _endpoint_stalled[endpoint]; |
} |
//----------------------------------------------------------------- |
// usbhw_clear_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_clear_endpoint_stall(unsigned char endpoint) |
{ |
_endpoint_stalled[endpoint] = 0; |
USB_FUNC_EP(endpoint) = 0; |
} |
//----------------------------------------------------------------- |
// usbhw_set_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_set_endpoint_stall(unsigned char endpoint) |
{ |
_endpoint_stalled[endpoint] = 1; |
USB_FUNC_EP(endpoint) = USB_EP_STALL; |
} |
//----------------------------------------------------------------- |
// usbhw_is_rx_ready: Is some receive data ready on an endpoint? |
//----------------------------------------------------------------- |
int usbhw_is_rx_ready(unsigned char endpoint) |
{ |
return (USB_FUNC_EP(endpoint) & USB_EP_RX_AVAIL) ? 1 : 0; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_count: Get amount of data waiting in endpoint |
//----------------------------------------------------------------- |
int usbhw_get_rx_count(unsigned char bEndp) |
{ |
int count = USB_FUNC_EP(bEndp) & USB_EP_COUNT_MASK; |
|
// Received data count includes CRC |
if (count >= 2) |
return count - 2; |
else |
return 0; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_data: Read data from endpoint & clear full flag |
//----------------------------------------------------------------- |
int usbhw_get_rx_data(unsigned char endpoint, unsigned char *data, int max_len) |
{ |
int i; |
int bytes_ready; |
int bytes_read = 0; |
|
// Received data count includes CRC |
bytes_ready = USB_FUNC_EP(endpoint) & USB_EP_COUNT_MASK; |
if (bytes_ready >= 2) |
bytes_ready -= 2; |
|
// Limit data read to buffer size |
bytes_read = MIN(bytes_ready, max_len); |
|
for (i=0;i<bytes_read;i++) |
{ |
*data++ = (unsigned char) USB_FUNC_EP_DATA(endpoint); |
} |
|
// Allow more data to be received |
usbhw_clear_rx_ready( endpoint ); |
|
// Return number of bytes read |
return bytes_read; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_byte: Read byte from endpoint |
//----------------------------------------------------------------- |
unsigned char usbhw_get_rx_byte(unsigned char endpoint) |
{ |
return (unsigned char)USB_FUNC_EP_DATA(endpoint); |
} |
//----------------------------------------------------------------- |
// usbhw_clear_rx_ready: Clear Rx data ready flag |
//----------------------------------------------------------------- |
void usbhw_clear_rx_ready(unsigned char endpoint) |
{ |
log_printf(USBLOG_HW_DATA, "USB: Clear endpoint buffer (Rx %d)\n", USB_FUNC_EP(endpoint) & USB_EP_COUNT_MASK); |
USB_FUNC_EP(endpoint) = USB_EP_RX_ACK; |
} |
//----------------------------------------------------------------- |
// usbhw_has_tx_space: Is there space in the tx buffer |
//----------------------------------------------------------------- |
int usbhw_has_tx_space(unsigned char endpoint) |
{ |
return (USB_FUNC_EP(endpoint) & USB_EP_TX_READY) ? 0 : 1; |
} |
//----------------------------------------------------------------- |
// usbhw_load_tx_buffer: Load tx buffer & start transfer (non-blocking) |
//----------------------------------------------------------------- |
int usbhw_load_tx_buffer(unsigned char endpoint, unsigned char *data, int count) |
{ |
int i; |
|
for (i=0;i<count;i++) |
USB_FUNC_EP_DATA(endpoint) = *data++; |
|
// Start transmit |
USB_FUNC_EP(endpoint) = USB_EP_TX_READY | count; |
|
log_printf(USBLOG_HW_DATA, " USB: Tx %d\n", count); |
|
return count; |
} |
//----------------------------------------------------------------- |
// usbhw_write_tx_byte: Write a byte to Tx buffer (don't send yet) |
//----------------------------------------------------------------- |
void usbhw_write_tx_byte(unsigned char endpoint, unsigned char data) |
{ |
// If FIFO should be empty |
if (_tx_count[endpoint] == 0 && |
!(USB_FUNC_EP(endpoint) & USB_EP_TX_READY)) |
{ |
// (Shouldn't need this) Flush Tx FIFO |
USB_FUNC_EP(endpoint) = USB_EP_TX_FLUSH; |
} |
|
USB_FUNC_EP_DATA(endpoint) = (unsigned int) data; |
_tx_count[endpoint]++; |
} |
//----------------------------------------------------------------- |
// usbhw_start_tx: Start a tx packet with data loaded into endpoint |
//----------------------------------------------------------------- |
void usbhw_start_tx(unsigned char endpoint) |
{ |
// Initiate TX |
USB_FUNC_EP(endpoint) = USB_EP_TX_READY | _tx_count[endpoint]; |
log_printf(USBLOG_HW_DATA, " USB: Tx %d\n", _tx_count[endpoint]); |
|
_tx_count[endpoint] = 0; |
} |
//----------------------------------------------------------------- |
// usbhw_control_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_control_endpoint_stall(void) |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: Error, send EP stall!\n"); |
USB_FUNC_EP0 = USB_EP_STALL; |
} |
//----------------------------------------------------------------- |
// usbhw_control_endpoint_ack: |
//----------------------------------------------------------------- |
void usbhw_control_endpoint_ack(void) |
{ |
USB_FUNC_EP0 = USB_EP_TX_READY; |
log_printf(USBLOG_HW_DATA, " USB: Tx [ZLP/ACK]\n"); |
|
while (!usbhw_has_tx_space(0)) |
; |
} |
//----------------------------------------------------------------- |
// usbhw_get_frame_number: |
//----------------------------------------------------------------- |
unsigned short usbhw_get_frame_number(void) |
{ |
return (unsigned short)(USB_FUNC_STAT & USB_FUNC_FRAME_COUNT); |
} |
/trunk/sw/usb_device.c
1,38 → 1,45
//----------------------------------------------------------------- |
// USB CDC Device SW |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for use in |
// closed source commercial applications please contact me for details. |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// This file is part of USB CDC Device SW. |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// USB CDC Device SW is free software; you can redistribute it and/or modify |
// it under the terms of the GNU General Public License as published by |
// the Free Software Foundation; either version 2 of the License, or |
// (at your option) any later version. |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// USB CDC Device SW is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// You should have received a copy of the GNU General Public License |
// along with USB CDC Device SW; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include "usb_device.h" |
#include "usb_desc.h" |
#include "usb_log.h" |
#include "usbf_defs.h" |
#include "usbf_hw.h" |
#include "usb_defs.h" |
#include "usb_hw.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// Defines: |
99,17 → 106,17
if (_remote_wake_enabled) |
data[0] |= (1 << 1); |
|
usb_control_send( data, 2, request->wLength ); |
usb_control_send( data, 2 ); |
} |
else if ( bRecipient == USB_RECIPIENT_INTERFACE ) |
{ |
usb_control_send( data, 2, request->wLength ); |
usb_control_send( data, 2 ); |
} |
else if ( bRecipient == USB_RECIPIENT_ENDPOINT ) |
{ |
if (usbhw_is_endpoint_stalled( request->wIndex & ENDPOINT_ADDR_MASK)) |
data[0] = 1; |
usb_control_send( data, 2, request->wLength ); |
usb_control_send( data, 2 ); |
} |
else |
usbhw_control_endpoint_stall(); |
208,7 → 215,7
desc_ptr = usb_get_descriptor(bDescriptorType, bDescriptorIndex, wLength, &bCount); |
|
if (desc_ptr) |
usb_control_send(desc_ptr, bCount, request->wLength); |
usb_control_send(desc_ptr, bCount); |
else |
usbhw_control_endpoint_stall(); |
} |
221,7 → 228,7
|
log_printf(USBLOG_INFO, "USB: Get configuration %x\n", conf); |
|
usb_control_send( &conf, 1, request->wLength ); |
usb_control_send( &conf, 1 ); |
} |
//----------------------------------------------------------------- |
// set_configuration: |
331,7 → 338,6
unsigned char setup_pkt[EP0_MAX_PACKET_SIZE]; |
|
usbhw_get_rx_data(ENDPOINT_CONTROL, setup_pkt, EP0_MAX_PACKET_SIZE); |
usbhw_clear_rx_ready(ENDPOINT_CONTROL); |
|
#if (LOG_LEVEL >= USBLOG_SETUP_DATA) |
{ |
438,7 → 444,6
else |
{ |
usbhw_get_rx_data(ENDPOINT_CONTROL, &_ctrl_xfer.data_buffer[_ctrl_xfer.data_idx], received); |
usbhw_clear_rx_ready(ENDPOINT_CONTROL); |
_ctrl_xfer.data_idx += received; |
|
log_printf(USBLOG_SETUP_OUT, "USB: OUT packet re-assembled %d\n", _ctrl_xfer.data_idx); |
467,7 → 472,7
//----------------------------------------------------------------- |
// usb_control_send: Perform a transfer via IN |
//----------------------------------------------------------------- |
int usb_control_send(unsigned char *buf, int size, int requested_size) |
int usb_control_send(unsigned char *buf, int size) |
{ |
t_time tS; |
int send; |
485,10 → 490,6
|
log_printf(USBLOG_SETUP_IN_DBG, " Remain %d, Send %d\n", remain, send); |
|
// Do not send ZLP if requested size was size transferred |
if (remain == 0 && size == requested_size) |
break; |
|
usbhw_load_tx_buffer(ENDPOINT_CONTROL, buf, (unsigned char) send); |
|
buf += send; |
496,22 → 497,15
|
log_printf(USBLOG_SETUP_IN_DBG, " Sent %d, Remain %d\n", send, (size - count)); |
|
tS = usbhw_timer_now(); |
tS = timer_now(); |
while ( !usbhw_has_tx_space( ENDPOINT_CONTROL ) ) |
{ |
if (usbhw_timer_diff(usbhw_timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
if (timer_diff(timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "USB: Timeout sending IN data\n"); |
err = 1; |
break; |
} |
|
// Give up on early OUT (STATUS stage) |
if (usbhw_is_rx_ready(ENDPOINT_CONTROL)) |
{ |
log_printf(USBLOG_ERR, "USB: Early ACK received...\n"); |
break; |
} |
} |
} |
} |
while (send >= EP0_MAX_PACKET_SIZE); |
521,10 → 515,10
log_printf(USBLOG_SETUP_IN, "USB: Sent total %d\n", count); |
|
// Wait for ACK from host |
tS = usbhw_timer_now(); |
tS = timer_now(); |
do |
{ |
if (usbhw_timer_diff(usbhw_timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
if (timer_diff(timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "USB: ACK not received\n"); |
err = 1; |
544,10 → 538,10
return !err; |
} |
//----------------------------------------------------------------- |
// usbf_init: |
// usb_init: |
//----------------------------------------------------------------- |
void usbf_init(unsigned int base, FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request) |
void usb_init(FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request) |
{ |
_class_request = class_request; |
usbhw_init(base, bus_reset, usb_process_setup, usb_process_out); |
usbhw_init(bus_reset, usb_process_setup, usb_process_out); |
} |
/trunk/sw/usb_uart.h
4,20 → 4,11
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
#ifdef __cplusplus |
extern "C" { |
#endif |
|
void usb_uart_init(void); |
int usb_uart_haschar(void); |
int usb_uart_getchar(void); |
int usb_uart_putblock(unsigned char *data, int length); |
int usb_uart_getblock(unsigned char *data, int max_length); |
int usb_uart_putchar(char txbyte); |
void usb_uart_flush(void); |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif |
/trunk/sw/usb_desc.h
4,15 → 4,7
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
#ifdef __cplusplus |
extern "C" { |
#endif |
|
unsigned char *usb_get_descriptor( unsigned char bDescriptorType, unsigned char bDescriptorIndex, unsigned short wLength, unsigned char *pSize ); |
int usb_is_bus_powered(void); |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif |
/trunk/sw/usb_hw.h
0,0 → 1,45
#ifndef __USB_HW_H__ |
#define __USB_HW_H__ |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#define ENDPOINT_CONTROL 0 |
|
#define EP0_MAX_PACKET_SIZE 8 |
#define EP1_MAX_PACKET_SIZE 64 |
#define EP2_MAX_PACKET_SIZE 64 |
#define EP3_MAX_PACKET_SIZE 64 |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
typedef void (*FUNC_PTR)(void); |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
void usbhw_init(FUNC_PTR bus_reset, FUNC_PTR on_setup, FUNC_PTR on_out); |
void usbhw_service(void); |
void usbhw_attach(int state); |
int usbhw_is_attached(void); |
int usbhw_is_configured(void); |
void usbhw_set_configured(int configured); |
void usbhw_set_address(unsigned char addr); |
int usbhw_is_endpoint_stalled(unsigned char endpoint); |
void usbhw_clear_endpoint_stall(unsigned char endpoint); |
void usbhw_set_endpoint_stall(unsigned char endpoint); |
int usbhw_is_rx_ready(unsigned char endpoint); |
int usbhw_get_rx_count(unsigned char endpoint); |
int usbhw_get_rx_data(unsigned char endpoint, unsigned char *data, int max_len); |
unsigned char usbhw_get_rx_byte(unsigned char endpoint); |
void usbhw_clear_rx_ready(unsigned char endpoint); |
int usbhw_has_tx_space(unsigned char endpoint); |
int usbhw_load_tx_buffer(unsigned char endpoint, unsigned char *data, int count); |
void usbhw_write_tx_byte(unsigned char endpoint, unsigned char data); |
void usbhw_start_tx(unsigned char endpoint); |
void usbhw_control_endpoint_stall(void); |
void usbhw_control_endpoint_ack(void); |
unsigned short usbhw_get_frame_number(void); |
|
#endif |
/trunk/sw/usb_device.h
10,15 → 10,7
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
#ifdef __cplusplus |
extern "C" { |
#endif |
void usb_init(FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request); |
int usb_control_send(unsigned char *buf, int size); |
|
void usbf_init(unsigned int base, FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request); |
int usb_control_send(unsigned char *buf, int size, int requested_size); |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif |
/trunk/rtl/phy/usb_rx_phy.v
0,0 → 1,447
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// RX & DPLL //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: usb_rx_phy.v,v 1.5 2004-10-19 09:29:07 rudi Exp $ |
// |
// $Date: 2004-10-19 09:29:07 $ |
// $Revision: 1.5 $ |
// $Author: rudi $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2003/12/02 04:56:00 rudi |
// Fixed a bug reported by Karl C. Posch from Graz University of Technology. Thanks Karl ! |
// |
// Revision 1.3 2003/10/19 18:07:45 rudi |
// - Fixed Sync Error to be only checked/generated during the sync phase |
// |
// Revision 1.2 2003/10/19 17:40:13 rudi |
// - Made core more robust against line noise |
// - Added Error Checking and Reporting |
// (See README.txt for more info) |
// |
// Revision 1.1.1.1 2002/09/16 14:27:01 rudi |
// Created Directory Structure |
// |
// |
// |
// |
// |
// |
// |
// |
|
module usb_rx_phy( clk, rst, fs_ce, |
|
// Transciever Interface |
rxd, rxdp, rxdn, |
|
// UTMI Interface |
RxValid_o, RxActive_o, RxError_o, DataIn_o, |
RxEn_i, LineState); |
|
input clk; |
input rst; |
output fs_ce; |
input rxd, rxdp, rxdn; |
output [7:0] DataIn_o; |
output RxValid_o; |
output RxActive_o; |
output RxError_o; |
input RxEn_i; |
output [1:0] LineState; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
reg rxd_s0, rxd_s1, rxd_s; |
reg rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r; |
reg rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r; |
reg synced_d; |
wire k, j, se0; |
reg rxd_r; |
reg rx_en; |
reg rx_active; |
reg [2:0] bit_cnt; |
reg rx_valid1, rx_valid; |
reg shift_en; |
reg sd_r; |
reg sd_nrzi; |
reg [7:0] hold_reg; |
wire drop_bit; // Indicates a stuffed bit |
reg [2:0] one_cnt; |
|
reg [1:0] dpll_state, dpll_next_state; |
reg fs_ce_d; |
reg fs_ce; |
wire change; |
wire lock_en; |
reg [2:0] fs_state, fs_next_state; |
reg rx_valid_r; |
reg sync_err_d, sync_err; |
reg bit_stuff_err; |
reg se0_r, byte_err; |
reg se0_s; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
assign RxActive_o = rx_active; |
assign RxValid_o = rx_valid; |
assign RxError_o = sync_err | bit_stuff_err | byte_err; |
assign DataIn_o = hold_reg; |
assign LineState = {rxdn_s1, rxdp_s1}; |
|
always @(posedge clk) rx_en <= RxEn_i; |
always @(posedge clk) sync_err <= !rx_active & sync_err_d; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Synchronize Inputs |
// |
|
// First synchronize to the local system clock to |
// avoid metastability outside the sync block (*_s0). |
// Then make sure we see the signal for at least two |
// clock cycles stable to avoid glitches and noise |
|
always @(posedge clk) rxd_s0 <= rxd; |
always @(posedge clk) rxd_s1 <= rxd_s0; |
always @(posedge clk) // Avoid detecting Line Glitches and noise |
if(rxd_s0 && rxd_s1) rxd_s <= 1'b1; |
else |
if(!rxd_s0 && !rxd_s1) rxd_s <= 1'b0; |
|
always @(posedge clk) rxdp_s0 <= rxdp; |
always @(posedge clk) rxdp_s1 <= rxdp_s0; |
always @(posedge clk) rxdp_s_r <= rxdp_s0 & rxdp_s1; |
always @(posedge clk) rxdp_s <= (rxdp_s0 & rxdp_s1) | rxdp_s_r; // Avoid detecting Line Glitches and noise |
|
always @(posedge clk) rxdn_s0 <= rxdn; |
always @(posedge clk) rxdn_s1 <= rxdn_s0; |
always @(posedge clk) rxdn_s_r <= rxdn_s0 & rxdn_s1; |
always @(posedge clk) rxdn_s <= (rxdn_s0 & rxdn_s1) | rxdn_s_r; // Avoid detecting Line Glitches and noise |
|
assign k = !rxdp_s & rxdn_s; |
assign j = rxdp_s & !rxdn_s; |
assign se0 = !rxdp_s & !rxdn_s; |
|
always @(posedge clk) if(fs_ce) se0_s <= se0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// DPLL |
// |
|
// This design uses a clock enable to do 12Mhz timing and not a |
// real 12Mhz clock. Everything always runs at 48Mhz. We want to |
// make sure however, that the clock enable is always exactly in |
// the middle between two virtual 12Mhz rising edges. |
// We monitor rxdp and rxdn for any changes and do the appropiate |
// adjustments. |
// In addition to the locking done in the dpll FSM, we adjust the |
// final latch enable to compensate for various sync registers ... |
|
// Allow lockinf only when we are receiving |
assign lock_en = rx_en; |
|
always @(posedge clk) rxd_r <= rxd_s; |
|
// Edge detector |
assign change = rxd_r != rxd_s; |
|
// DPLL FSM |
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) dpll_state <= 2'h1; |
else dpll_state <= dpll_next_state; |
|
always @(dpll_state or lock_en or change) |
begin |
fs_ce_d = 1'b0; |
case(dpll_state) // synopsys full_case parallel_case |
2'h0: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h1; |
2'h1:begin |
fs_ce_d = 1'b1; |
if(lock_en && change) dpll_next_state = 2'h3; |
else dpll_next_state = 2'h2; |
end |
2'h2: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h3; |
2'h3: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h0; |
endcase |
end |
|
// Compensate for sync registers at the input - allign full speed |
// clock enable to be in the middle between two bit changes ... |
reg fs_ce_r1, fs_ce_r2; |
|
always @(posedge clk) fs_ce_r1 <= fs_ce_d; |
always @(posedge clk) fs_ce_r2 <= fs_ce_r1; |
always @(posedge clk) fs_ce <= fs_ce_r2; |
|
|
/////////////////////////////////////////////////////////////////// |
// |
// Find Sync Pattern FSM |
// |
|
parameter FS_IDLE = 3'h0, |
K1 = 3'h1, |
J1 = 3'h2, |
K2 = 3'h3, |
J2 = 3'h4, |
K3 = 3'h5, |
J3 = 3'h6, |
K4 = 3'h7; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) fs_state <= FS_IDLE; |
else fs_state <= fs_next_state; |
|
always @(fs_state or fs_ce or k or j or rx_en or rx_active or se0 or se0_s) |
begin |
synced_d = 1'b0; |
sync_err_d = 1'b0; |
fs_next_state = fs_state; |
if(fs_ce && !rx_active && !se0 && !se0_s) |
case(fs_state) // synopsys full_case parallel_case |
FS_IDLE: |
begin |
if(k && rx_en) fs_next_state = K1; |
end |
K1: |
begin |
if(j && rx_en) fs_next_state = J1; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J1: |
begin |
if(k && rx_en) fs_next_state = K2; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K2: |
begin |
if(j && rx_en) fs_next_state = J2; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J2: |
begin |
if(k && rx_en) fs_next_state = K3; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K3: |
begin |
if(j && rx_en) fs_next_state = J3; |
else |
if(k && rx_en) |
begin |
fs_next_state = FS_IDLE; // Allow missing first K-J |
synced_d = 1'b1; |
end |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J3: |
begin |
if(k && rx_en) fs_next_state = K4; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K4: |
begin |
if(k) synced_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
endcase |
end |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate RxActive |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rx_active <= 1'b0; |
else |
if(synced_d && rx_en) rx_active <= 1'b1; |
else |
if(se0 && rx_valid_r) rx_active <= 1'b0; |
|
always @(posedge clk) |
if(rx_valid) rx_valid_r <= 1'b1; |
else |
if(fs_ce) rx_valid_r <= 1'b0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// NRZI Decoder |
// |
|
always @(posedge clk) |
if(fs_ce) sd_r <= rxd_s; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_nrzi <= 1'b0; |
else |
if(!rx_active) sd_nrzi <= 1'b1; |
else |
if(rx_active && fs_ce) sd_nrzi <= !(rxd_s ^ sd_r); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Bit Stuff Detect |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) one_cnt <= 3'h0; |
else |
if(!shift_en) one_cnt <= 3'h0; |
else |
if(fs_ce) |
begin |
if(!sd_nrzi || drop_bit) one_cnt <= 3'h0; |
else one_cnt <= one_cnt + 3'h1; |
end |
|
assign drop_bit = (one_cnt==3'h6); |
|
always @(posedge clk) bit_stuff_err <= drop_bit & sd_nrzi & fs_ce & !se0 & rx_active; // Bit Stuff Error |
|
/////////////////////////////////////////////////////////////////// |
// |
// Serial => Parallel converter |
// |
|
always @(posedge clk) |
if(fs_ce) shift_en <= synced_d | rx_active; |
|
always @(posedge clk) |
if(fs_ce && shift_en && !drop_bit) |
hold_reg <= {sd_nrzi, hold_reg[7:1]}; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate RxValid |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) bit_cnt <= 3'b0; |
else |
if(!shift_en) bit_cnt <= 3'h0; |
else |
if(fs_ce && !drop_bit) bit_cnt <= bit_cnt + 3'h1; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rx_valid1 <= 1'b0; |
else |
if(fs_ce && !drop_bit && (bit_cnt==3'h7)) rx_valid1 <= 1'b1; |
else |
if(rx_valid1 && fs_ce && !drop_bit) rx_valid1 <= 1'b0; |
|
always @(posedge clk) rx_valid <= !drop_bit & rx_valid1 & fs_ce; |
|
always @(posedge clk) se0_r <= se0; |
|
always @(posedge clk) byte_err <= se0 & !se0_r & (|bit_cnt[2:1]) & rx_active; |
|
endmodule |
|
/trunk/rtl/phy/usb_tx_phy.v
0,0 → 1,456
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// TX //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: usb_tx_phy.v,v 1.4 2004-10-19 09:29:07 rudi Exp $ |
// |
// $Date: 2004-10-19 09:29:07 $ |
// $Revision: 1.4 $ |
// $Author: rudi $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.3 2003/10/21 05:58:41 rudi |
// usb_rst is no longer or'ed with the incomming reset internally. |
// Now usb_rst is simply an output, the application can decide how |
// to utilize it. |
// |
// Revision 1.2 2003/10/19 17:40:13 rudi |
// - Made core more robust against line noise |
// - Added Error Checking and Reporting |
// (See README.txt for more info) |
// |
// Revision 1.1.1.1 2002/09/16 14:27:02 rudi |
// Created Directory Structure |
// |
// |
// |
// |
// |
// |
// |
|
module usb_tx_phy( |
clk, rst, fs_ce, phy_mode, |
|
// Transciever Interface |
txdp, txdn, txoe, |
|
// UTMI Interface |
DataOut_i, TxValid_i, TxReady_o |
); |
|
input clk; |
input rst; |
input fs_ce; |
input phy_mode; |
output txdp, txdn, txoe; |
input [7:0] DataOut_i; |
input TxValid_i; |
output TxReady_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
parameter IDLE = 3'd0; |
parameter SOP = 3'h1; |
parameter DATA = 3'h2; |
parameter EOP = 3'h3; |
|
reg TxReady_o; |
reg [2:0] state, next_state; |
reg tx_ready_d; |
reg ld_sop_d; |
reg ld_data_d; |
reg ld_eop_d; |
reg tx_ip; |
reg tx_ip_sync; |
reg [2:0] bit_cnt; |
reg [7:0] hold_reg; |
reg [7:0] hold_reg_d; |
|
reg [2:0] eop_cnt; |
wire eop_done; |
|
reg sd_raw_o; |
wire hold; |
reg data_done; |
reg sft_done; |
reg sft_done_r; |
wire sft_done_e; |
reg ld_data; |
reg [2:0] one_cnt; |
wire stuff; |
reg sd_bs_o; |
reg sd_nrzi_o; |
reg txdp, txdn; |
reg txoe_r1, txoe_r2; |
reg txoe; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) TxReady_o <= 1'b0; |
else TxReady_o <= tx_ready_d & TxValid_i; |
|
always @(posedge clk) ld_data <= ld_data_d; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Transmit in progress indicator |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) tx_ip <= 1'b0; |
else |
if(ld_sop_d) tx_ip <= 1'b1; |
else |
if(eop_done) tx_ip <= 1'b0; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) tx_ip_sync <= 1'b0; |
else |
if(fs_ce) tx_ip_sync <= tx_ip; |
|
// data_done helps us to catch cases where TxValid drops due to |
// packet end and then gets re-asserted as a new packet starts. |
// We might not see this because we are still transmitting. |
// data_done should solve those cases ... |
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) data_done <= 1'b0; |
else |
if(TxValid_i && ! tx_ip) data_done <= 1'b1; |
else |
if(!TxValid_i) data_done <= 1'b0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Shift Register |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) |
begin |
bit_cnt <= 3'h0; |
end |
else |
if(!tx_ip_sync) bit_cnt <= 3'h0; |
else |
if(fs_ce && !hold) |
begin |
bit_cnt <= bit_cnt + 3'h1; |
end |
|
assign hold = stuff; |
|
always @(posedge clk) |
if(!tx_ip_sync) |
begin |
sd_raw_o <= 1'b0; |
end |
else |
begin |
case(bit_cnt) // synopsys full_case parallel_case |
3'h0: sd_raw_o <= hold_reg_d[0]; |
3'h1: sd_raw_o <= hold_reg_d[1]; |
3'h2: sd_raw_o <= hold_reg_d[2]; |
3'h3: sd_raw_o <= hold_reg_d[3]; |
3'h4: sd_raw_o <= hold_reg_d[4]; |
3'h5: sd_raw_o <= hold_reg_d[5]; |
3'h6: sd_raw_o <= hold_reg_d[6]; |
3'h7: sd_raw_o <= hold_reg_d[7]; |
endcase |
|
`ifdef CONF_DISPLAY_USB_TX |
if (fs_ce) |
case(bit_cnt) // synopsys full_case parallel_case |
3'h0: $display("\nTx0=%01d", hold_reg_d[0]); |
3'h1: $display("Tx1=%01d", hold_reg_d[1]); |
3'h2: $display("Tx2=%01d", hold_reg_d[2]); |
3'h3: $display("Tx3=%01d", hold_reg_d[3]); |
3'h4: $display("Tx4=%01d", hold_reg_d[4]); |
3'h5: $display("Tx5=%01d", hold_reg_d[5]); |
3'h6: $display("Tx6=%01d", hold_reg_d[6]); |
3'h7: $display("Tx7=%01d", hold_reg_d[7]); |
endcase |
`endif |
|
end |
|
always @(posedge clk) |
sft_done <= !hold & (bit_cnt == 3'h7); |
|
always @(posedge clk) |
sft_done_r <= sft_done; |
|
assign sft_done_e = sft_done & !sft_done_r; |
|
// Out Data Hold Register |
always @(posedge clk) |
if(ld_sop_d) hold_reg <= 8'h80; |
else |
if(ld_data) hold_reg <= DataOut_i; |
|
always @(posedge clk) hold_reg_d <= hold_reg; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Bit Stuffer |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) one_cnt <= 3'h0; |
else |
if(!tx_ip_sync) one_cnt <= 3'h0; |
else |
if(fs_ce) |
begin |
if(!sd_raw_o || stuff) one_cnt <= 3'h0; |
else one_cnt <= one_cnt + 3'h1; |
end |
|
assign stuff = (one_cnt==3'h6); |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_bs_o <= 1'h0; |
else |
if(fs_ce) sd_bs_o <= !tx_ip_sync ? 1'b0 : (stuff ? 1'b0 : sd_raw_o); |
|
/////////////////////////////////////////////////////////////////// |
// |
// NRZI Encoder |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_nrzi_o <= 1'b1; |
else |
if(!tx_ip_sync || !txoe_r1) sd_nrzi_o <= 1'b1; |
else |
if(fs_ce) sd_nrzi_o <= sd_bs_o ? sd_nrzi_o : ~sd_nrzi_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// EOP append logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) |
begin |
eop_cnt <= 3'b000; |
end |
else |
begin |
if (ld_eop_d) |
eop_cnt <= 3'b001; |
else if(fs_ce && eop_cnt != 3'b000) |
begin |
if (stuff && eop_cnt == 3'b010) |
eop_cnt <= eop_cnt; |
else |
eop_cnt <= eop_cnt + 1; |
end |
end |
|
|
assign eop_done = (eop_cnt == 3'h4 || eop_cnt == 3'h5) ? 1'b1 : 1'b0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Output Enable Logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe_r1 <= 1'b0; |
else |
if(fs_ce) txoe_r1 <= tx_ip_sync; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe_r2 <= 1'b0; |
else |
if(fs_ce) txoe_r2 <= txoe_r1; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe <= 1'b1; |
else |
if(fs_ce) txoe <= !(txoe_r1 | txoe_r2); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Output Registers |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txdp <= 1'b1; |
else |
if(fs_ce) txdp <= phy_mode ? |
(!eop_done & sd_nrzi_o) : sd_nrzi_o; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txdn <= 1'b0; |
else |
begin |
if(fs_ce) |
txdn <= phy_mode ? |
(!eop_done & ~sd_nrzi_o) : eop_done; |
end |
|
/////////////////////////////////////////////////////////////////// |
// |
// Tx state machine |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) state <= IDLE; |
else state <= next_state; |
|
always @(state or TxValid_i or data_done or sft_done_e or fs_ce or eop_cnt) |
begin |
next_state = state; |
tx_ready_d = 1'b0; |
|
ld_sop_d = 1'b0; |
ld_data_d = 1'b0; |
ld_eop_d = 1'b0; |
|
case(state) // synopsys full_case parallel_case |
IDLE: |
if(TxValid_i) |
begin |
ld_sop_d = 1'b1; |
next_state = SOP; |
end |
SOP: |
if(sft_done_e) |
begin |
tx_ready_d = 1'b1; |
ld_data_d = 1'b1; |
next_state = DATA; |
end |
DATA: |
begin |
if(!data_done && sft_done_e) |
begin |
ld_eop_d = 1'b1; |
next_state = EOP; |
end |
|
if(data_done && sft_done_e) |
begin |
tx_ready_d = 1'b1; |
ld_data_d = 1'b1; |
end |
end |
EOP: |
if(fs_ce && eop_cnt == 3'h7) |
next_state = IDLE; |
default : |
next_state = IDLE; |
endcase |
end |
|
endmodule |
|
/trunk/rtl/phy/README.txt
0,0 → 1,96
|
This core was written by Rudolf Usselmann and downloaded from: |
|
http://opencores.org/project,usb_phy |
|
This core has a bug fix applied related to bitstuffing prior to EOP. |
|
==================================================================== |
|
Copyright (C) 2000-2002 Rudolf Usselmann |
www.asics.ws |
rudi@asics.ws |
|
This source file may be used and distributed without |
restriction provided that this copyright statement is not |
removed from the file and that any derivative work contains |
the original copyright notice and the associated disclaimer. |
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY |
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR |
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
|
|
USB 1.1 PHY |
========== |
|
Status |
------ |
This core is done. It was tested with a USB 1.1 core I have written on |
a XESS XCV800 board with a a Philips PDIUSBP11A transceiver. |
I have NOT yet tested it with my USB 2.0 Function IP core. |
|
Test Bench |
---------- |
There is no test bench, period ! As I said above I have tested this core |
in real hardware and it works just fine. |
|
Documentation |
------------- |
Sorry, there is none. I just don't have the time to write it. I have tried |
to follow the UTMI interface specification from USB 2.0. |
'phy_mode' selects between single ended and differential tx_phy output. See |
Philips ISP 1105 transceiver data sheet for an explanation of it's MODE |
select pin (see Note below). |
Currently this PHY only operates in Full-Speed mode. Required clock frequency |
is 48MHz, from which the 12MHz USB transmit and receive clocks are derived. |
|
RxError reports the following errors: |
- sync errors |
Could not synchronize to incoming bit stream |
- Bit Stuff Error |
Stuff bit had the wrong value (expected '0' got '1') |
- Byte Error |
Got a EOP (se0) before finished assembling a full byteAll of those errors |
are or'ed together and reported via RxError. |
|
Note: |
1) "phy_tx_mode" selects the PHY Transmit Mode: |
When phy_tx_mode is '0' the outputs are encoded as: |
txdn, txdp |
0 0 Differential Logic '0' |
0 1 Differential Logic '1' |
1 0 Single Ended '0' |
1 1 Single Ended '0' |
|
When phy_tx_mode is '1' the outputs are encoded as: |
txdn, txdp |
0 0 Single Ended '0' |
0 1 Differential Logic '1' |
1 0 Differential Logic '0' |
1 1 Illegal State |
|
See PHILIPS Transceiver Data Sheet for: ISP1105, ISP1106 and ISP1107 |
for more details. |
|
2) "usb_rst" Indicates a USB Bus Reset (this output is also or'ed with |
the reset input). |
|
Misc |
---- |
The USB 1.1 Phy Project Page is: |
http://www.opencores.org/cores/usb_phy |
|
To find out more about me (Rudolf Usselmann), please visit: |
http://www.asics.ws |
|
/trunk/rtl/phy/usb_phy.v
0,0 → 1,228
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
//----------------------------------------------------------------- |
// Module: |
//----------------------------------------------------------------- |
module usb_phy |
( |
// Clock (48MHz) & reset |
clk, |
rst, |
|
// PHY Transmit Mode: |
// When phy_tx_mode_i is '0' the outputs are encoded as: |
// TX- TX+ |
// 0 0 Differential Logic '0' |
// 0 1 Differential Logic '1' |
// 1 0 Single Ended '0' |
// 1 1 Single Ended '0' |
// When phy_tx_mode_i is '1' the outputs are encoded as: |
// TX- TX+ |
// 0 0 Single Ended '0' |
// 0 1 Differential Logic '1' |
// 1 0 Differential Logic '0' |
// 1 1 Illegal State |
phy_tx_mode_i, |
|
// USB bus reset event |
usb_rst_o, |
usb_rst_i, |
|
// Transciever Interface |
// Tx +/- |
tx_dp_o, |
tx_dn_o, |
|
// Tx output enable (active low) |
tx_oen_o, |
|
// Receive data |
rx_rcv_i, |
|
// Rx +/- |
rx_dp_i, |
rx_dn_i, |
|
// UTMI Interface |
|
// Transmit data [7:0] |
utmi_data_i, |
|
// Transmit data enable |
utmi_txvalid_i, |
|
// Transmit ready (L=hold,H=load data) |
utmi_txready_o, |
|
// Receive data [7:0] |
utmi_data_o, |
|
// Valid data on utmi_data_o |
utmi_rxvalid_o, |
|
// Receive active (SYNC recieved) |
utmi_rxactive_o, |
|
// Rx error occurred |
utmi_rxerror_o, |
|
// Receive line state [1=RX-, 0=RX+] |
utmi_linestate_o |
); |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// I/O |
//----------------------------------------------------------------- |
input clk; |
input rst; |
input phy_tx_mode_i; |
output usb_rst_o; |
input usb_rst_i; |
output tx_dp_o, tx_dn_o, tx_oen_o; |
input rx_rcv_i, rx_dp_i, rx_dn_i; |
input [7:0] utmi_data_i; |
input utmi_txvalid_i; |
output utmi_txready_o; |
output [7:0] utmi_data_o; |
output utmi_rxvalid_o; |
output utmi_rxactive_o; |
output utmi_rxerror_o; |
output [1:0] utmi_linestate_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
reg [4:0] rst_cnt; |
reg usb_rst_o; |
wire fs_ce; |
wire rst; |
|
wire tx_dp_int; |
wire tx_dn_int; |
wire tx_oen_int; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
/////////////////////////////////////////////////////////////////// |
// |
// TX Phy |
// |
|
usb_tx_phy i_tx_phy( |
.clk( clk ), |
.rst( rst ), |
.fs_ce( fs_ce ), |
.phy_mode( phy_tx_mode_i ), |
|
// Transciever Interface |
.txdp( tx_dp_int ), |
.txdn( tx_dn_int ), |
.txoe( tx_oen_int ), |
|
// UTMI Interface |
.DataOut_i( utmi_data_i ), |
.TxValid_i( utmi_txvalid_i ), |
.TxReady_o( utmi_txready_o ) |
); |
|
/////////////////////////////////////////////////////////////////// |
// |
// RX Phy and DPLL |
// |
|
usb_rx_phy i_rx_phy( |
.clk( clk ), |
.rst( rst ), |
.fs_ce( fs_ce ), |
|
// Transciever Interface |
.rxd( rx_rcv_i ), |
.rxdp( rx_dp_i ), |
.rxdn( rx_dn_i ), |
|
// UTMI Interface |
.DataIn_o( utmi_data_o ), |
.RxValid_o( utmi_rxvalid_o ), |
.RxActive_o( utmi_rxactive_o ), |
.RxError_o( utmi_rxerror_o ), |
.RxEn_i( tx_oen_o ), |
.LineState( utmi_linestate_o ) |
); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate an USB Reset is we see SE0 for at least 2.5uS |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rst_cnt <= 5'h0; |
else |
if(utmi_linestate_o != 2'h0) rst_cnt <= 5'h0; |
else |
if(!usb_rst_o && fs_ce) rst_cnt <= rst_cnt + 5'h1; |
|
`ifdef CONF_TARGET_SIM |
// Disable RST_O |
always @(posedge clk) |
usb_rst_o <= 1'b0; |
`else |
always @(posedge clk) |
usb_rst_o <= (rst_cnt == 5'h1f); |
`endif |
|
// Host generate USB reset event (SE0) |
assign tx_dp_o = usb_rst_i ? 1'b0 : tx_dp_int; |
assign tx_dn_o = usb_rst_i ? 1'b1 : tx_dn_int; |
assign tx_oen_o = usb_rst_i ? 1'b0 : tx_oen_int; |
|
endmodule |
|
/trunk/rtl/usbf_crc16.v
0,0 → 1,78
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: 16-bit CRC used by USB data packets |
//----------------------------------------------------------------- |
module usbf_crc16 |
( |
input [15:0] crc_in, |
input [7:0] din, |
output [15:0] crc_out |
); |
|
//----------------------------------------------------------------- |
// Logic |
//----------------------------------------------------------------- |
assign crc_out[15] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^ din[7] ^ |
crc_in[7] ^ crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0]; |
assign crc_out[14] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^ |
crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0]; |
assign crc_out[13] = din[6] ^ din[7] ^ |
crc_in[7] ^ crc_in[6]; |
assign crc_out[12] = din[5] ^ din[6] ^ |
crc_in[6] ^ crc_in[5]; |
assign crc_out[11] = din[4] ^ din[5] ^ |
crc_in[5] ^ crc_in[4]; |
assign crc_out[10] = din[3] ^ din[4] ^ |
crc_in[4] ^ crc_in[3]; |
assign crc_out[9] = din[2] ^ din[3] ^ |
crc_in[3] ^ crc_in[2]; |
assign crc_out[8] = din[1] ^ din[2] ^ |
crc_in[2] ^ crc_in[1]; |
assign crc_out[7] = din[0] ^ din[1] ^ |
crc_in[15] ^ crc_in[1] ^ crc_in[0]; |
assign crc_out[6] = din[0] ^ |
crc_in[14] ^ crc_in[0]; |
assign crc_out[5] = crc_in[13]; |
assign crc_out[4] = crc_in[12]; |
assign crc_out[3] = crc_in[11]; |
assign crc_out[2] = crc_in[10]; |
assign crc_out[1] = crc_in[9]; |
assign crc_out[0] = din[0] ^ din[1] ^ din[2] ^ din[3] ^ din[4] ^ din[5] ^ din[6] ^ din[7] ^ |
crc_in[8] ^ crc_in[7] ^ crc_in[6] ^ crc_in[5] ^ crc_in[4] ^ crc_in[3] ^ crc_in[2] ^ crc_in[1] ^ crc_in[0]; |
|
endmodule |
/trunk/rtl/usbf_device.v
0,0 → 1,211
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: USB device core (top) |
//----------------------------------------------------------------- |
module usbf_device |
( |
// Clocking (48MHz) & Reset |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
|
// Interrupt output |
output intr_o /*verilator public*/, |
|
// Peripheral Interface (from CPU) |
input [7:0] addr_i /*verilator public*/, |
input [31:0] data_i /*verilator public*/, |
output [31:0] data_o /*verilator public*/, |
input we_i /*verilator public*/, |
input stb_i /*verilator public*/, |
|
// USB Transceiver Interface |
output usb_vmo_o /*verilator public*/, |
output usb_vpo_o /*verilator public*/, |
output usb_oe_o /*verilator public*/, |
input usb_rx_i /*verilator public*/, |
input usb_vp_i /*verilator public*/, |
input usb_vm_i /*verilator public*/, |
output usb_speed_o /*verilator public*/, |
output usb_susp_o /*verilator public*/, |
output usb_mode_o /*verilator public*/, |
output usb_en_o /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
wire [7:0] utmi_data_w; |
wire [7:0] utmi_data_r; |
wire utmi_txvalid; |
wire utmi_txready; |
wire utmi_rxvalid; |
wire utmi_rxactive; |
wire utmi_rxerror; |
wire [1:0] utmi_linestate; |
|
wire usb_oen; |
wire usb_tx_p; |
wire usb_tx_n; |
wire usb_rx_p; |
wire usb_rx_n; |
wire usb_rx; |
wire usb_rst; |
|
wire nrst; |
|
//----------------------------------------------------------------- |
// Instantiation |
//----------------------------------------------------------------- |
usbf_sie |
usb |
( |
// Clocking (48MHz) & Reset |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
// Interrupt output |
.intr_o(intr_o), |
|
// Peripheral Interface (from CPU) |
.addr_i(addr_i), |
.data_i(data_i), |
.data_o(data_o), |
.we_i(we_i), |
.stb_i(stb_i), |
|
// UTMI interface |
.utmi_rst_i(usb_rst), |
.utmi_data_w(utmi_data_w), |
.utmi_data_r(utmi_data_r), |
.utmi_txvalid_o(utmi_txvalid), |
.utmi_txready_i(utmi_txready), |
.utmi_rxvalid_i(utmi_rxvalid), |
.utmi_rxactive_i(utmi_rxactive), |
.utmi_rxerror_i(utmi_rxerror), |
.utmi_linestate_i(utmi_linestate), |
|
// Pull-up enable |
.usb_en_o(usb_en_o) |
); |
|
// USB-PHY module (UTMI->PHY interface) |
usb_phy |
u_phy |
( |
// Clock (48MHz) & reset |
.clk(clk_i), |
.rst(nrst), |
|
// PHY Transmit Mode: |
// When phy_tx_mode_i is '0' the outputs are encoded as: |
// TX- TX+ |
// 0 0 Differential Logic '0' |
// 0 1 Differential Logic '1' |
// 1 0 Single Ended '0' |
// 1 1 Single Ended '0' |
// When phy_tx_mode_i is '1' the outputs are encoded as: |
// TX- TX+ |
// 0 0 Single Ended '0' |
// 0 1 Differential Logic '1' |
// 1 0 Differential Logic '0' |
// 1 1 Illegal State |
.phy_tx_mode_i(1'b0), |
|
// USB bus reset event |
.usb_rst_o(usb_rst), |
.usb_rst_i(1'b0), |
|
// Transciever Interface |
// Tx +/- |
.tx_dp_o(usb_tx_p), |
.tx_dn_o(usb_tx_n), |
|
// Tx output enable (active low) |
.tx_oen_o(usb_oen), |
|
// Receive data |
.rx_rcv_i(usb_rx), |
|
// Rx +/- |
.rx_dp_i(usb_rx_p), |
.rx_dn_i(usb_rx_n), |
|
// UTMI Interface |
|
// Transmit data [7:0] |
.utmi_data_i(utmi_data_w), |
|
// Transmit data enable |
.utmi_txvalid_i(utmi_txvalid), |
|
// Transmit ready (L=hold,H=load data) |
.utmi_txready_o(utmi_txready), |
|
// Receive data [7:0] |
.utmi_data_o(utmi_data_r), |
|
// Valid data on utmi_data_o |
.utmi_rxvalid_o(utmi_rxvalid), |
|
// Receive active (SYNC recieved) |
.utmi_rxactive_o(utmi_rxactive), |
|
// Rx error occurred |
.utmi_rxerror_o(utmi_rxerror), |
|
// Receive line state [1=RX-, 0=RX+] |
.utmi_linestate_o(utmi_linestate) |
); |
|
//----------------------------------------------------------------- |
// Assignments |
//----------------------------------------------------------------- |
assign usb_rx = usb_rx_i; |
assign usb_rx_p = usb_vp_i; |
assign usb_rx_n = usb_vm_i; |
assign usb_vpo_o = usb_tx_p; |
assign usb_vmo_o = usb_tx_n; |
assign usb_oe_o = usb_oen; |
|
assign usb_mode_o = 1'b0; |
assign usb_speed_o = 1'b1; |
assign usb_susp_o = 1'b0; |
|
assign nrst = !rst_i; |
|
endmodule |
/trunk/rtl/usbf_sie.v
0,0 → 1,1753
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// !!!! This file is auto generated !!!! |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: Simplified USB device serial interface engine |
//----------------------------------------------------------------- |
module usbf_sie |
( |
// Clocking (48MHz) & Reset |
input wire clk_i /*verilator public*/, |
input wire rst_i /*verilator public*/, |
|
// Interrupt output |
output reg intr_o /*verilator public*/, |
|
// Peripheral Interface |
input wire [7:0] addr_i /*verilator public*/, |
input wire [31:0] data_i /*verilator public*/, |
output reg [31:0] data_o /*verilator public*/, |
input wire we_i /*verilator public*/, |
input wire stb_i /*verilator public*/, |
|
// UTMI interface |
input wire utmi_rst_i /*verilator public*/, |
output wire [7:0] utmi_data_w /*verilator public*/, |
input wire [7:0] utmi_data_r /*verilator public*/, |
output reg utmi_txvalid_o /*verilator public*/, |
input wire utmi_txready_i /*verilator public*/, |
input wire utmi_rxvalid_i /*verilator public*/, |
input wire utmi_rxactive_i /*verilator public*/, |
input wire utmi_rxerror_i /*verilator public*/, |
input wire [1:0] utmi_linestate_i /*verilator public*/, |
|
// Pull-up enable |
output reg usb_en_o /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
// Current state |
parameter STATE_RX_IDLE = 4'b0000; |
parameter STATE_RX_TOKEN2 = 4'b0001; |
parameter STATE_RX_TOKEN3 = 4'b0010; |
parameter STATE_RX_TOKEN_COMPLETE = 4'b0011; |
parameter STATE_RX_SOF2 = 4'b0100; |
parameter STATE_RX_SOF3 = 4'b0101; |
parameter STATE_RX_DATA = 4'b0110; |
parameter STATE_RX_DATA_IGNORE = 4'b0111; |
parameter STATE_RX_DATA_COMPLETE = 4'b1000; |
parameter STATE_TX_DATA = 4'b1001; |
parameter STATE_TX_CRC = 4'b1010; |
parameter STATE_TX_CRC1 = 4'b1011; |
parameter STATE_TX_CRC2 = 4'b1100; |
parameter STATE_TX_ACK = 4'b1101; |
parameter STATE_TX_NAK = 4'b1110; |
parameter STATE_TX_STALL = 4'b1111; |
reg [3:0] usb_state; |
|
reg [7:0] utmi_txdata; |
|
// CRC16 |
reg [15:0] crc_sum; |
wire [15:0] crc_out; |
wire [7:0] crc_data_in; |
|
// Others |
reg [6:0] usb_this_device; |
reg [6:0] usb_next_address; |
reg usb_address_pending; |
reg usb_event_bus_reset; |
|
// Interrupt enables |
reg usb_int_en_tx; |
reg usb_int_en_rx; |
reg usb_int_en_sof; |
|
// Incoming request type |
reg usb_rx_pid_out; |
reg usb_rx_pid_in; |
reg usb_rx_pid_setup; |
|
// Request details |
reg [10:0] usb_frame_number; |
reg [6:0] usb_address; |
reg [2-1:0] usb_endpoint; |
|
// Request action |
reg usb_rx_accept_data; |
reg usb_rx_send_nak; |
reg usb_rx_send_stall; |
|
// Transmit details |
reg [7:0] usb_tx_idx; |
|
// Endpoint state |
reg usb_ep_tx_pend[3:0]; |
reg usb_ep_tx_data1[3:0]; |
reg [7:0] usb_ep_tx_count[3:0]; |
reg usb_ep_stall[3:0]; |
reg usb_ep_iso[3:0]; |
|
reg [7:0] usb_rx_count; |
|
reg usb_ep0_rx_setup; |
|
reg usb_ep_full[3:0]; |
reg [7:0] usb_ep_rx_count[3:0]; |
reg usb_ep_crc_err[3:0]; |
|
// Endpoint receive FIFO (Host -> Device) |
reg usb_fifo_rd_push[3:0]; |
reg usb_fifo_rd_flush[3:0]; |
reg usb_fifo_rd_pop[3:0]; |
reg [7:0] usb_fifo_rd_in; |
wire [7:0] usb_fifo_rd_out[3:0]; |
|
// Endpoint transmit FIFO (Device -> Host) |
reg usb_fifo_wr_push[3:0]; |
reg usb_fifo_wr_pop[3:0]; |
reg usb_fifo_wr_flush[3:0]; |
reg [7:0] usb_fifo_wr_data[3:0]; |
wire [7:0] usb_fifo_wr_out[3:0]; |
reg [7:0] usb_write_data; |
|
wire new_data_ready = utmi_rxvalid_i & utmi_rxactive_i; |
|
//----------------------------------------------------------------- |
// Peripheral Memory Map |
//----------------------------------------------------------------- |
`define USB_FUNC_CTRL 8'd0 |
`define USB_FUNC_STAT 8'd0 |
`define USB_FUNC_EP0 8'd4 |
`define USB_FUNC_EP0_DATA 8'd32 |
`define USB_FUNC_EP1 8'd8 |
`define USB_FUNC_EP1_DATA 8'd36 |
`define USB_FUNC_EP2 8'd12 |
`define USB_FUNC_EP2_DATA 8'd40 |
`define USB_FUNC_EP3 8'd16 |
`define USB_FUNC_EP3_DATA 8'd44 |
|
//----------------------------------------------------------------- |
// Register Definitions |
//----------------------------------------------------------------- |
// USB_FUNC_CTRL |
`define USB_FUNC_CTRL_ADDR 6:0 |
`define USB_FUNC_CTRL_ADDR_SET 8 |
`define USB_FUNC_CTRL_INT_EN_TX 9 |
`define USB_FUNC_CTRL_INT_EN_RX 10 |
`define USB_FUNC_CTRL_INT_EN_SOF 11 |
`define USB_FUNC_CTRL_PULLUP_EN 12 |
|
// USB_FUNC_STAT |
`define USB_FUNC_STAT_FRAME 10:0 |
`define USB_FUNC_STAT_LS_RXP 16 |
`define USB_FUNC_STAT_LS_RXN 17 |
`define USB_FUNC_STAT_RST 18 |
|
// USB_FUNC_EPx |
`define USB_EP_COUNT 7:0 |
`define USB_EP_TX_READY 16 |
`define USB_EP_RX_AVAIL 17 |
`define USB_EP_RX_ACK 18 |
`define USB_EP_RX_SETUP 18 |
`define USB_EP_RX_CRC_ERR 19 |
`define USB_EP_STALL 20 |
`define USB_EP_TX_FLUSH 21 |
`define USB_EP_ISO 22 |
|
//----------------------------------------------------------------- |
// Definitions |
//----------------------------------------------------------------- |
|
// Tokens |
`define PID_OUT 8'hE1 |
`define PID_IN 8'h69 |
`define PID_SOF 8'hA5 |
`define PID_SETUP 8'h2D |
|
// Data |
`define PID_DATA0 8'hC3 |
`define PID_DATA1 8'h4B |
|
// Handshake |
`define PID_ACK 8'hD2 |
`define PID_NAK 8'h5A |
`define PID_STALL 8'h1E |
|
//----------------------------------------------------------------- |
// Instantiation |
//----------------------------------------------------------------- |
|
// CRC16 |
usbf_crc16 |
u_crc16 |
( |
.crc_in(crc_sum), |
.din(crc_data_in), |
.crc_out(crc_out) |
); |
|
//----------------------------------------------------------------- |
// Endpoint 0: Host -> Device |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(8), |
.ADDR_W(3) |
) |
u_fifo_rx_ep0 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_rd_in), |
.push_i(usb_fifo_rd_push[0]), |
|
.flush_i(usb_fifo_rd_flush[0]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_rd_out[0]), |
.pop_i(usb_fifo_rd_pop[0]) |
); |
|
//----------------------------------------------------------------- |
// Endpoint 0: Device -> Host |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(8), |
.ADDR_W(3) |
) |
u_fifo_tx_ep0 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_wr_data[0]), |
.push_i(usb_fifo_wr_push[0]), |
|
.flush_i(usb_fifo_wr_flush[0]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_wr_out[0]), |
.pop_i(usb_fifo_wr_pop[0]) |
); |
//----------------------------------------------------------------- |
// Endpoint 1: Host -> Device |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_rx_ep1 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_rd_in), |
.push_i(usb_fifo_rd_push[1]), |
|
.flush_i(usb_fifo_rd_flush[1]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_rd_out[1]), |
.pop_i(usb_fifo_rd_pop[1]) |
); |
|
//----------------------------------------------------------------- |
// Endpoint 1: Device -> Host |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_tx_ep1 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_wr_data[1]), |
.push_i(usb_fifo_wr_push[1]), |
|
.flush_i(usb_fifo_wr_flush[1]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_wr_out[1]), |
.pop_i(usb_fifo_wr_pop[1]) |
); |
//----------------------------------------------------------------- |
// Endpoint 2: Host -> Device |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_rx_ep2 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_rd_in), |
.push_i(usb_fifo_rd_push[2]), |
|
.flush_i(usb_fifo_rd_flush[2]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_rd_out[2]), |
.pop_i(usb_fifo_rd_pop[2]) |
); |
|
//----------------------------------------------------------------- |
// Endpoint 2: Device -> Host |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_tx_ep2 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_wr_data[2]), |
.push_i(usb_fifo_wr_push[2]), |
|
.flush_i(usb_fifo_wr_flush[2]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_wr_out[2]), |
.pop_i(usb_fifo_wr_pop[2]) |
); |
//----------------------------------------------------------------- |
// Endpoint 3: Host -> Device |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_rx_ep3 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_rd_in), |
.push_i(usb_fifo_rd_push[3]), |
|
.flush_i(usb_fifo_rd_flush[3]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_rd_out[3]), |
.pop_i(usb_fifo_rd_pop[3]) |
); |
|
//----------------------------------------------------------------- |
// Endpoint 3: Device -> Host |
//----------------------------------------------------------------- |
usbf_fifo |
#( |
.DEPTH(64), |
.ADDR_W(6) |
) |
u_fifo_tx_ep3 |
( |
.clk_i(clk_i), |
.rst_i(rst_i), |
|
.data_i(usb_fifo_wr_data[3]), |
.push_i(usb_fifo_wr_push[3]), |
|
.flush_i(usb_fifo_wr_flush[3]), |
|
.full_o(), |
.empty_o(), |
|
.data_o(usb_fifo_wr_out[3]), |
.pop_i(usb_fifo_wr_pop[3]) |
); |
|
//----------------------------------------------------------------- |
// Next state |
//----------------------------------------------------------------- |
reg [3:0] next_state_r; |
|
always @ * |
begin |
next_state_r = usb_state; |
|
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_RX_IDLE : |
begin |
if (new_data_ready) |
begin |
// Decode PID |
case (utmi_data_r) |
|
`PID_OUT, `PID_IN, `PID_SETUP: |
next_state_r = STATE_RX_TOKEN2; |
|
`PID_SOF: |
next_state_r = STATE_RX_SOF2; |
|
`PID_DATA0, `PID_DATA1: |
begin |
if (usb_rx_accept_data && !usb_rx_send_stall) |
next_state_r = STATE_RX_DATA; |
else |
next_state_r = STATE_RX_DATA_IGNORE; |
end |
|
`PID_ACK, `PID_NAK, `PID_STALL: |
next_state_r = STATE_RX_IDLE; |
|
default : |
; |
endcase |
end |
end |
|
//----------------------------------------- |
// SOF (BYTE 2) |
//----------------------------------------- |
STATE_RX_SOF2 : |
begin |
if (new_data_ready) |
next_state_r = STATE_RX_SOF3; |
end |
|
//----------------------------------------- |
// SOF (BYTE 3) |
//----------------------------------------- |
STATE_RX_SOF3 : |
begin |
if (new_data_ready) |
next_state_r = STATE_RX_IDLE; |
end |
|
//----------------------------------------- |
// TOKEN (IN/OUT/SETUP) (Address/Endpoint) |
//----------------------------------------- |
STATE_RX_TOKEN2 : |
begin |
if (new_data_ready) |
next_state_r = STATE_RX_TOKEN3; |
end |
|
//----------------------------------------- |
// TOKEN (IN/OUT/SETUP) (Endpoint/CRC) |
//----------------------------------------- |
STATE_RX_TOKEN3 : |
begin |
if (new_data_ready) |
next_state_r = STATE_RX_TOKEN_COMPLETE; |
end |
|
//----------------------------------------- |
// RX_TOKEN_COMPLETE |
//----------------------------------------- |
STATE_RX_TOKEN_COMPLETE : |
begin |
next_state_r = STATE_RX_IDLE; |
|
// Addressed to this device? |
if (usb_address == usb_this_device) |
begin |
//------------------------------- |
// IN transfer (device -> host) |
//------------------------------- |
if (usb_rx_pid_in) |
begin |
// Stalled endpoint? |
if (usb_ep_stall[usb_endpoint]) |
next_state_r = STATE_TX_STALL; |
// Some data to TX? |
else if (usb_ep_tx_pend[usb_endpoint]) |
next_state_r = STATE_TX_DATA; |
// No data to TX |
else |
next_state_r = STATE_TX_NAK; |
end |
end |
end |
|
//----------------------------------------- |
// RX_DATA |
//----------------------------------------- |
STATE_RX_DATA : |
begin |
// Receive complete |
if (utmi_rxactive_i == 1'b0) |
next_state_r = STATE_RX_DATA_COMPLETE; |
end |
|
//----------------------------------------- |
// RX_DATA_IGNORE |
//----------------------------------------- |
STATE_RX_DATA_IGNORE : |
begin |
// Receive complete |
if (utmi_rxactive_i == 1'b0) |
begin |
// ISO endpoint? |
if (usb_ep_iso[usb_endpoint]) |
next_state_r = STATE_RX_IDLE; |
// Send STALL? |
else if (usb_rx_send_stall) |
next_state_r = STATE_TX_STALL; |
// Send NAK |
else if (usb_rx_send_nak) |
next_state_r = STATE_TX_NAK; |
else |
next_state_r = STATE_RX_IDLE; |
end |
end |
|
//----------------------------------------- |
// RX_DATA_COMPLETE |
//----------------------------------------- |
STATE_RX_DATA_COMPLETE : |
begin |
// Check for CRC error on receive data |
if (crc_sum != 16'hB001) |
next_state_r = STATE_RX_IDLE; |
// Good CRC |
else |
begin |
// ISO endpoint? |
if (usb_ep_iso[usb_endpoint]) |
next_state_r = STATE_RX_IDLE; |
// Non-ISO, send ACK |
else |
next_state_r = STATE_TX_ACK; |
end |
end |
|
//----------------------------------------- |
// TX_ACK/NAK/STALL |
//----------------------------------------- |
STATE_TX_ACK, STATE_TX_NAK, STATE_TX_STALL : |
begin |
// Data sent? |
if (utmi_txready_i) |
next_state_r = STATE_RX_IDLE; |
end |
|
//----------------------------------------- |
// TX_DATA |
//----------------------------------------- |
STATE_TX_DATA : |
begin |
// Data sent? |
if (utmi_txready_i) |
begin |
// Generate CRC16 at end of packet |
if (usb_tx_idx == usb_ep_tx_count[usb_endpoint]) |
next_state_r = STATE_TX_CRC; |
end |
end |
|
//----------------------------------------- |
// TX_CRC (generate) |
//----------------------------------------- |
STATE_TX_CRC : |
next_state_r = STATE_TX_CRC1; |
|
//----------------------------------------- |
// TX_CRC1 (first byte) |
//----------------------------------------- |
STATE_TX_CRC1 : |
begin |
// Data sent? |
if (utmi_txready_i) |
next_state_r = STATE_TX_CRC2; |
end |
|
//----------------------------------------- |
// TX_CRC (second byte) |
//----------------------------------------- |
STATE_TX_CRC2 : |
begin |
// Data sent? |
if (utmi_txready_i) |
next_state_r = STATE_RX_IDLE; |
end |
|
default : |
; |
|
endcase |
|
//----------------------------------------- |
// USB Bus Reset (HOST->DEVICE) |
//----------------------------------------- |
if (utmi_rst_i) |
next_state_r = STATE_RX_IDLE; |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i) |
begin |
if (rst_i == 1'b1) |
usb_state <= STATE_RX_IDLE; |
else |
usb_state <= next_state_r; |
end |
|
//----------------------------------------------------------------- |
// Tx |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
utmi_txvalid_o <= 1'b0; |
utmi_txdata <= 8'h00; |
|
usb_tx_idx <= 8'b0; |
|
usb_ep_tx_pend[0] <= 1'b0; |
usb_ep_tx_data1[0] <= 1'b0; |
usb_ep_tx_count[0] <= 8'b0; |
usb_fifo_wr_pop[0] <= 1'b0; |
usb_fifo_wr_push[0] <= 1'b0; |
usb_fifo_wr_data[0] <= 8'h00; |
usb_fifo_wr_flush[0]<= 1'b0; |
usb_ep_tx_pend[1] <= 1'b0; |
usb_ep_tx_data1[1] <= 1'b0; |
usb_ep_tx_count[1] <= 8'b0; |
usb_fifo_wr_pop[1] <= 1'b0; |
usb_fifo_wr_push[1] <= 1'b0; |
usb_fifo_wr_data[1] <= 8'h00; |
usb_fifo_wr_flush[1]<= 1'b0; |
usb_ep_tx_pend[2] <= 1'b0; |
usb_ep_tx_data1[2] <= 1'b0; |
usb_ep_tx_count[2] <= 8'b0; |
usb_fifo_wr_pop[2] <= 1'b0; |
usb_fifo_wr_push[2] <= 1'b0; |
usb_fifo_wr_data[2] <= 8'h00; |
usb_fifo_wr_flush[2]<= 1'b0; |
usb_ep_tx_pend[3] <= 1'b0; |
usb_ep_tx_data1[3] <= 1'b0; |
usb_ep_tx_count[3] <= 8'b0; |
usb_fifo_wr_pop[3] <= 1'b0; |
usb_fifo_wr_push[3] <= 1'b0; |
usb_fifo_wr_data[3] <= 8'h00; |
usb_fifo_wr_flush[3]<= 1'b0; |
end |
else |
begin |
usb_fifo_wr_pop[0] <= 1'b0; |
usb_fifo_wr_push[0] <= 1'b0; |
usb_fifo_wr_flush[0] <= 1'b0; |
usb_fifo_wr_pop[1] <= 1'b0; |
usb_fifo_wr_push[1] <= 1'b0; |
usb_fifo_wr_flush[1] <= 1'b0; |
usb_fifo_wr_pop[2] <= 1'b0; |
usb_fifo_wr_push[2] <= 1'b0; |
usb_fifo_wr_flush[2] <= 1'b0; |
usb_fifo_wr_pop[3] <= 1'b0; |
usb_fifo_wr_push[3] <= 1'b0; |
usb_fifo_wr_flush[3] <= 1'b0; |
|
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_RX_IDLE : |
begin |
if (new_data_ready) |
begin |
usb_tx_idx <= 8'b0; |
|
// Decode PID |
case (utmi_data_r) |
`PID_SETUP: |
begin |
// Send DATA1 when responding to SETUP |
usb_ep_tx_data1[0] <= 1'b1; |
end |
|
default : |
; |
endcase |
end |
end |
|
//----------------------------------------- |
// TX_ACK |
//----------------------------------------- |
STATE_TX_ACK : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
|
// Data to send |
utmi_txdata <= `PID_ACK; |
|
// Data sent? |
if (utmi_txready_i) |
begin |
|
utmi_txvalid_o <= 1'b0; |
end |
end |
|
//----------------------------------------- |
// TX_NAK |
//----------------------------------------- |
STATE_TX_NAK : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
|
// Data to send |
utmi_txdata <= `PID_NAK; |
|
// Data sent? |
if (utmi_txready_i) |
begin |
|
utmi_txvalid_o <= 1'b0; |
end |
end |
|
//----------------------------------------- |
// TX_STALL |
//----------------------------------------- |
STATE_TX_STALL : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
|
// Data to send |
utmi_txdata <= `PID_STALL; |
|
// Data sent? |
if (utmi_txready_i) |
begin |
|
utmi_txvalid_o <= 1'b0; |
end |
end |
|
//----------------------------------------- |
// TX_DATA |
//----------------------------------------- |
STATE_TX_DATA : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
|
// Send PID (first byte - DATA0 or DATA1) |
if (usb_tx_idx == 8'b0) |
begin |
if (usb_ep_tx_data1[usb_endpoint]) |
utmi_txdata <= `PID_DATA1; |
else |
utmi_txdata <= `PID_DATA0; |
end |
// Data to send |
else |
utmi_txdata <= usb_write_data; |
|
// Data sent? |
if (utmi_txready_i) |
begin |
// First byte is PID (not CRC'd) |
if (usb_tx_idx == 8'b0) |
begin |
usb_tx_idx <= usb_tx_idx + 8'd1; |
|
// Switch to next DATAx |
usb_ep_tx_data1[usb_endpoint] <= ~usb_ep_tx_data1[usb_endpoint]; |
end |
else |
begin |
|
// Pop FIFO |
usb_fifo_wr_pop[usb_endpoint] <= 1'b1; |
|
// Increment index |
usb_tx_idx <= usb_tx_idx + 8'd1; |
end |
end |
end |
|
//----------------------------------------- |
// TX_CRC1 (first byte) |
//----------------------------------------- |
STATE_TX_CRC1 : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
end |
|
//----------------------------------------- |
// TX_CRC (second byte) |
//----------------------------------------- |
STATE_TX_CRC2 : |
begin |
// Tx active |
utmi_txvalid_o <= 1'b1; |
|
// Data sent? |
if (utmi_txready_i) |
begin |
// Transfer now complete |
utmi_txvalid_o <= 1'b0; |
|
// Mark data as sent |
usb_ep_tx_pend[usb_endpoint] <= 1'b0; |
|
end |
end |
|
//----------------------------------------- |
// RX_TOKEN_COMPLETE |
//----------------------------------------- |
STATE_RX_TOKEN_COMPLETE : |
begin |
// Addressed to this device? |
if (usb_address == usb_this_device) |
begin |
//------------------------------- |
// SETUP transfer (EP0) |
//------------------------------- |
if (usb_rx_pid_setup) |
begin |
// New SETUP token resets Tx pending status on EP0 |
usb_ep_tx_pend[0] <= 1'b0; |
usb_fifo_wr_flush[0] <= 1'b1; |
end |
end |
end |
|
default : |
; |
|
endcase |
|
//----------------------------------------------------------------- |
// Peripheral Registers (Write) |
//----------------------------------------------------------------- |
if (we_i & stb_i) |
case (addr_i) |
|
`USB_FUNC_EP0 : |
begin |
usb_ep_tx_pend[0] <= data_i[`USB_EP_TX_READY]; |
usb_ep_tx_count[0] <= data_i[`USB_EP_COUNT]; |
end |
|
`USB_FUNC_EP1 : |
begin |
usb_ep_tx_pend[1] <= data_i[`USB_EP_TX_READY]; |
usb_ep_tx_count[1] <= data_i[`USB_EP_COUNT]; |
|
// Flush transmit FIFO? |
if (data_i[`USB_EP_TX_FLUSH]) |
usb_fifo_wr_flush[1] <= 1'b1; |
end |
`USB_FUNC_EP2 : |
begin |
usb_ep_tx_pend[2] <= data_i[`USB_EP_TX_READY]; |
usb_ep_tx_count[2] <= data_i[`USB_EP_COUNT]; |
|
// Flush transmit FIFO? |
if (data_i[`USB_EP_TX_FLUSH]) |
usb_fifo_wr_flush[2] <= 1'b1; |
end |
`USB_FUNC_EP3 : |
begin |
usb_ep_tx_pend[3] <= data_i[`USB_EP_TX_READY]; |
usb_ep_tx_count[3] <= data_i[`USB_EP_COUNT]; |
|
// Flush transmit FIFO? |
if (data_i[`USB_EP_TX_FLUSH]) |
usb_fifo_wr_flush[3] <= 1'b1; |
end |
|
`USB_FUNC_EP0_DATA: |
begin |
usb_fifo_wr_data[0] <= data_i[7:0]; |
usb_fifo_wr_push[0] <= 1'b1; |
end |
`USB_FUNC_EP1_DATA: |
begin |
usb_fifo_wr_data[1] <= data_i[7:0]; |
usb_fifo_wr_push[1] <= 1'b1; |
end |
`USB_FUNC_EP2_DATA: |
begin |
usb_fifo_wr_data[2] <= data_i[7:0]; |
usb_fifo_wr_push[2] <= 1'b1; |
end |
`USB_FUNC_EP3_DATA: |
begin |
usb_fifo_wr_data[3] <= data_i[7:0]; |
usb_fifo_wr_push[3] <= 1'b1; |
end |
|
default : |
; |
endcase |
|
//----------------------------------------- |
// USB Bus Reset (HOST->DEVICE) |
//----------------------------------------- |
if (utmi_rst_i) |
begin |
// Reset endpoint state |
usb_ep_tx_pend[0] <= 1'b0; |
usb_ep_tx_data1[0]<= 1'b0; |
usb_ep_tx_pend[1] <= 1'b0; |
usb_ep_tx_data1[1]<= 1'b0; |
usb_ep_tx_pend[2] <= 1'b0; |
usb_ep_tx_data1[2]<= 1'b0; |
usb_ep_tx_pend[3] <= 1'b0; |
usb_ep_tx_data1[3]<= 1'b0; |
|
// Reset to IDLE |
utmi_txvalid_o <= 1'b0; |
end |
end |
end |
|
//----------------------------------------------------------------- |
// Rx |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
// Other |
usb_rx_pid_out <= 1'b0; |
usb_rx_pid_in <= 1'b0; |
usb_rx_pid_setup <= 1'b0; |
|
usb_endpoint <= 2'b0; |
|
usb_rx_accept_data <= 1'b0; |
usb_rx_send_nak <= 1'b0; |
usb_rx_send_stall <= 1'b0; |
|
usb_rx_count <= 8'b0; |
usb_ep0_rx_setup <= 1'b0; |
|
usb_ep_stall[0] <= 1'b0; |
usb_ep_iso[0] <= 1'b0; |
usb_fifo_rd_push[0] <= 1'b0; |
usb_fifo_rd_flush[0]<= 1'b0; |
|
usb_ep_full[0] <= 1'b0; |
usb_ep_rx_count[0] <= 8'b0; |
usb_ep_crc_err[0] <= 1'b0; |
usb_ep_stall[1] <= 1'b0; |
usb_ep_iso[1] <= 1'b0; |
usb_fifo_rd_push[1] <= 1'b0; |
usb_fifo_rd_flush[1]<= 1'b0; |
|
usb_ep_full[1] <= 1'b0; |
usb_ep_rx_count[1] <= 8'b0; |
usb_ep_crc_err[1] <= 1'b0; |
usb_ep_stall[2] <= 1'b0; |
usb_ep_iso[2] <= 1'b0; |
usb_fifo_rd_push[2] <= 1'b0; |
usb_fifo_rd_flush[2]<= 1'b0; |
|
usb_ep_full[2] <= 1'b0; |
usb_ep_rx_count[2] <= 8'b0; |
usb_ep_crc_err[2] <= 1'b0; |
usb_ep_stall[3] <= 1'b0; |
usb_ep_iso[3] <= 1'b0; |
usb_fifo_rd_push[3] <= 1'b0; |
usb_fifo_rd_flush[3]<= 1'b0; |
|
usb_ep_full[3] <= 1'b0; |
usb_ep_rx_count[3] <= 8'b0; |
usb_ep_crc_err[3] <= 1'b0; |
usb_fifo_rd_in <= 8'b0; |
end |
else |
begin |
usb_fifo_rd_push[0] <= 1'b0; |
usb_fifo_rd_flush[0] <= 1'b0; |
usb_fifo_rd_push[1] <= 1'b0; |
usb_fifo_rd_flush[1] <= 1'b0; |
usb_fifo_rd_push[2] <= 1'b0; |
usb_fifo_rd_flush[2] <= 1'b0; |
usb_fifo_rd_push[3] <= 1'b0; |
usb_fifo_rd_flush[3] <= 1'b0; |
|
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_RX_IDLE : |
begin |
if (new_data_ready) |
begin |
// Decode PID |
case (utmi_data_r) |
|
`PID_OUT: |
begin |
usb_rx_pid_out <= 1'b1; |
usb_rx_pid_in <= 1'b0; |
usb_rx_pid_setup <= 1'b0; |
end |
|
`PID_IN: |
begin |
usb_rx_pid_out <= 1'b0; |
usb_rx_pid_in <= 1'b1; |
usb_rx_pid_setup <= 1'b0; |
end |
|
`PID_SETUP: |
begin |
usb_rx_pid_out <= 1'b0; |
usb_rx_pid_in <= 1'b0; |
usb_rx_pid_setup <= 1'b1; |
|
// Reset EP0 stall status on SETUP |
usb_rx_send_stall <= 1'b0; |
usb_ep_stall[0] <= 1'b0; |
end |
|
`PID_DATA0: |
begin |
if (usb_rx_accept_data && !usb_rx_send_stall) |
begin |
usb_rx_accept_data <= 1'b0; |
usb_rx_count <= 0; |
end |
end |
|
`PID_DATA1: |
begin |
if (usb_rx_accept_data && !usb_rx_send_stall) |
begin |
usb_rx_accept_data <= 1'b0; |
usb_rx_count <= 0; |
end |
end |
|
`PID_ACK: |
begin |
end |
|
`PID_NAK: |
begin |
end |
|
`PID_STALL: |
begin |
end |
|
default : |
begin |
// Reset state |
usb_rx_pid_out <= 1'b0; |
usb_rx_pid_in <= 1'b0; |
usb_rx_pid_setup <= 1'b0; |
end |
|
endcase |
end |
end |
|
//----------------------------------------- |
// TOKEN (IN/OUT/SETUP) (Address/Endpoint) |
//----------------------------------------- |
STATE_RX_TOKEN2 : |
begin |
if (new_data_ready) |
usb_endpoint[0] <= utmi_data_r[7]; |
end |
|
//----------------------------------------- |
// TOKEN (IN/OUT/SETUP) (Endpoint/CRC) |
//----------------------------------------- |
STATE_RX_TOKEN3 : |
begin |
if (new_data_ready) |
usb_endpoint[2-1:1] <= utmi_data_r[2-2:0]; |
end |
|
//----------------------------------------- |
// RX_TOKEN_COMPLETE |
//----------------------------------------- |
STATE_RX_TOKEN_COMPLETE : |
begin |
|
// Ignore following data unless addressed |
usb_rx_accept_data <= 1'b0; |
usb_rx_send_nak <= 1'b0; |
usb_rx_send_stall <= 1'b0; |
|
// Addressed to this device? |
if (usb_address == usb_this_device) |
begin |
//------------------------------- |
// OUT transfer (host -> device) |
//------------------------------- |
if (usb_rx_pid_out) |
begin |
usb_rx_accept_data <= !usb_ep_full[usb_endpoint]; |
usb_rx_send_nak <= usb_ep_full[usb_endpoint]; |
usb_rx_send_stall <= usb_ep_stall[usb_endpoint]; |
end |
//------------------------------- |
// SETUP transfer (EP0) |
//------------------------------- |
else if (usb_rx_pid_setup) |
begin |
// Must accept data! |
usb_rx_accept_data <= 1'b1; |
end |
end |
else |
begin |
end |
end |
|
//----------------------------------------- |
// RX_DATA |
//----------------------------------------- |
STATE_RX_DATA : |
begin |
if (new_data_ready) |
begin |
// Increment index |
usb_rx_count <= usb_rx_count + 1; |
|
// Write incoming data to FIFO |
usb_fifo_rd_in <= utmi_data_r; |
|
// Push data into correct EP FIFO |
usb_fifo_rd_push[usb_endpoint] <= 1'b1; |
|
end |
end |
|
//----------------------------------------- |
// RX_DATA_IGNORE |
//----------------------------------------- |
STATE_RX_DATA_IGNORE : |
begin |
end |
|
//----------------------------------------- |
// RX_DATA_COMPLETE |
//----------------------------------------- |
STATE_RX_DATA_COMPLETE : |
begin |
// Check for CRC error on receive data |
if (crc_sum != 16'hB001) |
begin |
|
// Signal error and reset FIFO |
usb_ep_full[usb_endpoint] <= 1'b0; |
usb_ep_crc_err[usb_endpoint] <= 1'b1; |
usb_fifo_rd_flush[usb_endpoint] <= 1'b1; |
usb_ep_rx_count[usb_endpoint] <= 8'b0; |
end |
// Good CRC |
else |
begin |
// Update status |
usb_ep_full[usb_endpoint] <= 1'b1; |
usb_ep_rx_count[usb_endpoint] <= usb_rx_count; |
|
// Endpoint 0 is different |
if (usb_endpoint == 2'b0) |
begin |
usb_ep0_rx_setup <= usb_rx_pid_setup; |
end |
end |
end |
|
default : |
; |
|
endcase |
|
//----------------------------------------------------------------- |
// Peripheral Registers (Write) |
//----------------------------------------------------------------- |
if (we_i & stb_i) |
case (addr_i) |
|
`USB_FUNC_EP0 : |
begin |
// Clear receive status? |
if (data_i[`USB_EP_RX_ACK]) |
begin |
usb_ep_full[0] <= 1'b0; |
usb_ep0_rx_setup <= 1'b0; |
usb_ep_crc_err[0] <= 1'b0; |
usb_fifo_rd_flush[0] <= 1'b1; |
end |
usb_ep_iso[0] <= 1'b0; |
|
// Respond with STALL on EP0? |
if (data_i[`USB_EP_STALL]) |
usb_ep_stall[0] <= 1'b1; |
end |
|
`USB_FUNC_EP1 : |
begin |
// Clear receive status? |
if (data_i[`USB_EP_RX_ACK]) |
begin |
usb_ep_full[1] <= 1'b0; |
usb_ep_crc_err[1] <= 1'b0; |
usb_fifo_rd_flush[1] <= 1'b1; |
end |
usb_ep_iso[1] <= data_i[`USB_EP_ISO]; |
|
// Endpoint stalled? |
usb_ep_stall[1] <= data_i[`USB_EP_STALL]; |
end |
`USB_FUNC_EP2 : |
begin |
// Clear receive status? |
if (data_i[`USB_EP_RX_ACK]) |
begin |
usb_ep_full[2] <= 1'b0; |
usb_ep_crc_err[2] <= 1'b0; |
usb_fifo_rd_flush[2] <= 1'b1; |
end |
usb_ep_iso[2] <= data_i[`USB_EP_ISO]; |
|
// Endpoint stalled? |
usb_ep_stall[2] <= data_i[`USB_EP_STALL]; |
end |
`USB_FUNC_EP3 : |
begin |
// Clear receive status? |
if (data_i[`USB_EP_RX_ACK]) |
begin |
usb_ep_full[3] <= 1'b0; |
usb_ep_crc_err[3] <= 1'b0; |
usb_fifo_rd_flush[3] <= 1'b1; |
end |
usb_ep_iso[3] <= data_i[`USB_EP_ISO]; |
|
// Endpoint stalled? |
usb_ep_stall[3] <= data_i[`USB_EP_STALL]; |
end |
|
default : |
; |
endcase |
|
//----------------------------------------- |
// USB Bus Reset (HOST->DEVICE) |
//----------------------------------------- |
if (utmi_rst_i) |
begin |
// Reset endpoint state |
usb_ep_full[0] <= 1'b0; |
usb_ep_rx_count[0]<= 8'b0; |
usb_ep_full[1] <= 1'b0; |
usb_ep_rx_count[1]<= 8'b0; |
usb_ep_full[2] <= 1'b0; |
usb_ep_rx_count[2]<= 8'b0; |
usb_ep_full[3] <= 1'b0; |
usb_ep_rx_count[3]<= 8'b0; |
|
usb_ep0_rx_setup <= 1'b0; |
end |
end |
end |
|
//----------------------------------------------------------------- |
// CRC generation |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
crc_sum <= 16'hFFFF; |
end |
else |
begin |
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_RX_IDLE : |
begin |
if (new_data_ready) |
begin |
// Data packet? |
if (utmi_data_r == `PID_DATA0 || utmi_data_r == `PID_DATA1) |
if (usb_rx_accept_data && !usb_rx_send_stall) |
crc_sum <= 16'hFFFF; |
end |
end |
|
//----------------------------------------- |
// RX_DATA |
//----------------------------------------- |
STATE_RX_DATA : |
begin |
if (new_data_ready) |
crc_sum <= crc_out; |
end |
|
//----------------------------------------- |
// TX_DATA |
//----------------------------------------- |
STATE_TX_DATA : |
begin |
// Data sent? |
if (utmi_txready_i) |
begin |
// First byte is PID (not CRC'd) |
if (usb_tx_idx == 8'b0) |
begin |
// Reset CRC16 |
crc_sum <= 16'hFFFF; |
end |
else |
begin |
// Next CRC start value |
crc_sum <= crc_out; |
end |
end |
end |
|
//----------------------------------------- |
// TX_CRC (generate) |
//----------------------------------------- |
STATE_TX_CRC : |
begin |
// Next CRC start value |
crc_sum <= crc_sum ^ 16'hFFFF; |
end |
|
default : |
; |
|
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Address / Frame / Misc |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
usb_en_o <= 1'b0; |
|
usb_frame_number <= 11'h000; |
usb_address <= 7'h00; |
usb_this_device <= 7'h00; |
usb_next_address <= 7'h00; |
usb_address_pending <= 1'b0; |
usb_event_bus_reset <= 1'b0; |
end |
else |
begin |
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// SOF (BYTE 2) |
//----------------------------------------- |
STATE_RX_SOF2 : |
begin |
if (new_data_ready) |
usb_frame_number[7:0] <= utmi_data_r; |
end |
|
//----------------------------------------- |
// SOF (BYTE 3) |
//----------------------------------------- |
STATE_RX_SOF3 : |
begin |
if (new_data_ready) |
usb_frame_number[10:8] <= utmi_data_r[2:0]; |
end |
|
//----------------------------------------- |
// TOKEN (IN/OUT/SETUP) (Address/Endpoint) |
//----------------------------------------- |
STATE_RX_TOKEN2 : |
begin |
if (new_data_ready) |
usb_address <= utmi_data_r[6:0]; |
end |
|
//----------------------------------------- |
// TX_CRC (second byte) |
//----------------------------------------- |
STATE_TX_CRC2 : |
begin |
// Data sent? |
if (utmi_txready_i) |
begin |
// Address changes actually occur in status phase |
if (usb_address_pending) |
begin |
usb_address_pending <= 1'b0; |
usb_this_device <= usb_next_address; |
|
end |
end |
end |
|
default : |
; |
|
endcase |
|
//----------------------------------------------------------------- |
// Peripheral Registers (Write) |
//----------------------------------------------------------------- |
if (we_i & stb_i) |
case (addr_i) |
|
`USB_FUNC_CTRL : |
begin |
// Set new device address? |
if (data_i[`USB_FUNC_CTRL_ADDR_SET]) |
begin |
|
// Device address change occurs in the status stage |
usb_next_address <= data_i[`USB_FUNC_CTRL_ADDR]; |
usb_address_pending <= 1'b1; |
end |
|
usb_en_o <= data_i[`USB_FUNC_CTRL_PULLUP_EN]; |
|
// Clear bus reset event status |
usb_event_bus_reset <= 1'b0; |
end |
|
default : |
; |
endcase |
|
//----------------------------------------- |
// USB Bus Reset (HOST->DEVICE) |
//----------------------------------------- |
if (utmi_rst_i) |
begin |
usb_event_bus_reset <= 1'b1; |
|
// Reset SOF |
usb_frame_number <= 11'h000; |
|
// Reset device address |
usb_this_device <= 7'h00; |
usb_address_pending <= 1'b0; |
end |
end |
end |
|
//----------------------------------------------------------------- |
// Interrupts |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
intr_o <= 1'b0; |
|
// Interrupt control |
usb_int_en_tx <= 1'b0; |
usb_int_en_rx <= 1'b0; |
usb_int_en_sof <= 1'b0; |
end |
else |
begin |
intr_o <= 1'b0; |
|
//----------------------------------------- |
// State Machine |
//----------------------------------------- |
case (usb_state) |
|
//----------------------------------------- |
// SOF (BYTE 3) |
//----------------------------------------- |
STATE_RX_SOF3 : |
begin |
if (new_data_ready) |
begin |
// Generate interrupt? |
if (usb_int_en_sof) |
intr_o <= 1'b1; |
end |
end |
|
//----------------------------------------- |
// RX_DATA_COMPLETE |
//----------------------------------------- |
STATE_RX_DATA_COMPLETE : |
begin |
// Generate interrupt on Rx complete? |
if (usb_int_en_rx) |
intr_o <= 1'b1; |
end |
|
//----------------------------------------- |
// TX_CRC (second byte) |
//----------------------------------------- |
STATE_TX_CRC2 : |
begin |
// Data sent? |
if (utmi_txready_i) |
begin |
// Generate interrupt on Tx complete? |
if (usb_int_en_tx) |
intr_o <= 1'b1; |
end |
end |
|
default : |
; |
|
endcase |
|
//----------------------------------------------------------------- |
// Peripheral Registers (Write) |
//----------------------------------------------------------------- |
if (we_i & stb_i) |
case (addr_i) |
|
`USB_FUNC_CTRL : |
begin |
// Interrupt control |
usb_int_en_tx <= data_i[`USB_FUNC_CTRL_INT_EN_TX]; |
usb_int_en_rx <= data_i[`USB_FUNC_CTRL_INT_EN_RX]; |
usb_int_en_sof <= data_i[`USB_FUNC_CTRL_INT_EN_SOF]; |
end |
|
default : |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Peripheral Registers (Read) |
//----------------------------------------------------------------- |
always @ * |
begin |
case (addr_i) |
|
`USB_FUNC_STAT : |
begin |
data_o = 32'b0; |
data_o[`USB_FUNC_STAT_FRAME] = usb_frame_number; |
data_o[`USB_FUNC_STAT_LS_RXP] = utmi_linestate_i[0]; |
data_o[`USB_FUNC_STAT_LS_RXN] = utmi_linestate_i[1]; |
data_o[`USB_FUNC_STAT_RST] = usb_event_bus_reset; |
end |
|
`USB_FUNC_EP0: |
begin |
data_o = 32'b0; |
data_o[`USB_EP_COUNT] = usb_ep_rx_count[0]; |
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[0]; |
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[0]; |
data_o[`USB_EP_RX_SETUP] = usb_ep0_rx_setup; |
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[0]; |
data_o[`USB_EP_STALL] = usb_ep_stall[0]; |
end |
|
`USB_FUNC_EP1: |
begin |
data_o = 32'b0; |
data_o[`USB_EP_COUNT] = usb_ep_rx_count[1]; |
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[1]; |
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[1]; |
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[1]; |
data_o[`USB_EP_STALL] = usb_ep_stall[1]; |
end |
`USB_FUNC_EP2: |
begin |
data_o = 32'b0; |
data_o[`USB_EP_COUNT] = usb_ep_rx_count[2]; |
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[2]; |
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[2]; |
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[2]; |
data_o[`USB_EP_STALL] = usb_ep_stall[2]; |
end |
`USB_FUNC_EP3: |
begin |
data_o = 32'b0; |
data_o[`USB_EP_COUNT] = usb_ep_rx_count[3]; |
data_o[`USB_EP_TX_READY] = usb_ep_tx_pend[3]; |
data_o[`USB_EP_RX_AVAIL] = usb_ep_full[3]; |
data_o[`USB_EP_RX_CRC_ERR]= usb_ep_crc_err[3]; |
data_o[`USB_EP_STALL] = usb_ep_stall[3]; |
end |
|
`USB_FUNC_EP0_DATA: |
data_o = {24'b0, usb_fifo_rd_out[0]}; |
`USB_FUNC_EP1_DATA: |
data_o = {24'b0, usb_fifo_rd_out[1]}; |
`USB_FUNC_EP2_DATA: |
data_o = {24'b0, usb_fifo_rd_out[2]}; |
`USB_FUNC_EP3_DATA: |
data_o = {24'b0, usb_fifo_rd_out[3]}; |
|
default : |
data_o = 32'h00000000; |
endcase |
end |
|
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
usb_fifo_rd_pop[0] <= 1'b0; |
usb_fifo_rd_pop[1] <= 1'b0; |
usb_fifo_rd_pop[2] <= 1'b0; |
usb_fifo_rd_pop[3] <= 1'b0; |
end |
else |
begin |
|
usb_fifo_rd_pop[0] <= 1'b0; |
usb_fifo_rd_pop[1] <= 1'b0; |
usb_fifo_rd_pop[2] <= 1'b0; |
usb_fifo_rd_pop[3] <= 1'b0; |
|
// Read cycle? |
if (~we_i & stb_i) |
case (addr_i) |
`USB_FUNC_EP0_DATA: |
usb_fifo_rd_pop[0] <= 1'b1; |
`USB_FUNC_EP1_DATA: |
usb_fifo_rd_pop[1] <= 1'b1; |
`USB_FUNC_EP2_DATA: |
usb_fifo_rd_pop[2] <= 1'b1; |
`USB_FUNC_EP3_DATA: |
usb_fifo_rd_pop[3] <= 1'b1; |
|
default : |
; |
endcase |
end |
end |
|
// Decode endpoint to FIFO |
always @ * |
begin |
usb_write_data = 8'b0; |
case (usb_endpoint) |
0 : usb_write_data = usb_fifo_wr_out[0]; |
1 : usb_write_data = usb_fifo_wr_out[1]; |
2 : usb_write_data = usb_fifo_wr_out[2]; |
3 : usb_write_data = usb_fifo_wr_out[3]; |
endcase |
end |
|
//----------------------------------------------------------------- |
// Assignments |
//----------------------------------------------------------------- |
assign utmi_data_w = (usb_state == STATE_TX_CRC1) ? crc_sum[7:0] : |
(usb_state == STATE_TX_CRC2) ? crc_sum[15:8] : |
utmi_txdata; |
|
assign crc_data_in = (usb_state == STATE_RX_DATA || usb_state == STATE_RX_IDLE) ? utmi_data_r : usb_write_data; |
|
endmodule |
/trunk/rtl/usbf_fifo.v
0,0 → 1,141
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: USB FIFO - simple FIFO |
//----------------------------------------------------------------- |
module usbf_fifo |
( |
clk_i, |
rst_i, |
|
data_i, |
push_i, |
|
full_o, |
empty_o, |
|
data_o, |
pop_i, |
|
flush_i |
); |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
parameter WIDTH = 8; |
parameter DEPTH = 4; |
parameter ADDR_W = 2; |
parameter COUNT_W = ADDR_W + 1; |
|
//----------------------------------------------------------------- |
// I/O |
//----------------------------------------------------------------- |
input clk_i /*verilator public*/; |
input rst_i /*verilator public*/; |
input [WIDTH-1:0] data_i /*verilator public*/; |
input push_i /*verilator public*/; |
output full_o /*verilator public*/; |
output empty_o /*verilator public*/; |
output [WIDTH-1:0] data_o /*verilator public*/; |
input pop_i /*verilator public*/; |
input flush_i /*verilator public*/; |
|
//----------------------------------------------------------------- |
// Registers |
//----------------------------------------------------------------- |
reg [WIDTH-1:0] ram [DEPTH-1:0]; |
reg [ADDR_W-1:0] rd_ptr; |
reg [ADDR_W-1:0] wr_ptr; |
reg [COUNT_W-1:0] count; |
|
//----------------------------------------------------------------- |
// Sequential |
//----------------------------------------------------------------- |
always @ (posedge clk_i or posedge rst_i) |
begin |
if (rst_i == 1'b1) |
begin |
count <= {(COUNT_W) {1'b0}}; |
rd_ptr <= {(ADDR_W) {1'b0}}; |
wr_ptr <= {(ADDR_W) {1'b0}}; |
end |
else |
begin |
|
if (flush_i) |
begin |
count <= {(COUNT_W) {1'b0}}; |
rd_ptr <= {(ADDR_W) {1'b0}}; |
wr_ptr <= {(ADDR_W) {1'b0}}; |
end |
|
// Push |
if (push_i & ~full_o) |
begin |
ram[wr_ptr] <= data_i; |
wr_ptr <= wr_ptr + 1; |
end |
|
// Pop |
if (pop_i & ~empty_o) |
begin |
rd_ptr <= rd_ptr + 1; |
end |
|
// Count up |
if ((push_i & ~full_o) & ~(pop_i & ~empty_o)) |
begin |
count <= count + 1; |
end |
// Count down |
else if (~(push_i & ~full_o) & (pop_i & ~empty_o)) |
begin |
count <= count - 1; |
end |
end |
end |
|
//------------------------------------------------------------------- |
// Combinatorial |
//------------------------------------------------------------------- |
assign full_o = (count == DEPTH); |
assign empty_o = (count == 0); |
|
assign data_o = ram[rd_ptr]; |
|
endmodule |