diff --git a/.gitignore b/.gitignore index ae69db1d..27e86337 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,9 @@ _build/ *.pyc *.expect *.so -*/logs/* +**/bin/** +**/tests/result/* +**/logs*/** test_results.csv .DS_Store _README/** @@ -30,9 +32,14 @@ Installs/ tests/bin.txt tests/log tests/test_**/**test_xs2.xn -tests/test_**/**test_xs3_500.xn -tests/test_**/**test_xs3_540.xn -tests/test_**/**test_xs3_600.xn -tests/test_**/**test_xs3_800.xn +tests/test_**/**test_xs3_*.xn **/venv/** *.gtkw +**/tests/build/** +**/tests/doc/** +**/build/html/** +**/tests/assets/** +**/build/docstrees/** +tests/report.html +tests/testplan.rst +build/doctrees/environment.pickle diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 12d65f97..8e40e0b2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ lib_xud Change Log ================== +2.1.0 +----- + + * CHANGE: Various optimisations to aid corner-case timings on XS3 based + devices + * CHANGE: Some API functions re-authored in C (from Assembly) + * CHANGE: Testbench now more accurately models XS3 based devices + 2.0.2 ----- diff --git a/README.rst b/README.rst index b815cd4a..bc9c04f3 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,8 @@ The library provides functionality to act as a USB *device* only. This library is for use with xCORE-200 Series or xCORE-AI series devices only, previous generations of xCORE devices are no longer supported. +Note, at points lib_xud will run in "fast mode" this is a requirement to meet timing. + Features ........ diff --git a/examples/AN00129_hid_class/Makefile b/examples/AN00129_hid_class/Makefile index 216c1563..9eccf06a 100644 --- a/examples/AN00129_hid_class/Makefile +++ b/examples/AN00129_hid_class/Makefile @@ -18,6 +18,7 @@ BUILD_FLAGS = -O3 -report -fxscope XCC_FLAGS_200 = $(BUILD_FLAGS) XCC_FLAGS_AI = $(BUILD_FLAGS) +XCC_FLAGS_AI_C = $(BUILD_FLAGS) USED_MODULES = lib_xud @@ -28,10 +29,15 @@ USED_MODULES = lib_xud # In this case, the target depends on the build configuration. ifeq ($(CONFIG),AI) TARGET = XCORE-AI-EXPLORER +EXCLUDE_FILES = main.c +else ifeq ($(CONFIG),AI_C) +TARGET = XCORE-AI-EXPLORER +EXCLUDE_FILES = main.xc \ + endpoint0.xc else TARGET = XCORE-200-EXPLORER +EXCLUDE_FILES = main.c endif - #============================================================================= # The following part of the Makefile includes the common build infrastructure # for compiling XMOS applications. You should not need to edit below here. diff --git a/examples/AN00129_hid_class/doc/rst/AN00129.rst b/examples/AN00129_hid_class/doc/rst/AN00129.rst index 18582b7e..d5fe9ead 100644 --- a/examples/AN00129_hid_class/doc/rst/AN00129.rst +++ b/examples/AN00129_hid_class/doc/rst/AN00129.rst @@ -107,29 +107,20 @@ Looking at this in a more detail you can see the following: Configuring the USB Device ID ............................. -The USB ID values used for vendor id, product id and device version number are defined in the file ``endpoint0.xc``. These are used by the host machine to determine the vendor of the device (in this case XMOS) and the product plus the firmware version. +The USB ID values used for vendor ID, product ID and device version number are defined in the file ``endpoint0.xc``. These are used by the host machine to determine the vendor of the device (in this case XMOS) and the product plus the firmware version. -.. literalinclude:: endpoint0.xc - :start-on: USB HID Device - :end-before: Standard - -USB HID Class specific defines -.............................. - -The USB HID Class is configured in the file ``endpoint0.xc``. Below there are a set of standard defines which are used to configure the USB device descriptors to setup a USB HID class device running on an xCORE-USB microcontroller. - -.. literalinclude:: endpoint0.xc - :start-on: Standard HID - :end-before: Device Descriptor +.. literalinclude:: hid_defs.h + :start-on: /* USB HID Device Product Defines + :end-before: /* Device Descriptor |newpage| USB Device Descriptor ..................... -``endpoint0.xc`` is where the standard USB device descriptor is declared for the HID class device. Below is the structure which contains this descriptor. This will be requested by the host when the device is enumerated on the USB bus. +``hid_defs.h`` is where the standard USB device descriptor is declared for the HID class device. Below is the structure which contains this descriptor. This will be requested by the host when the device is enumerated on the USB bus. -.. literalinclude:: endpoint0.xc +.. literalinclude:: hid_defs.h :start-on: devDesc :end-on: } @@ -142,7 +133,7 @@ USB Configuration Descriptor The USB configuration descriptor is used to configure the device in terms of the device class and the endpoint setup. For the USB HID class device the configuration descriptor which is read by the host is as follows. -.. literalinclude:: endpoint0.xc +.. literalinclude:: hid_defs.h :start-on: cfgDesc :end-on: } @@ -155,7 +146,7 @@ USB HID Class Descriptor For USB HID class devices there is a descriptor that is device in the HID device class specification which needs to be provided to the host in addition to the default decriptor types described above. The host will request this descriptor from the device when it enumerates as a HID class device. The HID descriptor for our mouse demo application is as follows. -.. literalinclude:: endpoint0.xc +.. literalinclude:: hid_defs.h :start-on: hidDescriptor :end-on: } @@ -166,7 +157,7 @@ USB HID Report Descriptor Along with the HID class descriptor there is a HID report descriptor which describes to the host the usage of the device and the data it will be reporting when it communicates. As HID devices are supported by standard drivers on a host machine this allow a level of configuration between the host and the device. The HID report descriptor for our example application is below. -.. literalinclude:: endpoint0.xc +.. literalinclude:: hid_defs.h :start-on: hidReportDesc :end-on: } @@ -179,7 +170,7 @@ There are two further descriptors within this file relating to the configuration of the USB Printer Class. These sections should also be modified to match the capabilities of the printer. -.. literalinclude:: endpoint0.xc +.. literalinclude:: hid_defs.h :start-on: String table :end-on: } @@ -191,7 +182,7 @@ USB HID Class requests Inside ``endpoint0.xc`` there is a function for handling the USB HID device class specific requests. The code for handling these requests is shown as follows: .. literalinclude:: endpoint0.xc - :lines: 142-198 + :lines: 16-74 These HID specific requests are implemented by the application as they do not form part of the standard requests which have to be accepted by all device classes via endpoint0. @@ -203,7 +194,7 @@ USB HID Class Endpoint0 The function ``Endpoint0()`` contains the code for dealing with device requests made from the host to the standard endpoint0 which is present in all USB devices. In addition to requests required for all devices, the code handles the requests specific to the HID class. .. literalinclude:: endpoint0.xc - :lines: 201-301 + :lines: 75-176 |newpage| diff --git a/examples/AN00129_hid_class/src/endpoint0.xc b/examples/AN00129_hid_class/src/endpoint0.xc index c0050f67..715b196d 100644 --- a/examples/AN00129_hid_class/src/endpoint0.xc +++ b/examples/AN00129_hid_class/src/endpoint0.xc @@ -8,131 +8,6 @@ #include "hid.h" #include "hid_defs.h" -/* USB HID Device Product Defines */ -#define BCD_DEVICE 0x1000 -#define VENDOR_ID 0x20B1 -#define PRODUCT_ID 0x1010 - -/* Device Descriptor */ -static unsigned char devDesc[] = -{ - 0x12, /* 0 bLength */ - USB_DESCTYPE_DEVICE, /* 1 bdescriptorType */ - 0x00, /* 2 bcdUSB */ - 0x02, /* 3 bcdUSB */ - 0x00, /* 4 bDeviceClass */ - 0x00, /* 5 bDeviceSubClass */ - 0x00, /* 6 bDeviceProtocol */ - 0x40, /* 7 bMaxPacketSize */ - (VENDOR_ID & 0xFF), /* 8 idVendor */ - (VENDOR_ID >> 8), /* 9 idVendor */ - (PRODUCT_ID & 0xFF), /* 10 idProduct */ - (PRODUCT_ID >> 8), /* 11 idProduct */ - (BCD_DEVICE & 0xFF), /* 12 bcdDevice */ - (BCD_DEVICE >> 8), /* 13 bcdDevice */ - 0x01, /* 14 iManufacturer */ - 0x02, /* 15 iProduct */ - 0x00, /* 16 iSerialNumber */ - 0x01 /* 17 bNumConfigurations */ -}; - - -/* Configuration Descriptor */ -static unsigned char cfgDesc[] = { - 0x09, /* 0 bLength */ - 0x02, /* 1 bDescriptortype */ - 0x22, 0x00, /* 2 wTotalLength */ - 0x01, /* 4 bNumInterfaces */ - 0x01, /* 5 bConfigurationValue */ - 0x03, /* 6 iConfiguration */ - 0x80, /* 7 bmAttributes */ - 0xC8, /* 8 bMaxPower */ - - 0x09, /* 0 bLength */ - 0x04, /* 1 bDescriptorType */ - 0x00, /* 2 bInterfacecNumber */ - 0x00, /* 3 bAlternateSetting */ - 0x01, /* 4: bNumEndpoints */ - 0x03, /* 5: bInterfaceClass */ - 0x00, /* 6: bInterfaceSubClass */ - 0x02, /* 7: bInterfaceProtocol*/ - 0x00, /* 8 iInterface */ - - 0x09, /* 0 bLength. Note this is currently - replicated in hidDescriptor[] below */ - 0x21, /* 1 bDescriptorType (HID) */ - 0x11, /* 2 bcdHID */ - 0x01, /* 3 bcdHID */ - 0x00, /* 4 bCountryCode */ - 0x01, /* 5 bNumDescriptors */ - 0x22, /* 6 bDescriptorType[0] (Report) */ - 0x32, /* 7 wDescriptorLength */ - 0x00, /* 8 wDescriptorLength */ - - 0x07, /* 0 bLength */ - 0x05, /* 1 bDescriptorType */ - 0x81, /* 2 bEndpointAddress */ - 0x03, /* 3 bmAttributes */ - 0x40, /* 4 wMaxPacketSize */ - 0x00, /* 5 wMaxPacketSize */ - 0x0a /* 6 bInterval */ -}; - -static unsigned char hidDescriptor[] = -{ - 0x09, /* 0 bLength */ - 0x21, /* 1 bDescriptorType (HID) */ - 0x11, /* 2 bcdHID */ - 0x01, /* 3 bcdHID */ - 0x00, /* 4 bCountryCode */ - 0x01, /* 5 bNumDescriptors */ - 0x22, /* 6 bDescriptorType[0] (Report) */ - 0x32, /* 7 wDescriptorLength */ - 0x00, /* 8 wDescriptorLength */ -}; - -/* HID Report Descriptor */ -static unsigned char hidReportDescriptor[] = -{ - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x02, /* Usage (Mouse) */ - 0xA1, 0x01, /* Collection (Application) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xA1, 0x00, /* Collection (Physical) */ - 0x05, 0x09, /* Usage Page (Buttons) */ - 0x19, 0x01, /* Usage Minimum (01) */ - 0x29, 0x03, /* Usage Maximum (03) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x03, /* Report Count (3) */ - 0x75, 0x01, /* Report Size (1) */ - 0x81, 0x02, /* Input (Data,Variable,Absolute); 3 button bits */ - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x05, /* Report Size (5) */ - 0x81, 0x01, /* Input(Constant); 5 bit padding */ - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x30, /* Usage (X) */ - 0x09, 0x31, /* Usage (Y) */ - 0x15, 0x81, /* Logical Minimum (-127) */ - 0x25, 0x7F, /* Logical Maximum (127) */ - 0x75, 0x08, /* Report Size (8) */ - 0x95, 0x02, /* Report Count (2) */ - 0x81, 0x06, /* Input (Data,Variable,Relative); 2 position bytes (X & Y) */ - 0xC0, /* End Collection */ - 0xC0 /* End Collection */ -}; - -unsafe{ -/* String table */ -static char * unsafe stringDescriptors[]= -{ - "\x09\x04", // Language ID string (US English) - "XMOS", // iManufacturer - "Example HID Mouse", // iProduct - "Config", // iConfiguration -}; -} - /* It is essential that HID_REPORT_BUFFER_SIZE, defined in hid_defs.h, matches the */ /* infered length of the report described in hidReportDescriptor above. In this case */ /* it is three bytes, three button bits padded to a byte, plus a byte each for X & Y */ diff --git a/examples/AN00129_hid_class/src/hid_defs.h b/examples/AN00129_hid_class/src/hid_defs.h index d246a16e..8afd235f 100644 --- a/examples/AN00129_hid_class/src/hid_defs.h +++ b/examples/AN00129_hid_class/src/hid_defs.h @@ -9,6 +9,129 @@ /* Global report buffer */ #define HID_REPORT_BUFFER_SIZE 3 -extern char g_reportBuffer[HID_REPORT_BUFFER_SIZE]; +extern unsigned char g_reportBuffer[HID_REPORT_BUFFER_SIZE]; + +/* USB HID Device Product Defines */ +#define BCD_DEVICE 0x1000 +#define VENDOR_ID 0x20B1 +#define PRODUCT_ID 0x1010 + +/* Device Descriptor */ +static unsigned char devDesc[] = +{ + 0x12, /* 0 bLength */ + USB_DESCTYPE_DEVICE, /* 1 bdescriptorType */ + 0x00, /* 2 bcdUSB */ + 0x02, /* 3 bcdUSB */ + 0x00, /* 4 bDeviceClass */ + 0x00, /* 5 bDeviceSubClass */ + 0x00, /* 6 bDeviceProtocol */ + 0x40, /* 7 bMaxPacketSize */ + (VENDOR_ID & 0xFF), /* 8 idVendor */ + (VENDOR_ID >> 8), /* 9 idVendor */ + (PRODUCT_ID & 0xFF), /* 10 idProduct */ + (PRODUCT_ID >> 8), /* 11 idProduct */ + (BCD_DEVICE & 0xFF), /* 12 bcdDevice */ + (BCD_DEVICE >> 8), /* 13 bcdDevice */ + 0x01, /* 14 iManufacturer */ + 0x02, /* 15 iProduct */ + 0x00, /* 16 iSerialNumber */ + 0x01 /* 17 bNumConfigurations */ +}; + + +/* Configuration Descriptor */ +static unsigned char cfgDesc[] = { + 0x09, /* 0 bLength */ + 0x02, /* 1 bDescriptortype */ + 0x22, 0x00, /* 2 wTotalLength */ + 0x01, /* 4 bNumInterfaces */ + 0x01, /* 5 bConfigurationValue */ + 0x03, /* 6 iConfiguration */ + 0x80, /* 7 bmAttributes */ + 0xC8, /* 8 bMaxPower */ + + 0x09, /* 0 bLength */ + 0x04, /* 1 bDescriptorType */ + 0x00, /* 2 bInterfacecNumber */ + 0x00, /* 3 bAlternateSetting */ + 0x01, /* 4: bNumEndpoints */ + 0x03, /* 5: bInterfaceClass */ + 0x00, /* 6: bInterfaceSubClass */ + 0x02, /* 7: bInterfaceProtocol*/ + 0x00, /* 8 iInterface */ + + 0x09, /* 0 bLength. Note this is currently + replicated in hidDescriptor[] below */ + 0x21, /* 1 bDescriptorType (HID) */ + 0x11, /* 2 bcdHID */ + 0x01, /* 3 bcdHID */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ + 0x22, /* 6 bDescriptorType[0] (Report) */ + 0x32, /* 7 wDescriptorLength */ + 0x00, /* 8 wDescriptorLength */ + + 0x07, /* 0 bLength */ + 0x05, /* 1 bDescriptorType */ + 0x81, /* 2 bEndpointAddress */ + 0x03, /* 3 bmAttributes */ + 0x40, /* 4 wMaxPacketSize */ + 0x00, /* 5 wMaxPacketSize */ + 0x0a /* 6 bInterval */ +}; + +static unsigned char hidDescriptor[] = +{ + 0x09, /* 0 bLength */ + 0x21, /* 1 bDescriptorType (HID) */ + 0x11, /* 2 bcdHID */ + 0x01, /* 3 bcdHID */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ + 0x22, /* 6 bDescriptorType[0] (Report) */ + 0x32, /* 7 wDescriptorLength */ + 0x00, /* 8 wDescriptorLength */ +}; + +/* HID Report Descriptor */ +static unsigned char hidReportDescriptor[] = +{ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xA1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Buttons) */ + 0x19, 0x01, /* Usage Minimum (01) */ + 0x29, 0x03, /* Usage Maximum (03) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data,Variable,Absolute); 3 button bits */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x01, /* Input(Constant); 5 bit padding */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x06, /* Input (Data,Variable,Relative); 2 position bytes (X & Y) */ + 0xC0, /* End Collection */ + 0xC0 /* End Collection */ +}; + +/* String table */ +static char * stringDescriptors[]= +{ + "\x09\x04", // Language ID string (US English) + "XMOS", // iManufacturer + "Example HID Mouse", // iProduct + "Config", // iConfiguration +}; #endif // HID_DEFS_H diff --git a/examples/AN00129_hid_class/src/main.c b/examples/AN00129_hid_class/src/main.c new file mode 100644 index 00000000..bff72567 --- /dev/null +++ b/examples/AN00129_hid_class/src/main.c @@ -0,0 +1,292 @@ +// Copyright 2015-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include +#include +#include + +#include +#include "hid_defs.h" +#include "hid.h" + +#include + +/* Number of Endpoints used by this app */ +#define EP_COUNT_OUT 1 +#define EP_COUNT_IN 2 + +/* Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also + * if the endpoint wishes to be informed of USB bus resets + */ +XUD_EpType epTypeTableOut[EP_COUNT_OUT] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE }; +XUD_EpType epTypeTableIn[EP_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_BUL }; + +/* It is essential that HID_REPORT_BUFFER_SIZE, defined in hid_defs.h, matches the */ +/* infered length of the report described in hidReportDescriptor above. In this case */ +/* it is three bytes, three button bits padded to a byte, plus a byte each for X & Y */ +unsigned char g_reportBuffer[HID_REPORT_BUFFER_SIZE] = {0, 0, 0}; + +/* HID Class Requests */ +XUD_Result_t HidInterfaceClassRequests(XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t sp) +{ + unsigned buffer[64]; + + switch(sp.bRequest) + { + case HID_GET_REPORT: + + /* Mandatory. Allows sending of report over control pipe */ + /* Send a hid report - note the use of unsafe due to shared mem */ + buffer[0] = g_reportBuffer[0]; + return XUD_DoGetRequest(c_ep0_out, c_ep0_in, (void*)buffer, 4, sp.wLength); + break; + + case HID_GET_IDLE: + /* Return the current Idle rate - optional for a HID mouse */ + + /* Do nothing - i.e. STALL */ + break; + + case HID_GET_PROTOCOL: + /* Required only devices supporting boot protocol devices, + * which this example does not */ + + /* Do nothing - i.e. STALL */ + break; + + case HID_SET_REPORT: + /* The host sends an Output or Feature report to a HID + * using a cntrol transfer - optional */ + + /* Do nothing - i.e. STALL */ + break; + + case HID_SET_IDLE: + /* Set the current Idle rate - this is optional for a HID mouse + * (Bandwidth can be saved by limiting the frequency that an + * interrupt IN EP when the data hasn't changed since the last + * report */ + + /* Do nothing - i.e. STALL */ + break; + + case HID_SET_PROTOCOL: + /* Required only devices supporting boot protocol devices, + * which this example does not */ + + /* Do nothing - i.e. STALL */ + break; + } + + return XUD_RES_ERR; +} + +DECLARE_JOB(Endpoint0, (chanend_t, chanend_t)); +/* Endpoint 0 Task */ +void Endpoint0(chanend_t chan_ep0_out, chanend_t chan_ep0_in) +{ + USB_SetupPacket_t sp; + + unsigned bmRequestType; + XUD_BusSpeed_t usbBusSpeed; + + printf("Endpoint0: out: %x\n", chan_ep0_out); + printf("Endpoint0: in: %x\n", chan_ep0_in); + + XUD_ep ep0_out = XUD_InitEp(chan_ep0_out); + XUD_ep ep0_in = XUD_InitEp(chan_ep0_in); + + while(1) + { + /* Returns XUD_RES_OKAY on success */ + XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); + + if(result == XUD_RES_OKAY) + { + /* Set result to ERR, we expect it to get set to OKAY if a request is handled */ + result = XUD_RES_ERR; + + /* Stick bmRequest type back together for an easier parse... */ + bmRequestType = (sp.bmRequestType.Direction << 7) | + (sp.bmRequestType.Type << 5) | + (sp.bmRequestType.Recipient); + + if ((bmRequestType == USB_BMREQ_H2D_STANDARD_DEV) && + (sp.bRequest == USB_SET_ADDRESS)) + { + // Host has set device address, value contained in sp.wValue + } + + switch(bmRequestType) + { + /* Direction: Device-to-host + * Type: Standard + * Recipient: Interface + */ + case USB_BMREQ_D2H_STANDARD_INT: + + if(sp.bRequest == USB_GET_DESCRIPTOR) + { + /* HID Interface is Interface 0 */ + if(sp.wIndex == 0) + { + /* Look at Descriptor Type (high-byte of wValue) */ + unsigned short descriptorType = sp.wValue & 0xff00; + + switch(descriptorType) + { + case HID_HID: + result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, sizeof(hidDescriptor), sp.wLength); + break; + + case HID_REPORT: + result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, sizeof(hidReportDescriptor), sp.wLength); + break; + } + } + } + break; + + /* Direction: Device-to-host and Host-to-device + * Type: Class + * Recipient: Interface + */ + case USB_BMREQ_H2D_CLASS_INT: + case USB_BMREQ_D2H_CLASS_INT: + + /* Inspect for HID interface num */ + if(sp.wIndex == 0) + { + /* Returns XUD_RES_OKAY if handled, + * XUD_RES_ERR if not handled, + * XUD_RES_RST for bus reset */ + result = HidInterfaceClassRequests(ep0_out, ep0_in, sp); + } + break; + } + } + + /* If we haven't handled the request about then do standard enumeration requests */ + if(result == XUD_RES_ERR ) + { + /* Returns XUD_RES_OKAY if handled okay, + * XUD_RES_ERR if request was not handled (STALLed), + * XUD_RES_RST for USB Reset */ + result = USB_StandardRequests(ep0_out, ep0_in, devDesc, + sizeof(devDesc), cfgDesc, sizeof(cfgDesc), + NULL, 0, NULL, 0, stringDescriptors, sizeof(stringDescriptors)/sizeof(stringDescriptors[0]), + &sp, usbBusSpeed); + } + + /* USB bus reset detected, reset EP and get new bus speed */ + if(result == XUD_RES_RST) + { + usbBusSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); + } + } +} + +DECLARE_JOB(hid_mouse, (chanend_t)); +/* + * This function responds to the HID requests + * - It draws a square using the mouse moving 40 pixels in each direction + * - The sequence repeats every 500 requests. + */ +void hid_mouse(chanend_t chan_ep_hid) +{ + unsigned int counter = 0; + enum {RIGHT, DOWN, LEFT, UP} state = RIGHT; + + printf("hid_mouse: %x\n", chan_ep_hid); + XUD_ep ep_hid = XUD_InitEp(chan_ep_hid); + + for(;;) + { + /* Move the pointer around in a square (relative) */ + if(counter++ >= 500) + { + int x; + int y; + + switch(state) { + case RIGHT: + x = 40; + y = 0; + state = DOWN; + break; + + case DOWN: + x = 0; + y = 40; + state = LEFT; + break; + + case LEFT: + x = -40; + y = 0; + state = UP; + break; + + case UP: + default: + x = 0; + y = -40; + state = RIGHT; + break; + } + + /* Unsafe region so we can use shared memory. */ + /* global buffer 'g_reportBuffer' defined in hid_defs.h */ + g_reportBuffer[1] = x; + g_reportBuffer[2] = y; + + /* Send the buffer off to the host. Note this will return when complete */ + XUD_SetBuffer(ep_hid, (void*)g_reportBuffer, sizeof(g_reportBuffer)); + counter = 0; + } + } +} + +DECLARE_JOB(_XUD_Main, (chanend_t*, int, chanend_t*, int, chanend_t, XUD_EpType*, XUD_EpType*, XUD_BusSpeed_t, XUD_PwrConfig)); +void _XUD_Main(chanend_t *c_epOut, int noEpOut, chanend_t *c_epIn, int noEpIn, chanend_t c_sof, XUD_EpType *epTypeTableOut, XUD_EpType *epTypeTableIn, XUD_BusSpeed_t desiredSpeed, XUD_PwrConfig pwrConfig) +{ + for(int i = 0; i < EP_COUNT_OUT; ++i) { + printf("out[%d]: %x\n", i, c_epOut[i]); + } + for(int i = 0; i < EP_COUNT_IN; ++i) { + printf("in[%d]: %x\n", i, c_epIn[i]); + } + XUD_Main(c_epOut, noEpOut, c_epIn, noEpIn, c_sof, + epTypeTableOut, epTypeTableIn, desiredSpeed, pwrConfig); +} + +int main() +{ + channel_t channel_ep_out[EP_COUNT_OUT]; + channel_t channel_ep_in[EP_COUNT_IN]; + + for(int i = 0; i < sizeof(channel_ep_out) / sizeof(*channel_ep_out); ++i) { + channel_ep_out[i] = chan_alloc(); + } + for(int i = 0; i < sizeof(channel_ep_in) / sizeof(*channel_ep_in); ++i) { + channel_ep_in[i] = chan_alloc(); + } + + chanend_t c_ep_out[EP_COUNT_OUT]; + chanend_t c_ep_in[EP_COUNT_IN]; + + for(int i = 0; i < EP_COUNT_OUT; ++i) { + c_ep_out[i] = channel_ep_out[i].end_a; + } + for(int i = 0; i < EP_COUNT_IN; ++i) { + c_ep_in[i] = channel_ep_in[i].end_a; + } + + PAR_JOBS( + PJOB(_XUD_Main, (c_ep_out, EP_COUNT_OUT, c_ep_in, EP_COUNT_IN, 0, epTypeTableOut, epTypeTableIn, XUD_SPEED_HS, XUD_PWR_BUS)), + PJOB(Endpoint0, (channel_ep_out[0].end_b, channel_ep_in[0].end_b)), + PJOB(hid_mouse, (channel_ep_in[1].end_b)) + ); + + return 0; +} \ No newline at end of file diff --git a/examples/AN00135_test_and_measurement_class/src/scpi_parser/LICENSE b/examples/AN00135_test_and_measurement_class/src/scpi_parser/LICENSE index 3282fb36..04303d7f 100644 --- a/examples/AN00135_test_and_measurement_class/src/scpi_parser/LICENSE +++ b/examples/AN00135_test_and_measurement_class/src/scpi_parser/LICENSE @@ -23,10 +23,3 @@ 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. - -// Copyright (c) 2014, XMOS Ltd, All rights reserved -// This software is freely distributable under a derivative of the -// University of Illinois/NCSA Open Source License posted in -// LICENSE.txt and at - - diff --git a/lib_xud/LICENSE.rst b/lib_xud/LICENSE.rst deleted file mode 100644 index ca48f20f..00000000 --- a/lib_xud/LICENSE.rst +++ /dev/null @@ -1,84 +0,0 @@ -******************************* -XMOS PUBLIC LICENCE: Version 1 -******************************* - -Subject to the conditions and limitations below, permission is hereby granted by XMOS LIMITED (“XMOS”), free of charge, to any person or entity obtaining a copy of the XMOS Software. - -**1. Definitions** - -**“Applicable Patent Rights”** means: (a) where XMOS is the grantor of the rights, (i) claims of patents that are now or in future owned by or assigned to XMOS and (ii) that cover subject matter contained in the Software, but only to the extent it is necessary to use, reproduce or distribute the Software without infringement; and (b) where you are the grantor of the rights, (i) claims of patents that are now or in future owned by or assigned to you and (ii) that cover the subject matter contained in your Derivatives, taken alone or in combination with the Software. - -**“Compiled Code”** means any compiled, binary, machine readable or executable version of the Source Code. - -**“Contributor”** means any person or entity that creates or contributes to the creation of Derivatives. - -**“Derivatives”** means any addition to, deletion from and/or change to the substance, structure of the Software, any previous Derivatives, the combination of the Derivatives and the Software and/or any respective portions thereof. - -**“Source Code”** means the human readable code that is suitable for making modifications but excluding any Compiled Code. - -**“Software”** means the software and associated documentation files which XMOS makes available and which contain a notice identifying the software as original XMOS software and referring to the software being subject to the terms of this XMOS Public Licence. - -This Licence refers to XMOS Software and does not relate to any XMOS hardware or devices which are protected by intellectual property rights (including patent and trade marks) which may be sold to you under a separate agreement. - - -**2. Licence** - -**Permitted Uses, Conditions and Restrictions.** Subject to the conditions below, XMOS grants you a worldwide, royalty free, non-exclusive licence, to the extent of any Patent Rights to do the following: - -2.1 **Unmodified Software.** You may use, copy, display, publish, distribute and make available unmodified copies of the Software: - -2.1.1 for personal or academic, non-commercial purposes; or - -2.1.2 for commercial purposes provided the Software is at all times used on a device designed, licensed or developed by XMOS and, provided that in each instance (2.1.1 and 2.1.2): - -(a) you must retain and reproduce in all copies of the Software the copyright and proprietary notices and disclaimers of XMOS as they appear in the Software, and keep intact all notices and disclaimers in the Software files that refer to this Licence; and - -(b) you must include a copy of this Licence with every copy of the Software and documentation you publish, distribute and make available and you may not offer or impose any terms on such Software that alter or restrict this Licence or the intent of such Licence, except as permitted below (Additional Terms). - -The licence above does not include any Compiled Code which XMOS may make available under a separate support and licence agreement. - -2.2 **Derivatives.** You may create and modify Derivatives and use, copy, display, publish, distribute and make available Derivatives: - -2.2.1 for personal or academic, non-commercial purposes; or - -2.2.2 for commercial purposes, provided the Derivatives are at all times used on a device designed, licensed or developed by XMOS and, provided that in each instance (2.2.1 and 2.2.2): - -(a) you must comply with the terms of clause 2.1 with respect to the Derivatives; - -(b) you must copy (to the extent it doesn’t already exist) the notice below in each file of the Derivatives, and ensure all the modified files carry prominent notices stating that you have changed the files and the date of any change; and - -(c) if you sublicence, distribute or otherwise make the Software and/or the Derivatives available for commercial purposes, you must provide that the Software and Derivatives are at all times used on a device designed, licensed or developed by XMOS. - -Without limitation to these terms and clause 3 below, the Source Code and Compiled Code to your Derivatives may at your discretion (but without obligation) be released, copied, displayed, published, distributed and made available; and if you elect to do so, it must be under the terms of this Licence including the terms of the licence at clauses 2.2.1, 2.2.2 and clause 3 below. - -2.3 **Distribution of Executable Versions.** If you distribute or make available Derivatives, you must include a prominent notice in the code itself as well as in all related documentation, stating that the Source Code of the Software from which the Derivatives are based is available under the terms of this Licence, with information on how and where to obtain such Source Code. - -**3. Your Grant of Rights.** In consideration and as a condition to this Licence, you grant to any person or entity receiving or distributing any Derivatives, a non-exclusive, royalty free, perpetual, irrevocable license under your Applicable Patent Rights and all other intellectual property rights owned or controlled by you, to use, copy, display, publish, distribute and make available your Derivatives of the same scope and extent as XMOS’s licence under clause 2.2 above. - -**4. Combined Products.** You may create a combined product by combining Software, Derivatives and other code not covered by this Licence as a single application or product. In such instance, you must comply with the requirements of this Licence for any portion of the Software and/or Derivatives. - -**5. Additional Terms.** You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations and/or other rights consistent with the term of this Licence (“Additional Terms”) to any legitimate recipients of the Software and/or Derivatives. The terms on which you provide such Additional Terms are on your sole responsibility and you shall indemnify, defend and hold XMOS harmless against any claims asserted against XMOS. - -**6. New Versions.** XMOS may publish revised and/or new versions of this Licence from time to time to accommodate changes to the Licence terms, new versions, updates and bug fixes of the Software. Each version will be given a distinguishing version number. Once Software has been published under a particular version of this Licence, you may continue to use it under the terms of that version. You may also choose to use the latest version of the Software under any subsequent version published by XMOS. Only XMOS shall have the right to modify these terms. - -**7. IPR and Ownership** -Any rights, including all intellectual property rights and all trademarks not expressly granted herein are reserved in full by the authors or copyright holders. Any requests for additional permissions by XMOS including any rights to use XMOS trademarks, should be made (without obligation) to XMOS at **support@xmos.com** - -Nothing herein shall limit any rights that XMOS is otherwise entitled to under the doctrines of patent exhaustion, implied license, or legal estoppel. Neither the name of the authors, the copyright holders or any contributors may be used to endorse or promote any Derivatives from this Software without specific written permission. Any attempt to deal with the Software which does not comply with this Licence shall be void and shall automatically terminate any rights granted under this licence (including any licence of any intellectual property rights granted herein). -Subject to the licences granted under this Licence any Contributor retains all rights, title and interest in and to any Derivatives made by Contributor subject to the underlying rights of XMOS in the Software. XMOS shall retain all rights, title and interest in the Software and any Derivatives made by XMOS (“XMOS Derivatives”). XMOS Derivatives will not automatically be subject to this Licence and XMOS shall be entitled to licence such rights on any terms (without obligation) as it sees fit. - -**8. Termination** - -8.1 This Licence will automatically terminate immediately, without notice to you, if: - -(a) you fail to comply with the terms of this Licence; and/or - -(b) you directly or indirectly commence any action for patent or intellectual property right infringement against XMOS, or any parent, group, affiliate or subsidiary of XMOS; provided XMOS did not first commence an action or patent infringement against you in that instance; and/or - -(c) the terms of this Licence are held by any court of competent jurisdiction to be unenforceable in whole or in part. - -**9. Critical Applications.** Unless XMOS has agreed in writing with you an agreement specifically governing use of the Goods in military, aerospace, automotive or medically related functions (collectively and individually hereinafter referred to as "Special Use"), any permitted use of the Software excludes Special Use. Notwithstanding any agreement between XMOS and you for Special Use, Special Use shall be at your own risk, and you shall fully indemnify XMOS against any damages, losses, costs and claims (direct and indirect) arising out of any Special Use. - -**10. NO WARRANTY OR SUPPORT.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL XMOS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, WARRANTY, CIVIL TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE INCLUDING GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES EVEN IF SUCH PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND NOT WITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE. IN SOME JURISDICTIONS PARTIES ARE UNABLE TO LIMIT LIABILTY IN THIS WAY, IF THIS APPLIES TO YOUR JURISDICTION THIS LIABILITY CLAUSE ABOVE MAY NOT APPLY. NOTWITHSTANDING THE ABOVE, IN NO EVENT SHALL XMOS’s TOTAL LIABILITY TO YOU FOR ALL DAMAGES, LOSS OR OTHERWISE EXCEED $50. - -**11. Governing Law and Jurisdiction.** This Licence constitutes the entire agreement between the parties with respect to the subject matter hereof. The Licence shall be governed by the laws of England and the conflict of laws and UN Convention on Contracts for the International Sale of Goods, shall not apply. diff --git a/lib_xud/api/xud.h b/lib_xud/api/xud.h index aac91c30..1e50e0ad 100644 --- a/lib_xud/api/xud.h +++ b/lib_xud/api/xud.h @@ -271,7 +271,7 @@ XUD_Result_t XUD_SetDevAddr(/*tileref usbtile*/ unsigned addr); * \param one IN or OUT endpoint identifier to perform the reset on. * \param two Optional second IN or OUT endpoint structure to perform a reset on. * \return Either ``XUD_SPEED_HS`` - the host has accepted that this device can execute - * at high speed, ``XUD_SPEED_FS`` - the device is runnig at full speed, + * at high speed, ``XUD_SPEED_FS`` - the device is running at full speed, * or ``XUD_SPEED_KILL`` to indicate that the USB stack has been shut down * by another part of the user code (using XUD_Kill). If the last value is * returned, the endpoint code should call XUD_CloseEndpoint and then @@ -552,6 +552,27 @@ void XUD_SetData_Select(chanend c, XUD_ep ep, REFERENCE_PARAM(XUD_Result_t, resu #define XUD_OSC_MHZ (24) #endif -#endif //__ASSEMBLER__ + +/* TODO pack this to save mem + * TODO size of this hardcoded in ResetRpStateByAddr_ + */ +typedef struct XUD_ep_info +{ + unsigned int array_ptr; // 0 + unsigned int xud_chanend; // 1 + unsigned int client_chanend; // 2 + unsigned int buffer; // 3 Pointer to buffer + unsigned int pid; // 4 Expected out PID + unsigned int epType; // 5 Data + unsigned int actualPid; // 6 Actual OUT PID received for OUT, Length (words) for IN. + unsigned int tailLength; // 7 "tail" length for IN (bytes) + unsigned int epAddress; // 8 EP address assigned by XUD (Used for marking stall etc) + unsigned int resetting; // 9 Flag to indicate to EP a bus-reset occured. + unsigned int halted; // 10 NAK or STALL + unsigned int saved_array_ptr; // 11 +} XUD_ep_info; + + +#endif //__ASSEMBLER__ #endif // _XUD_H_ diff --git a/lib_xud/doc/rst/version.rst b/lib_xud/doc/rst/version.rst index ecc91957..77150e32 100644 --- a/lib_xud/doc/rst/version.rst +++ b/lib_xud/doc/rst/version.rst @@ -1 +1 @@ -.. version:: 2.0.0 +.. version:: 2.1.0 diff --git a/lib_xud/module_build_info b/lib_xud/module_build_info index e1befd75..7d4de900 100644 --- a/lib_xud/module_build_info +++ b/lib_xud/module_build_info @@ -1,13 +1,14 @@ -VERSION = 2.0.2 +VERSION = 2.1.0 MODULE_XCC_FLAGS = $(XCC_FLAGS) \ -O3 \ -DREF_CLK_FREQ=100 \ -fasm-linenum \ -fcomment-asm \ - -DXUD_FULL_PIDTABLE=1 + -DXUD_FULL_PIDTABLE=1 \ + -g -XCC_FLAGS_XUD_IoLoop.S = $(MODULE_XCC_FLAGS) -fschedule -g0 +XCC_FLAGS_XUD_IoLoop.S = $(MODULE_XCC_FLAGS) -fschedule XCC_FLAGS_endpoint0.xc = $(MODULE_XCC_FLAGS) -Os XCC_FLAGS_dfu.xc = $(MODULE_XCC_FLAGS) -Os @@ -44,6 +45,7 @@ SOURCE_DIRS = src/core \ EXCLUDE_FILES += XUD_CrcAddrCheck.S \ XUD_G_Crc.S \ XUD_PidJumpTable.S \ + XUD_PidJumpTable_RxData.S \ XUD_RxData.S \ XUD_Token_In_DI.S \ XUD_Token_Out_DI.S \ diff --git a/lib_xud/src/core/XUD_CrcAddrCheck.S b/lib_xud/src/core/XUD_CrcAddrCheck.S index 6baf4459..0f378c78 100644 --- a/lib_xud/src/core/XUD_CrcAddrCheck.S +++ b/lib_xud/src/core/XUD_CrcAddrCheck.S @@ -10,17 +10,18 @@ // r10: Extracted EP number #ifdef __XS3A__ - {in r10, res[RXD]; sub r1, r8, 5} // ldc r1 11 - {shr r10, r10, 16; mkmsk r11, r1} - {and r11, r10, r11; shr r4, r10, r1} // r4: Received CRC + {in r10, res[RXD]; sub r1, r8, 5} // ldc r1 11 + {shr r10, r10, 16; mkmsk r11, r1} + {and r11, r10, r11; ldw r8, sp[STACK_CRC5TABLE_ADDR]} - ldaw r8, dp[crc5Table_Addr] - ld8u r8, r8[r11] // Correct CRC + {shr r4, r10, r1 // r4: Received CRC + ld8u r8, r8[r11]} // r8: Expected CRC - xor r4, r4, r8 // R4 set to 0 in L code with in from valid tok port - {BRFF_ru6 r4, 5; shr r10, r11, 7} // Extract EP number + //xor r4, r4, r8 // R4 set to 0 in L code with in from valid tok port + {eq r4, r4, r8; shr r10, r11, 7} // Extract EP number + BRFT_ru6 r4, 5 - ldw r11, sp[STACK_RXA_PORT] // Wait for RXA to gow low (i.e. end of packet) + ldw r11, sp[STACK_RXA_PORT] // Wait for RXA to gow low (i.e. end of packet) in r10, res[r11] bt r10, waitforRXALow0 setc res[RXD], XS1_SETC_RUN_CLRBUF diff --git a/lib_xud/src/core/XUD_IoLoop.S b/lib_xud/src/core/XUD_IoLoop.S index b088c148..2317a9a0 100755 --- a/lib_xud/src/core/XUD_IoLoop.S +++ b/lib_xud/src/core/XUD_IoLoop.S @@ -52,7 +52,8 @@ suspend_t_wtwrsths: #define STACK_TXCRC_INIT (20) #define STACK_RXCRC_INIT (21) #define STACK_PIDJUMPTABLE (22) -#define STACK_HANDSHAKETABLEIN (23) +#define STACK_PIDJUMPTABLE_RXDATA (23) +#define STACK_CRC5TABLE_ADDR (24) // Params #define STACK_VTOK_PORT (STACK_EXTEND + 1) @@ -70,6 +71,7 @@ suspend_t_wtwrsths: .globl UsbTestModeHandler_asm.nstackwords .linkset UsbTestModeHandler_asm.nstackwords, 0 .globl UsbTestModeHandler_asm +.type UsbTestModeHandler_asm, @function .text .cc_top UsbTestModeHandler_asm.func, UsbTestModeHandler_asm .issue_mode single @@ -100,6 +102,7 @@ UsbTestModeHandler_asm: .globl ResetIntHandler.nstackwords .linkset ResetIntHandler.nstackwords, 0 .globl ResetIntHandler +.type ResetIntHandler, @function .text .cc_top ResetIntHandler.func, ResetIntHandler .issue_mode dual @@ -137,8 +140,9 @@ ResetIntHandler: .linkset XUD_LLD_IoLoop.maxthreads, 0 .globl XUD_LLD_IoLoop -.cc_top XUD_LLD_IoLoop.func, XUD_LLD_IoLoop +.type XUD_LLD_IoLoop, @function .text +.cc_top XUD_LLD_IoLoop.func, XUD_LLD_IoLoop .issue_mode dual // Note, included here so in same elimination blocks to avoid long jumps @@ -260,8 +264,13 @@ ConfigSofJump: #endif ConfigSofJump_Done: stw r10, sp[STACK_PIDJUMPTABLE] - ldaw r10, dp[handshakeTable_IN] // Load handshake table - stw r10, sp[STACK_HANDSHAKETABLEIN] + + ldaw r10, dp[PidJumpTable_RxData] + stw r10, sp[STACK_PIDJUMPTABLE_RXDATA] + + ldaw r10, dp[crc5Table_Addr] + stw r10, sp[STACK_CRC5TABLE_ADDR] + ConfigRxErrEventVector: setc res[r3], XS1_SETC_COND_EQ @@ -371,4 +380,5 @@ Return: // Tables of tables... #include "./included/XUD_PidJumpTable.S" +#include "./included/XUD_PidJumpTable_RxData.S" diff --git a/lib_xud/src/core/XUD_Main.xc b/lib_xud/src/core/XUD_Main.xc index 00cfffb3..2ce8b84c 100755 --- a/lib_xud/src/core/XUD_Main.xc +++ b/lib_xud/src/core/XUD_Main.xc @@ -62,22 +62,7 @@ on USB_TILE: clock rx_usb_clk = XS1_CLKBLK_5; XUD_chan epChans[USB_MAX_NUM_EP]; XUD_chan epChans0[USB_MAX_NUM_EP]; -/* TODO pack this to save mem - * TODO size of this hardcoded in ResetRpStateByAddr_ - */ -typedef struct XUD_ep_info -{ - unsigned int chan_array_ptr; // 0 - unsigned int ep_xud_chanend; // 1 - unsigned int ep_client_chanend; // 2 - unsigned int scratch; // 3 used for datalength in - unsigned int pid; // 4 Expected out PID - unsigned int epType; // 5 Data - unsigned int actualPid; // 6 Actual OUT PID received for OUT, Length (words) for IN. - unsigned int tailLength; // 7 "tail" length for IN (bytes) - unsigned int epAddress; // 8 EP address assigned by XUD (Used for marking stall etc) - unsigned int resetting; // 9 Flag to indicate to EP a bus-reset occured. -} XUD_ep_info; + XUD_ep_info ep_info[USB_MAX_NUM_EP]; @@ -93,8 +78,8 @@ extern unsigned XUD_LLD_IoLoop( XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], XUD_chan epChans[], int epCount, chanend? c_sof) ; -unsigned handshakeTable_IN[USB_MAX_NUM_EP_IN] = {0}; // 0 or STALL -unsigned handshakeTable_OUT[USB_MAX_NUM_EP_OUT]; // NAK or STALL +unsigned ep_addr[USB_MAX_NUM_EP]; + unsigned sentReset=0; unsigned crcmask = 0b11111111111; @@ -181,21 +166,18 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epChans[], chanend ?c #endif #ifdef XUD_SIM_XSIM - #if (XUD_CORE_CLOCK > 500) - #define RX_RISE_DELAY 2 - #define RX_FALL_DELAY 5 - #define TX_RISE_DELAY 2 - #define TX_FALL_DELAY 3 - #elif (XUD_CORE_CLOCK > 400) - #define RX_RISE_DELAY 5 - #define RX_FALL_DELAY 5 - #define TX_RISE_DELAY 2 - #define TX_FALL_DELAY 3 - #else /* 400 */ - #define RX_RISE_DELAY 3 - #define RX_FALL_DELAY 5 - #define TX_RISE_DELAY 3 - #define TX_FALL_DELAY 3 + #if (XUD_CORE_CLOCK >= 700) + #define RX_RISE_DELAY 0 + #define RX_FALL_DELAY 0 + #define TX_RISE_DELAY 0 + #define TX_FALL_DELAY 7 + #elif (XUD_CORE_CLOCK >= 600) + #define RX_RISE_DELAY 0 + #define RX_FALL_DELAY 0 + #define TX_RISE_DELAY 0 + #define TX_FALL_DELAY 5 + #else + #error XUD_CORE_CLOCK must be >= 600 #endif #else #if (XUD_CORE_CLOCK >= 600) @@ -203,7 +185,6 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epChans[], chanend ?c #define RX_FALL_DELAY 1 #define TX_RISE_DELAY 1 #define TX_FALL_DELAY 1 - #elif (XUD_CORE_CLOCK >= 500) #define RX_RISE_DELAY 1 #define RX_FALL_DELAY 0 @@ -230,20 +211,18 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epChans[], chanend ?c set_port_inv(p_usb_clk); set_port_sample_delay(p_usb_clk); -#if !defined(XUD_SIM_XSIM) - //This delay controls the capture of rdy + // This delay controls the capture of rdy set_clock_rise_delay(tx_usb_clk, TX_RISE_DELAY); - //this delay controls the launch of data. + // This delay controls the launch of data. set_clock_fall_delay(tx_usb_clk, TX_FALL_DELAY); - //this delay th capture of the rdyIn and data. + // This delay the capture of the rdyIn and data. set_clock_rise_delay(rx_usb_clk, RX_RISE_DELAY); set_clock_fall_delay(rx_usb_clk, RX_FALL_DELAY); -#endif #ifdef __XS3A__ - set_pad_delay(flag1_port, 3); + set_pad_delay(flag1_port, 2); #else set_pad_delay(flag1_port, 2); #endif @@ -312,7 +291,7 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epChans[], chanend ?c /* Sample line state and check for reset (or suspend) */ XUD_LineState_t ls = XUD_HAL_GetLineState(); if(ls == XUD_LINESTATE_SE0) - reset == 1; + reset = 1; else reset = 0; } @@ -337,7 +316,6 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epChans[], chanend ?c /* Test if coming back from reset or suspend */ if(reset == 1) { - if(!sentReset) { SendResetToEps(epChans0, epChans, epTypeTableOut, epTypeTableIn, noEpOut, noEpIn, USB_RESET_TOKEN); @@ -484,16 +462,16 @@ int XUD_Main(chanend c_ep_out[], int noEpOut, for(int i = 0; i < USB_MAX_NUM_EP_OUT; i++) { - handshakeTable_OUT[i] = USB_PIDn_NAK; ep_info[i].epAddress = i; ep_info[i].resetting = 0; + ep_info[i].halted = USB_PIDn_NAK; } for(int i = 0; i < USB_MAX_NUM_EP_IN; i++) { - handshakeTable_IN[i] = 0; ep_info[USB_MAX_NUM_EP_OUT+i].epAddress = (i | 0x80); ep_info[USB_MAX_NUM_EP_OUT+i].resetting = 0; + ep_info[USB_MAX_NUM_EP_OUT+i].halted = 0; } /* Populate arrays of channels and status flag tabes */ @@ -505,16 +483,18 @@ int XUD_Main(chanend c_ep_out[], int noEpOut, epChans0[i] = XUD_Sup_GetResourceId(c_ep_out[i]); asm("ldaw %0, %1[%2]":"=r"(x):"r"(epChans),"r"(i)); - ep_info[i].chan_array_ptr = x; + ep_info[i].array_ptr = x; + ep_info[i].saved_array_ptr = 0; asm("mov %0, %1":"=r"(x):"r"(c_ep_out[i])); - ep_info[i].ep_xud_chanend = x; + ep_info[i].xud_chanend = x; asm("getd %0, res[%1]":"=r"(x):"r"(c_ep_out[i])); - ep_info[i].ep_client_chanend = x; + ep_info[i].client_chanend = x; asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"(i*sizeof(XUD_ep_info)/sizeof(unsigned))); outuint(c_ep_out[i], x); + ep_addr[i] = x; epStatFlagTableOut[i] = epTypeTableOut[i] & XUD_STATUS_ENABLE; epTypeTableOut[i] = epTypeTableOut[i] & 0x7FFFFFFF; @@ -537,17 +517,19 @@ int XUD_Main(chanend c_ep_out[], int noEpOut, epChans0[i+USB_MAX_NUM_EP_OUT] = XUD_Sup_GetResourceId(c_ep_in[i]); asm("ldaw %0, %1[%2]":"=r"(x):"r"(epChans),"r"(USB_MAX_NUM_EP_OUT+i)); - ep_info[USB_MAX_NUM_EP_OUT+i].chan_array_ptr = x; + ep_info[USB_MAX_NUM_EP_OUT+i].array_ptr = x; + ep_info[USB_MAX_NUM_EP_OUT+i].saved_array_ptr = 0; asm("mov %0, %1":"=r"(x):"r"(c_ep_in[i])); - ep_info[USB_MAX_NUM_EP_OUT+i].ep_xud_chanend = x; + ep_info[USB_MAX_NUM_EP_OUT+i].xud_chanend = x; asm("getd %0, res[%1]":"=r"(x):"r"(c_ep_in[i])); - ep_info[USB_MAX_NUM_EP_OUT+i].ep_client_chanend = x; + ep_info[USB_MAX_NUM_EP_OUT+i].client_chanend = x; asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"((USB_MAX_NUM_EP_OUT+i)*sizeof(XUD_ep_info)/sizeof(unsigned))); outuint(c_ep_in[i], x); + ep_addr[USB_MAX_NUM_EP_OUT+i] = x; ep_info[USB_MAX_NUM_EP_OUT+i].pid = USB_PIDn_DATA0; diff --git a/lib_xud/src/core/XUD_TestMode.S b/lib_xud/src/core/XUD_TestMode.S index f01b65fa..7dff0d9c 100644 --- a/lib_xud/src/core/XUD_TestMode.S +++ b/lib_xud/src/core/XUD_TestMode.S @@ -3,6 +3,7 @@ #include #include "XUD_USB_Defines.h" +#include "XUD_AlignmentDefines.h" .issue_mode dual @@ -14,6 +15,7 @@ // NAK every IN token if the CRC is correct. +.align FUNCTION_ALIGNMENT XUD_UsbTestSE0: DUALENTSP_lu6 0 // Note, don't really need DI here.. // TODO ideally don't load these from dp.. diff --git a/lib_xud/src/core/included/XUD_PidJumpTable_RxData.S b/lib_xud/src/core/included/XUD_PidJumpTable_RxData.S new file mode 100755 index 00000000..bad18a86 --- /dev/null +++ b/lib_xud/src/core/included/XUD_PidJumpTable_RxData.S @@ -0,0 +1,556 @@ +// Copyright 2011-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#if defined (__XS2A__) + +// PID jump table +.section .dp.data, "adw", @progbits + +.globl PidJumpTable_RxData +.type PidJumpTable_RxData, @object + +.cc_top PidJumpTable_RxData.func, PidJumpTable_RxData +.align 4 +PidJumpTable_RxData: +.word Pid_Reserved // 0 0x00 +.word Pid_Out // 1 0x01 +.word Pid_Ack // 2 0x02 +.word Pid_Data0_RxData // 3 0x03 +.word Pid_Ping // 4 0x04 +.word Pid_Sof // 5 0x05 +.word Pid_Nyet // 6 0x06 +.word Pid_Data2_RxData // 7 0x07 +.word Pid_Split // 8 0x08 +.word Pid_In // 9 0x09 +.word Pid_Nak // 10 0x0a +.word Pid_Data1_RxData // 11 0x0b +.word Pid_Pre // 12 0x0c +.word Pid_Setup // 13 0x0d +.word Pid_Stall // 14 0x0e +.word Pid_Datam_RxData // 15 0x0f +#if defined(XUD_DEBUG_VERSION) || defined(XUD_FULL_PIDTABLE) +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData +.word Pid_Bad_RxData + +#endif + +.size PidJumpTable_RxData, .-PidJumpTable_RxData +.cc_bottom PidJumpTable_RxData.func + +#endif + +#if defined(__XS3A__) +// Generated using genpidtable.c +.section .dp.data, "adw", @progbits +.globl PidJumpTable_RxData +.type PidJumpTable_RxData, @function + +.cc_top PidJumpTable_RxData.func, PidJumpTable_RxData +.align 4 + +PidJumpTable_RxData: +.word Pid_Bad_RxData // 0 0x00 +.word Pid_Bad_RxData // 1 0x01 +.word Pid_Bad_RxData // 2 0x02 +.word Pid_Bad_RxData // 3 0x03 +.word Pid_Bad_RxData // 4 0x04 +.word Pid_Bad_RxData // 5 0x05 +.word Pid_Bad_RxData // 6 0x06 +.word Pid_Bad_RxData // 7 0x07 +.word Pid_Bad_RxData // 8 0x08 +.word Pid_Bad_RxData // 9 0x09 +.word Pid_Bad_RxData // 10 0x0a +.word Pid_Bad_RxData // 11 0x0b +.word Pid_Bad_RxData // 12 0x0c +.word Pid_Bad_RxData // 13 0x0d +.word Pid_Bad_RxData // 14 0x0e +.word Pid_MData // 15 0x0f +.word Pid_Bad_RxData // 16 0x10 +.word Pid_Bad_RxData // 17 0x11 +.word Pid_Bad_RxData // 18 0x12 +.word Pid_Bad_RxData // 19 0x13 +.word Pid_Bad_RxData // 20 0x14 +.word Pid_Bad_RxData // 21 0x15 +.word Pid_Bad_RxData // 22 0x16 +.word Pid_Bad_RxData // 23 0x17 +.word Pid_Bad_RxData // 24 0x1 +.word Pid_Bad_RxData // 25 0x19 +.word Pid_Bad_RxData // 26 0x1a +.word Pid_Bad_RxData // 27 0x1b +.word Pid_Bad_RxData // 28 0x1c +.word Pid_Bad_RxData // 29 0x1d +.word Pid_Bad_RxData // 30 0x1e +.word Pid_Bad_RxData // 31 0x1f +.word Pid_Bad_RxData // 32 0x20 +.word Pid_Bad_RxData // 33 0x21 +.word Pid_Bad_RxData // 34 0x22 +.word Pid_Bad_RxData // 35 0x23 +.word Pid_Bad_RxData // 36 0x24 +.word Pid_Bad_RxData // 37 0x25 +.word Pid_Bad_RxData // 38 0x26 +.word Pid_Bad_RxData // 39 0x27 +.word Pid_Bad_RxData // 40 0x28 +.word Pid_Bad_RxData // 41 0x29 +.word Pid_Bad_RxData // 42 0x2a +.word Pid_Bad_RxData // 43 0x2b +.word Pid_Bad_RxData // 44 0x2c +.word Pid_Bad_RxData // 45 0x2d +.word Pid_Bad_RxData // 46 0x2e +.word Pid_Bad_RxData // 47 0x2f +.word Pid_Bad_RxData // 48 0x30 +.word Pid_Bad_RxData // 49 0x31 +.word Pid_Bad_RxData // 50 0x32 +.word Pid_Bad_RxData // 51 0x33 +.word Pid_Bad_RxData // 52 0x34 +.word Pid_Bad_RxData // 53 0x35 +.word Pid_Bad_RxData // 54 0x36 +.word Pid_Bad_RxData // 55 0x37 +.word Pid_Bad_RxData // 56 0x38 +.word Pid_Bad_RxData // 57 0x39 +.word Pid_Bad_RxData // 58 0x3a +.word Pid_Bad_RxData // 59 0x3b +.word Pid_Bad_RxData // 60 0x3c +.word Pid_Bad_RxData // 61 0x3d +.word Pid_Bad_RxData // 62 0x3e +.word Pid_Bad_RxData // 63 0x3f +.word Pid_Bad_RxData // 64 0x40 +.word Pid_Bad_RxData // 65 0x41 +.word Pid_Bad_RxData // 66 0x42 +.word Pid_Bad_RxData // 67 0x43 +.word Pid_Bad_RxData // 68 0x44 +.word Pid_Bad_RxData // 69 0x45 +.word Pid_Bad_RxData // 70 0x46 +.word Pid_Bad_RxData // 71 0x47 +.word Pid_Bad_RxData // 72 0x48 +.word Pid_Bad_RxData // 73 0x49 +.word Pid_Bad_RxData // 74 0x4a +.word Pid_Data1_RxData // 75 0x4b +.word Pid_Bad_RxData // 76 0x4c +.word Pid_Bad_RxData // 77 0x4d +.word Pid_Bad_RxData // 78 0x4e +.word Pid_Bad_RxData // 79 0x4f +.word Pid_Bad_RxData // 80 0x50 +.word Pid_Bad_RxData // 81 0x51 +.word Pid_Bad_RxData // 82 0x52 +.word Pid_Bad_RxData // 83 0x53 +.word Pid_Bad_RxData // 84 0x54 +.word Pid_Bad_RxData // 85 0x55 +.word Pid_Bad_RxData // 86 0x56 +.word Pid_Bad_RxData // 87 0x57 +.word Pid_Bad_RxData // 88 0x58 +.word Pid_Bad_RxData // 89 0x59 +.word Pid_Bad_RxData // 90 0x5a +.word Pid_Bad_RxData // 91 0x5b +.word Pid_Bad_RxData // 92 0x5c +.word Pid_Bad_RxData // 93 0x5d +.word Pid_Bad_RxData // 94 0x5e +.word Pid_Bad_RxData // 95 0x5f +.word Pid_Bad_RxData // 96 0x60 +.word Pid_Bad_RxData // 97 0x61 +.word Pid_Bad_RxData // 98 0x62 +.word Pid_Bad_RxData // 99 0x63 +.word Pid_Bad_RxData // 100 0x64 +.word Pid_Bad_RxData // 101 0x65 +.word Pid_Bad_RxData // 102 0x66 +.word Pid_Bad_RxData // 103 0x67 +.word Pid_Bad_RxData // 104 0x68 +.word Pid_Bad_RxData // 105 0x69 +.word Pid_Bad_RxData // 106 0x6a +.word Pid_Bad_RxData // 107 0x6b +.word Pid_Bad_RxData // 108 0x6c +.word Pid_Bad_RxData // 109 0x6d +.word Pid_Bad_RxData // 110 0x6e +.word Pid_Bad_RxData // 111 0x6f +.word Pid_Bad_RxData // 112 0x70 +.word Pid_Bad_RxData // 113 0x71 +.word Pid_Bad_RxData // 114 0x72 +.word Pid_Bad_RxData // 115 0x73 +.word Pid_Bad_RxData // 116 0x74 +.word Pid_Bad_RxData // 117 0x75 +.word Pid_Bad_RxData // 118 0x76 +.word Pid_Bad_RxData // 119 0x77 +.word Pid_Bad_RxData // 120 0x78 +.word Pid_Bad_RxData // 121 0x79 +.word Pid_Bad_RxData // 122 0x7a +.word Pid_Bad_RxData // 123 0x7b +.word Pid_Bad_RxData // 124 0x7c +.word Pid_Bad_RxData // 125 0x7d +.word Pid_Bad_RxData // 126 0x7e +.word Pid_Bad_RxData // 127 0x7f +.word Pid_Bad_RxData // 128 0x80 +.word Pid_Bad_RxData // 129 0x81 +.word Pid_Bad_RxData // 130 0x82 +.word Pid_Bad_RxData // 131 0x83 +.word Pid_Bad_RxData // 132 0x84 +.word Pid_Bad_RxData // 133 0x85 +.word Pid_Bad_RxData // 134 0x86 +.word Pid_Data2 // 135 0x87 +.word Pid_Bad_RxData // 136 0x88 +.word Pid_Bad_RxData // 137 0x89 +.word Pid_Bad_RxData // 138 0x8a +.word Pid_Bad_RxData // 139 0x8b +.word Pid_Bad_RxData // 140 0x8c +.word Pid_Bad_RxData // 141 0x8d +.word Pid_Bad_RxData // 142 0x8e +.word Pid_Bad_RxData // 143 0x8f +.word Pid_Bad_RxData // 144 0x90 +.word Pid_Bad_RxData // 145 0x91 +.word Pid_Bad_RxData // 146 0x92 +.word Pid_Bad_RxData // 147 0x93 +.word Pid_Bad_RxData // 148 0x94 +.word Pid_Bad_RxData // 149 0x95 +.word Pid_Bad_RxData // 150 0x96 +.word Pid_Bad_RxData // 151 0x97 +.word Pid_Bad_RxData // 152 0x98 +.word Pid_Bad_RxData // 153 0x99 +.word Pid_Bad_RxData // 154 0x9a +.word Pid_Bad_RxData // 155 0x9b +.word Pid_Bad_RxData // 156 0x9c +.word Pid_Bad_RxData // 157 0x9d +.word Pid_Bad_RxData // 158 0x9e +.word Pid_Bad_RxData // 159 0x9f +.word Pid_Bad_RxData // 160 0xa0 +.word Pid_Bad_RxData // 161 0xa1 +.word Pid_Bad_RxData // 162 0xa2 +.word Pid_Bad_RxData // 163 0xa3 +.word Pid_Bad_RxData // 164 0xa4 +.word Pid_Bad_RxData // 165 0xa5 +.word Pid_Bad_RxData // 166 0xa6 +.word Pid_Bad_RxData // 167 0xa7 +.word Pid_Bad_RxData // 168 0xa8 +.word Pid_Bad_RxData // 169 0xa9 +.word Pid_Bad_RxData // 170 0xaa +.word Pid_Bad_RxData // 171 0xab +.word Pid_Bad_RxData // 172 0xac +.word Pid_Bad_RxData // 173 0xad +.word Pid_Bad_RxData // 174 0xae +.word Pid_Bad_RxData // 175 0xaf +.word Pid_Bad_RxData // 176 0xb0 +.word Pid_Bad_RxData // 177 0xb1 +.word Pid_Bad_RxData // 178 0xb2 +.word Pid_Bad_RxData // 179 0xb3 +.word Pid_Bad_RxData // 180 0xb4 +.word Pid_Bad_RxData // 181 0xb5 +.word Pid_Bad_RxData // 182 0xb6 +.word Pid_Bad_RxData // 183 0xb7 +.word Pid_Bad_RxData // 184 0xb8 +.word Pid_Bad_RxData // 185 0xb9 +.word Pid_Bad_RxData // 186 0xba +.word Pid_Bad_RxData // 187 0xbb +.word Pid_Bad_RxData // 188 0xbc +.word Pid_Bad_RxData // 189 0xbd +.word Pid_Bad_RxData // 190 0xbe +.word Pid_Bad_RxData // 191 0xbf +.word Pid_Bad_RxData // 192 0xc0 +.word Pid_Bad_RxData // 193 0xc1 +.word Pid_Bad_RxData // 194 0xc2 +.word Pid_Data0_RxData // 195 0xc3 +.word Pid_Bad_RxData // 196 0xc4 +.word Pid_Bad_RxData // 197 0xc5 +.word Pid_Bad_RxData // 198 0xc6 +.word Pid_Bad_RxData // 199 0xc7 +.word Pid_Bad_RxData // 200 0xc8 +.word Pid_Bad_RxData // 201 0xc9 +.word Pid_Bad_RxData // 202 0xca +.word Pid_Bad_RxData // 203 0xcb +.word Pid_Bad_RxData // 204 0xcc +.word Pid_Bad_RxData // 205 0xcd +.word Pid_Bad_RxData // 206 0xce +.word Pid_Bad_RxData // 207 0xcf +.word Pid_Bad_RxData // 208 0xd0 +.word Pid_Bad_RxData // 209 0xd1 +.word Pid_Bad_RxData // 210 0xd2 +.word Pid_Bad_RxData // 211 0xd3 +.word Pid_Bad_RxData // 212 0xd4 +.word Pid_Bad_RxData // 213 0xd5 +.word Pid_Bad_RxData // 214 0xd6 +.word Pid_Bad_RxData // 215 0xd7 +.word Pid_Bad_RxData // 216 0xd8 +.word Pid_Bad_RxData // 217 0xd9 +.word Pid_Bad_RxData // 218 0xda +.word Pid_Bad_RxData // 219 0xdb +.word Pid_Bad_RxData // 220 0xdc +.word Pid_Bad_RxData // 221 0xdd +.word Pid_Bad_RxData // 222 0xde +.word Pid_Bad_RxData // 223 0xdf +.word Pid_Bad_RxData // 224 0xe0 +.word Pid_Bad_RxData // 225 0xe1 +.word Pid_Bad_RxData // 226 0xe2 +.word Pid_Bad_RxData // 227 0xe3 +.word Pid_Bad_RxData // 228 0xe4 +.word Pid_Bad_RxData // 229 0xe5 +.word Pid_Bad_RxData // 230 0xe6 +.word Pid_Bad_RxData // 231 0xe7 +.word Pid_Bad_RxData // 232 0xe8 +.word Pid_Bad_RxData // 233 0xe9 +.word Pid_Bad_RxData // 234 0xea +.word Pid_Bad_RxData // 235 0xeb +.word Pid_Bad_RxData // 236 0xec +.word Pid_Bad_RxData // 237 0xed +.word Pid_Bad_RxData // 238 0xee +.word Pid_Bad_RxData // 239 0xef +.word Pid_Bad_RxData // 240 0xf0 +.word Pid_Bad_RxData // 241 0xf1 +.word Pid_Bad_RxData // 242 0xf2 +.word Pid_Bad_RxData // 243 0xf3 +.word Pid_Bad_RxData // 244 0xf4 +.word Pid_Bad_RxData // 245 0xf5 +.word Pid_Bad_RxData // 246 0xf6 +.word Pid_Bad_RxData // 247 0xf7 +.word Pid_Bad_RxData // 248 0xf8 +.word Pid_Bad_RxData // 249 0xf9 +.word Pid_Bad_RxData // 250 0xfa +.word Pid_Bad_RxData // 251 0xfb +.word Pid_Bad_RxData // 252 0xfc +.word Pid_Bad_RxData // 253 0xfd +.word Pid_Bad_RxData // 254 0xfe +.word Pid_Bad_RxData // 255 0xff + +.size PidJumpTable_RxData, .-PidJumpTable_RxData +.cc_bottom PidJumpTable_RxData.func + +#endif diff --git a/lib_xud/src/core/included/XUD_RxData.S b/lib_xud/src/core/included/XUD_RxData.S index dde77ddf..fdc9a64d 100644 --- a/lib_xud/src/core/included/XUD_RxData.S +++ b/lib_xud/src/core/included/XUD_RxData.S @@ -1,68 +1,97 @@ // Copyright 2019-2021 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. - #define PASTER(x,y) x ## _ ## y #define EVALUATOR(x,y) PASTER(x,y) -//#define LABEL(fun) EVALUATOR(fun, LABELNO) #define LABEL(fun) fun // r0: RXD: Rx Data port // r1: Buffer // r2: Tx Port // r3: Ep structure -// r4: zero -// r5: buffer address -// r5: ep structures array -// r6: crc rx init -// r7: crc tx init -// r9: crc poly -// r8: -// r10: ep number -// r11: scratch +// r4: Zero (set in XUD_CrcAddCheck.S) then buffer index +// r5: EP structures array +// r6: CRC Rx init +// r7: CRC Tx init +// r9: CRC poly +// r8: Scratch +// r10: EP number +// r11: Scratch -doRXData_badPid: - ldc r8, 16 // Note, this is a cut-down version of XUD_TokenJump.S - ldaw r10, dp[PidJumpTable] - ldw r11, r10[r7] - {bau r11; setpsc res[RXD], r8} +// On exit require: +// r4: Datalength (words) +// r8: Taillength (bits) +// r11: Expected CRC -LABEL(doRXData): +Pid_Bad_RxData: + ldaw r10, dp[PidJumpTable] + {ldw r11, r10[r4]; ldc r8, 16} + {bau r11; setpsc res[RXD], r8} // XUD_CrcAddrCheck.S requires 16 in r8 - inpw r8, res[r0], 8 // Input PID +doRXData: + inpw r4, res[r0], 8 // Input PID + ldw r8, sp[STACK_RXA_PORT] +#ifdef __XS2A__ // If pid != DATAx then jump and handle as a token. DATA0, DATA1, DATA2 & MDATA all of the form 0bxx11. // This is a fast alternative to a "timeout" - {shr r7, r8, 24; mkmsk r11, 2} - and r11, r11, r7 - eq r11, r11, 3 - bf r11, doRXData_badPid - {setsr 1; ldw r7, sp[STACK_RXA_PORT]} // Load RxA Port ID + // Note, this doesn't check that PID[0:3] = ~PID[4:7] - which is an issue for XS3 + {mkmsk r11, 2; shr r4, r4, 24} + and r11, r11, r4 // Store PID into EP structure, + eq r11, r11, 3 + bf r11, Pid_Bad_RxData +#else + {shr r4, r4, 24; ldw r11, sp[STACK_PIDJUMPTABLE_RXDATA]} + ldw r11, r11[r4] + bau r11 +#endif + +Pid_Datam_RxData: +Pid_Data0_RxData: +Pid_Data1_RxData: +Pid_Data2_RxData: + {stw r4, r3[6]; setsr 1} // Store PID into EP structure -LABEL(GotRxPid): - eeu res[r7] // Enable events on RxA +GotRxPid: + {eeu res[r8]; mkmsk r4, 32} // Enable events on RxA + // Init buffer index to -1 -LABEL(NextRxWord): +NextRxWord: // Partially un-rolled to assist with timing + in r11, res[r0] + crc32_inc r6, r11, r9, r4, 1 + stw r11, r1[r4] in r11, res[r0] + crc32_inc r6, r11, r9, r4, 1 stw r11, r1[r4] + in r11, res[r0] crc32_inc r6, r11, r9, r4, 1 + stw r11, r1[r4] in r11, res[r0] + crc32_inc r6, r11, r9, r4, 1 stw r11, r1[r4] + in r11, res[r0] crc32_inc r6, r11, r9, r4, 1 + stw r11, r1[r4] in r11, res[r0] + crc32_inc r6, r11, r9, r4, 1 stw r11, r1[r4] + in r11, res[r0] crc32_inc r6, r11, r9, r4, 1 + stw r11, r1[r4] in r11, res[r0] + crc32_inc r6, r11, r9, r4, 1 stw r11, r1[r4] + in r11, res[r0] crc32_inc r6, r11, r9, r4, 1 - bu LABEL(NextRxWord) + stw r11, r1[r4] + bu NextRxWord ///////////////////////////////////////////////////////////////////////////// .align 32 -.skip 20 +.skip 16 RxALow: - {stw r8, r3[6]; in r7, res[r7]} // Store (NON-SHIFTED) PID into EP structure, - // Clear event data on RXA + stw r11, r1[r4] // Extra stw, if not enough MIPS STW in loop above may not have chance to run + {in r8, res[r8]; add r4, r4, 1} // Clear event data on RXA endin r8, res[r0] LABEL(RxTail): {in r11, res[r0]; bru r8} diff --git a/lib_xud/src/core/included/XUD_Token_In_DI.S b/lib_xud/src/core/included/XUD_Token_In_DI.S index 965515f4..a9ce35ea 100755 --- a/lib_xud/src/core/included/XUD_Token_In_DI.S +++ b/lib_xud/src/core/included/XUD_Token_In_DI.S @@ -13,13 +13,13 @@ // R10: EP number (used here) // R9 : CRC16 Poly (used here) // R8 : -// R7 : +// R7 : Tx CRC init // R6 : ep_pid_sequence_table_IN_A -// R5 : Channel Array +// R5 : EP structures array // R4 : // R3 : 0 // R2 : TXD -// R1 : Valid Token Port (XS2 only) +// R1 : XS2: Valid Token Port, XS3: Spare! // R0 : RXD .align FUNCTION_ALIGNMENT XUD_IN_NotReady: @@ -31,8 +31,10 @@ XUD_IN_NotReady: #include "XUD_TokenJmp.S" XUD_IN_TxHandshake: // Non-Iso - ldaw r11, dp[handshakeTable_IN] // Load handshake table - ldw r11, r11[r10] // Load handshake PID (or 0) + ldaw r11, dp[ep_addr] + ldw r11, r11[r3] + ldw r11, r11[10] + bf r11, XUD_IN_TxNak outpw res[TXD], r11, 8 // Output STALL #include "XUD_TokenJmp.S" @@ -52,12 +54,7 @@ Pid_In: ldaw r3, r10[4] // R3 = R10 + 16 ldw r4, r5[r3] // Load EP structure address bf r4, XUD_IN_NotReady - - ldaw r11, dp[handshakeTable_IN] // Load handshake table - ldw r11, r11[r10] - bt r11, XUD_IN_TxStall // Note, user could potentially stall an ISO EP. - - ldw r11, r4[4] // Load PID from structure + ldw r1, r4[4] // Load PID from structure XUD_IN_Ready: ldw r8, r4[3] // Load buffer @@ -66,13 +63,12 @@ XUD_IN_Ready: bf r4, XUD_IN_SmallTxPacket // Check for Short packet XUD_IN_Tx: - outpw res[TXD], r11, 8 // Out PID ldw r11, r8[r4] // Load first data word + crc32_inc r7, r11, r9, r4, 1 + outpw res[TXD], r1, 8 // Out PID -XUD_IN_TxPid: - out res[TXD], r11 - crc32_inc r7, r11, r9, r4, 1 - bf r4, XUD_IN_TxLoopEnd +XUD_IN_Loop0: + {out res[TXD], r11; bf r4, XUD_IN_TxLoopEnd} XUD_IN_TxLoop: ldw r11, r8[r4] // Load first data word @@ -102,7 +98,6 @@ DoneTail: SetupReceiveHandShake: ldc r11, 8 setpsc res[RXD], r11 // Set port shift count (expect 8 bit handshake) - eeu res[RXD] // Events on RXD always enabled - Can;t be any more due to using events on channels SetupTimeout: // Timeout done using another port we dont happen to already be using events on. Cunning. #ifdef __XS2A__ @@ -110,6 +105,8 @@ SetupTimeout: // Timeout done using another #else ldw r1, dp[rx_rdy] // TODO load from stack #endif + eeu res[RXD] // Events on RXD always enabled - Can;t be any more due to using events on channels + in r11, res[r1] // Do input and get port time/timestamps getts r11, res[r1] ldw r9, dp[g_txHandshakeTimeout] @@ -131,7 +128,6 @@ TxHandshakeTimeOut: // Transmitted data, and got something back within the timeout. Check for valid handshake... .align FUNCTION_ALIGNMENT TxHandShakeReceived: -XUD_IN_RxAck: in r11, res[RXD] // Input data from RXD port clrpt res[r1] // Clear port time on valid token port @@ -174,46 +170,45 @@ TxTail0s: // We know this is a < 4 byte // So crc = 0. Note our normal crc calculation works for this, it is // Not a special CRC case, but helps with timing. XUD_IN_TxPid_TailS0: - outpw res[TXD], r11, 8 // PID + outpw res[TXD], r1, 8 // PID XUD_IN_TxCrc_TailS0: - outpw res[TXD], r4, 16 // Output CRC + outpw res[TXD], r4, 16 // Output CRC bu DoneTail .align 32 .skip 0 -TxTail1s: // One tail byte - shl r6, r8, 8 // Concat PID and Data - or r11, r11, r6 - crc8 r7, r8, r8, r9 - crc32 r7, r4, r9 // r4: 0 - not r7, r7 +TxTail1s: // One tail byte + crcn r7, r8, r9, r6 + crc32 r7, r4, r9 // r4: 0 XUD_IN_TxPid_TailS1: - outpw res[TXD], r11, 16 // PID + not r7, r7 + outpw res[TXD], r1, 8 // Output PID + outpw res[TXD], r8, 8 // Output data[0] XUD_IN_TxCrc_TailS1: outpw res[TXD], r7, 16 bu DoneTail .align 32 .skip 0 -TxTail2s: // Two tail byte +TxTail2s: // Two tail byte crcn r7, r8, r9, r6 - shl r6, r8, 8 - crc32 r7, r4, r9 // r4: 0 - {not r7, r7; or r11, r11, r6} + crc32 r7, r4, r9 // r4: 0 XUD_IN_TxPid_TailS2: - outpw res[TXD], r11, 24 // Output PID and 2 bytes of data + outpw res[TXD], r1, 8 // Output PID + outpw res[TXD], r8, 16 // Output data[0:1] + not r7, r7 XUD_IN_TxCrc_TailS2: - outpw res[TXD], r7, 16 // Output CRC16 + outpw res[TXD], r7, 16 // Output CRC16 bu DoneTail .align 32 .skip 0 -TxTail3s: // Three tail byte +TxTail3s: // Three tail byte XUD_IN_TxPid_TailS3: - outpw res[TXD], r11, 8 // PID + outpw res[TXD], r1, 8 // PID outpw res[TXD], r8, 24 crcn r7, r8, r9, r6 - crc32 r7, r4, r9 // r4: 0 + crc32 r7, r4, r9 // r4: 0 not r7, r7 XUD_IN_TxCrc_TailS3: outpw res[TXD], r7, 16 @@ -221,12 +216,12 @@ XUD_IN_TxCrc_TailS3: .align 32 .skip 0 -TxTail4s: // Four tail byte +TxTail4s: // Four tail byte XUD_IN_TxPid_TailS4: - outpw res[TXD], r11, 8 // PID + outpw res[TXD], r1, 8 // PID out res[TXD], r8 crc32 r7, r8, r9 - crc32 r7, r4, r9 // r4: 0 + crc32 r7, r4, r9 // r4: 0 not r7, r7 XUD_IN_TxCrc_TailS4: outpw res[TXD], r7, 16 diff --git a/lib_xud/src/core/included/XUD_Token_Out_DI.S b/lib_xud/src/core/included/XUD_Token_Out_DI.S index 04b842ef..55996bd5 100755 --- a/lib_xud/src/core/included/XUD_Token_Out_DI.S +++ b/lib_xud/src/core/included/XUD_Token_Out_DI.S @@ -19,10 +19,10 @@ CheckEpTypeOut: OutReady: stw r11, r5[r10] // Clear ready straight away - we don't to CRC checking on Iso - else we would have to wait for end of packet bl doRXData - clre + {clre; + ldw r11, r3[1]} // Load EP chanend InformEP_Iso: // Iso EP - no handshake - ldw r11, r3[1] // Load EP chanend {out res[r11], r4; ldw r7, sp[STACK_TXCRC_INIT]} // Output datalength (words) & CRC 16 Init (IN) {outt res[r11], r8; ldw r6, sp[STACK_RXCRC_INIT]} // CRC16 init (out) - Needs reseting after an out & Send tail length #ifndef __XS3A__ @@ -39,16 +39,6 @@ DoOutNonIso: doRXDataReturn_NonIso: bf r1, NextTokenAfterOut // Check for bad crc - ldaw r6, dp[handshakeTable_OUT] // Load the handshake table. - {ldw r11, r6[r10] // Get the handshake PID for this EP - ldc r1, USB_PIDn_STALL} // as well as the STALL PID - eq r1, r11, r1 // and compare them. - nop // NOP to ensure minimum interpacket delay. - bt r1, XUD_TokenOut_Handshake // If the handshake PID for this EP is STALL, then - // go and send the handshake without clearing ready - // or communicating back to the application that - // the packet has been received. - ldc r11, USB_PIDn_ACK // Data CRC good, EP not Iso, and EP not halted: Send Ack outpw res[TXD], r11, 8 syncr res[TXD] @@ -80,13 +70,12 @@ Err_RxErr: // RxError signal high during da XUD_TokenOut_BufferFull: ldw r9, sp[STACK_RXA_PORT] setc res[r9], XS1_SETC_RUN_CLRBUF - setc res[r9], XS1_SETC_COND_NEQ + inpw r4, res[r0], 8 // Input PID of next packet. + // TODO catch case where PID is not DATA XUD_TokenOut_WaitForPacketEnd: // Wait for end of data then send NAK in r11, res[r9] - setc res[r9], XS1_SETC_COND_EQ - in r11, res[r9] - // TODO: Observe interpacket delay + #ifndef XUD_NAK_ISO_OUT ldw r4, sp[STACK_EPTYPES_OUT] // Load ep type table ldw r4, r4[r10] // load EP type @@ -94,9 +83,11 @@ XUD_TokenOut_WaitForPacketEnd: // Wait for end of data then sen #endif // Load handshake (ACK or STALL) - ldaw r6, dp[handshakeTable_OUT] // Load handshake table XUD_TokenOut_Handshake: - ldw r11, r6[r10] + ldaw r6, dp[ep_addr] + ldw r6, r6[r10] + ldw r11, r6[10] + outpw res[TXD], r11, 8 syncr res[TXD] diff --git a/lib_xud/src/core/included/XUD_Token_Ping.S b/lib_xud/src/core/included/XUD_Token_Ping.S index 79ce7dc2..0ae72f43 100755 --- a/lib_xud/src/core/included/XUD_Token_Ping.S +++ b/lib_xud/src/core/included/XUD_Token_Ping.S @@ -31,11 +31,11 @@ PrimaryBufferFull_PING: // Send NAK (or STALL) nop nop #endif - nop - nop - nop - ldaw r11, dp[handshakeTable_OUT] // Load handshake table - ldw r11, r11[r10] // Load handshake (ACK or STALL) + + ldaw r11, dp[ep_addr] + ldw r11, r11[r10] + ldw r11, r11[10] + outpw res[TXD], r11, 8 bu NextTokenAfterPing .scheduling default diff --git a/lib_xud/src/core/included/XUD_Token_Setup_DI.S b/lib_xud/src/core/included/XUD_Token_Setup_DI.S index 870f1321..81131762 100644 --- a/lib_xud/src/core/included/XUD_Token_Setup_DI.S +++ b/lib_xud/src/core/included/XUD_Token_Setup_DI.S @@ -22,11 +22,16 @@ XUD_SETUP_LoadBuffer: XUD_SETUP_ClearStall: // CRC OK // Have received a SETUP so clear any STALL condition on IN/OUT endpoint. - ldaw r11, dp[handshakeTable_OUT] // Note, we can speed this up by assuming SETUP only received on EP 0 - ldc r6, USB_PIDn_NAK - stw r6, r11[r10] - ldw r11, sp[STACK_HANDSHAKETABLEIN] - stw r1, r11[r10] + // Note, we can speed this up by assuming SETUP only received on EP 0 + ldaw r6, dp[ep_addr] + + ldaw r11, r10[4] // R11 = R10 + 16 + ldw r11, r6[r11] + stw r1, r11[10] // r1: 0 + + ldw r11, r6[r10] + ldc r6, USB_PIDn_NAK + stw r6, r11[10] XUD_SETUP_SendSetupAck: ldc r11, USB_PIDn_ACK diff --git a/lib_xud/src/user/client/XUD_EpFuncs.S b/lib_xud/src/user/client/XUD_EpFuncs.S index 5422500b..b8d7aa03 100644 --- a/lib_xud/src/user/client/XUD_EpFuncs.S +++ b/lib_xud/src/user/client/XUD_EpFuncs.S @@ -67,7 +67,7 @@ XUD_GetSetupData_ResetPid: // We must reset PID toggling on #endif stw r11, r0[4] // Reset OUT toggle - ldc r11, 640 // Assuming MAX_NUM_EPS is 16 and struct size is 40 here! + ldc r11, 768 // Assuming MAX_NUM_EPS is 16 and struct size is 44 here! add r11, r0, r11 ldc r10, USB_PIDn_DATA1 @@ -89,7 +89,7 @@ XUD_GetSetupData_GotOut: // Got an OUT instead not a SETU XUD_GetSetupData_CheckPid: ldw r11, r0[6] // Load received PID from EP structure - shr r11, r11, 24 // Shift down due to inpw + //shr r11, r11, 24 // Shift down due to inpw ldw r10, r0[4] // Load expected PID xor r11, r10, r11 // Do the comparison @@ -138,250 +138,6 @@ XUD_GetSetupData_Reset: .set XUD_GetSetupData.locnointerfaceaccess, 1 .set XUD_GetSetupData.locnonotificationselect, 1 -//int XUD_GetData(XUD_ep c, unsigned char buffer[], unsigned &length); -// r0 r1 r2 -.globl XUD_GetData -.type XUD_GetData, @function -.cc_top XUD_GetData.func -.align FUNCTION_ALIGNMENT -XUD_GetData: -#if defined(__XS2A__) || defined(__XS3A__) -.issue_mode single - ENTSP_lu6 4 -#else - entsp 4 -#endif - stw r10, sp[1] - mov r11, r1 - -XUD_GetData_: - ldw r10, r0[9] // Check if we missed a reset - bt r10, XUD_GetData_Reset - - stw r1, r0[3] // Store buffer address in EP structure - - ldw r10, r0[0] // Load mem address of EP in XUD ep table - stw r0, r10[0] - -XUD_GetData_Retry: - ldw r10, r0[2] // Load our chanend ID to use - // Wait for XUD response - testct r11, res[r10] // Test whether there is a RESET/SUSPEND exception - bt r11, XUD_GetData_Reset - -XUD_GetData_DataEnd: - in r3, res[r10] // Input packet "word" length - -XUD_GetData_SetupCheck: // Check if we have OUT or SETUP - testct r11, res[r10] - bt r11, XUD_GetData_GotSetup - int r11, res[r10] // r11 is tail length (bytes) - shr r11, r11, 3 - bu XUD_GetDataCalcDataLength - -XUD_GetDataCalcDataLength: - shl r3, r3, 2 // Num received words to bytes - add r3, r11, r3 // r11: Total bytes received (Note this includes 2 byte crc) - -XUD_GetData_CheckPid: - ldw r11, r0[6] // Load received PID from EP structure - shr r11, r11, 24 // Shift down due to inpw - ldw r10, r0[4] // Load expected PID - - xor r11, r10, r11 // Do the comparison - bt r11, XUD_GetData_ // Ignore packet... - -XUD_GetData_PidOkay: - ldw r11, r0[5] // Load EP type - bf r11, XUD_GetData_ReturnOk // Jump over PID toggle for ISO - -XUD_GetData_PidToggle: -#ifdef __XS3A__ - ldc r11, 0x88 -#else - ldc r11, 8 -#endif - xor r10, r10, r11 - stw r10, r0[4] - -XUD_GetData_ReturnOk: - sub r0, r3, 2 // Length correction for CRC correction - stw r0, r2[0] // Store in length (passed by ref) - - ldc r0, 0 // Return 0 for success - - ldw r10, sp[1] // TODO should check for <0 as ISO doesn't have CRC check - retsp 4 - -XUD_GetData_Reset: - mkmsk r0, 32 // Return -1 as length - -Return: - ldw r10, sp[1] - retsp 4 - -/////// -XUD_GetData_GotSetup: - inct r11, res[r10] // Expect r11: 0 - -//XUD_GetSetupData_CheckPid: - // We expect data0 else something gone wrong... - // TODO.. - -XUD_GetDataSetupData_ResetPid: // We must reset PID toggling on SETUP (both IN AND OUT) -#ifdef __XS3A__ - ldc r11, USB_PIDn_DATA1 -#else - ldc r11, USB_PID_DATA1 -#endif - stw r11, r0[4] // Reset OUT toggle - - ldc r11, 640 // Assuming MAX_NUM_EPS is 16 and struct size is 40 here! - add r11, r0, r11 - - ldc r10, USB_PIDn_DATA1 - stw r10, r11[4] // Reset IN toggle - - ldc r0, 8 // Return 8 byte length (TODO really could return actual length here) - stw r0, r2[0] - - ldc r0, 1 // Return got control XUD_RES_CTL - - ldw r10, sp[1] - retsp 4 - - - -.size XUD_GetData, .-XUD_GetData -.cc_bottom XUD_GetData.func -.globl XUD_GetData.nstackwords -.globl XUD_GetData.maxchanends -.globl XUD_GetData.maxtimers -.globl XUD_GetData.maxcores -.set XUD_GetData.nstackwords, 4 -.set XUD_GetData.maxchanends, 0 -.set XUD_GetData.maxtimers, 0 -.set XUD_GetData.maxcores, 1 -.globl XUD_GetData.locnoside -.globl XUD_GetData.locnochandec -.globl XUD_GetData.locnoglobalaccess -.globl XUD_GetData.locnointerfaceaccess -.globl XUD_GetData.locnonotificationselect -.set XUD_GetData.locnoside, 1 -.set XUD_GetData.locnochandec, 1 -.set XUD_GetData.locnoglobalaccess, 1 -.set XUD_GetData.locnointerfaceaccess, 1 -.set XUD_GetData.locnonotificationselect, 1 - - -// Note: Assumes startIndex is word aligned -// int XUD_SetData_indexed(XUD_ep e, unsigned buffer[], unsigned datasize, unsigned startIndex unsigned pid); -// r0 r1 r2 r3 -.globl XUD_SetData -.type XUD_SetData, @function -.cc_top XUD_SetData.func -.align FUNCTION_ALIGNMENT -XUD_SetData: -#if defined(__XS2A__) || defined(__XS3A__) -.issue_mode single - ENTSP_lu6 8 -#else - entsp 8 -#endif - stw r5, sp[5] - stw r10, sp[6] - -XUD_SetDataRetry: - stw r4, sp[0] - - ldw r11, r0[9] // Check if we missed a reset - bt r11, XUD_SetData_Reset - -XUD_SetData_NoReq: - add r1, r1, r3 // Add start index to buffer address - -CalcTailLength: - shl r3, r2, 3 // Tail length: bytes to bits - zext r3, 5 - -SetupLoopTerm: - shr r2, r2, 2 // r2: datalength (bytes) ---> r2: datalength (words) - - // TODO do this a bit more effciently.. - // If tail is 0 and word-length not 0. Make tail-length 32 and word-length-- - bt r3, AdjustBufferPointer - bf r2, AdjustBufferPointer - - sub r2, r2, 1 - ldc r3, 32 - -AdjustBufferPointer: - shl r5, r2, 2 // Get end off buffer address - add r1, r1, r5 - - -NegativeIndex: // Produce negtive offset from end of buffer - neg r2, r2 - stw r2, r0[6] // Store index - -XUD_SetData_DataRdy: - ldw r2, r0[0] // Load mem address of EP structure - stw r1, r0[3] // Store buffer address -StoreTailLength: - stw r3, r0[7] // Store tail length (bytes) - - stw r0, r2[0] // Mark ready with address of ep structure - - // Wait for XUD Response - ldw r10, r0[2] // Load our chanend ID to use - testct r11, res[r10] // Test for RESET/SUSPEND exception - bt r11, XUD_SetData_Reset - - in r11, res[r10] // Data sent okay - -XUD_SetData_LoadEpType: - ldw r11, r0[5] // Don't do any toggling for ISO - bf r11, XUD_SetData_DonePid - -XUD_SetData_PidToggle: // - ldw r11, r0[4] // Load EP PID from structure - ldc r4, 0x88 - xor r11, r11, r4 - stw r11, r0[4] // Store back PID - -XUD_SetData_DonePid: - ldc r0, 0 -XUD_SetData_Return: - ldw r4, sp[0] - ldw r5, sp[5] - ldw r10, sp[6] - retsp 8 - -XUD_SetData_Reset: - mkmsk r0, 32 // Return -1 - bu XUD_SetData_Return - -.size XUD_SetData, .-XUD_SetData -.cc_bottom XUD_SetData.func -.globl XUD_SetData.nstackwords -.globl XUD_SetData.maxchanends -.globl XUD_SetData.maxtimers -.globl XUD_SetData.maxcores -.set XUD_SetData.nstackwords, 8 -.set XUD_SetData.maxchanends, 0 -.set XUD_SetData.maxtimers, 0 -.set XUD_SetData.maxcores, 1 -.globl XUD_SetData.locnoside -.globl XUD_SetData.locnochandec -.globl XUD_SetData.locnoglobalaccess -.globl XUD_SetData.locnointerfaceaccess -.globl XUD_SetData.locnonotificationselect -.set XUD_SetData.locnoside, 1 -.set XUD_SetData.locnochandec, 1 -.set XUD_SetData.locnoglobalaccess, 1 -.set XUD_SetData.locnointerfaceaccess, 1 -.set XUD_SetData.locnonotificationselect, 1 - //void XUD_GetData_Select(chan c, XUD_ep ep, unsigned &datalength, XUD_Result_t &result); // r0, r1 r2 r3 .globl XUD_GetData_Select @@ -416,7 +172,7 @@ XUD_GetData_CheckDataLength: XUD_GetData_Select_CheckPid: // Check PID ldw r11, r1[6] // Load received PID from EP structure - shr r11, r11, 24 // Shift off junk + //shr r11, r11, 24 // Shift off junk // Note: We can't just jump back to XUD_GetData_Select since other EP's might need service @@ -531,117 +287,6 @@ XUD_SetData_Select_Reset: .set XUD_SetData_Select.locnonotificationselect, 1 -.globl XUD_SetStallByAddr -.type XUD_SetStallByAddr, @function - -/* R0: ep number */ -.cc_top XUD_SetStallByAddr.func -.align FUNCTION_ALIGNMENT -XUD_SetStallByAddr: -#if defined(__XS2A__) || defined(__XS3A__) -.issue_mode single - ENTSP_lu6 0 -#endif - ldc r2, USB_PIDn_STALL - ldc r11, 0x80 // Check for IN bit - and r11, r11, r0 - bf r11, XUD_SetStallByAddr_OUT - ldaw r1, dp[handshakeTable_IN] - mkmsk r11, 7 - and r11, r11, r0 - stw r2, r1[r11] - - retsp 0 -XUD_SetStallByAddr_OUT: - ldaw r1, dp[handshakeTable_OUT] - stw r2, r1[r0] - retsp 0 -.size XUD_SetStallByAddr, .-XUD_SetStallByAddr -.cc_bottom XUD_SetStallByAddr.func -.globl XUD_SetStallByAddr.nstackwords -.globl XUD_SetStallByAddr.maxchanends -.globl XUD_SetStallByAddr.maxtimers -.globl XUD_SetStallByAddr.maxcores -.set XUD_SetStallByAddr.nstackwords, 0 -.set XUD_SetStallByAddr.maxchanends, 0 -.set XUD_SetStallByAddr.maxtimers, 0 -.set XUD_SetStallByAddr.maxcores, 1 -.globl XUD_SetStallByAddr.locnoside -.globl XUD_SetStallByAddr.locnochandec -.globl XUD_SetStallByAddr.locnoglobalaccess -.globl XUD_SetStallByAddr.locnointerfaceaccess -.globl XUD_SetStallByAddr.locnonotificationselect -.set XUD_SetStallByAddr.locnoside, 1 -.set XUD_SetStallByAddr.locnochandec, 1 -.set XUD_SetStallByAddr.locnoglobalaccess, 1 -.set XUD_SetStallByAddr.locnointerfaceaccess, 1 -.set XUD_SetStallByAddr.locnonotificationselect, 1 - - -.globl XUD_ClearStallByAddr -.type XUD_ClearStallByAddr, @function - -/* R0: ep number */ -.cc_top XUD_ClearStallByAddr.func -.issue_mode single -.align FUNCTION_ALIGNMENT -XUD_ClearStallByAddr: - ENTSP_lu6 0 - ldc r2, USB_PIDn_NAK - ldc r11, 0x80 // Check for IN bit - and r11, r11, r0 - bf r11, XUD_ClearStallByAddr_OUT - ldaw r1, dp[handshakeTable_IN] // Reset Handshake - mkmsk r11, 7 - and r11, r11, r0 - ldc r2, 0 // Clear with 0 (differs to OUT) - stw r2, r1[r11] - // Calc offset for data pid - ldaw r0, r11[4] // Assume MAX_NUM_EP_OUT is 16 here! (r0 = r0 + 4 * 4) - ldc r1, USB_PIDn_DATA0 - bu XUD_ClearStallByAddr_ResetDataPid - -XUD_ClearStallByAddr_OUT: - ldc r2, USB_PIDn_NAK - ldaw r1, dp[handshakeTable_OUT] - stw r2, r1[r0] - -#ifdef __XS3A__ - ldc r1, USB_PIDn_DATA0 -#else - ldc r1, USB_PID_DATA0 -#endif - -XUD_ClearStallByAddr_ResetDataPid: // Reset DATA PID to DATA0 - ldc r2, 40 // Size of XUD_ep_info struct TODO use sizeof() - - mul r0, r0, r2 // Be careful with packing - ldw r2, cp[ep_info_address] - add r0, r2, r0 - stw r1, r0[4] - retsp 0 - - -.size XUD_ClearStallByAddr, .-XUD_ClearStallByAddr -.cc_bottom XUD_ClearStallByAddr.func -.globl XUD_ClearStallByAddr.nstackwords -.globl XUD_ClearStallByAddr.maxchanends -.globl XUD_ClearStallByAddr.maxtimers -.globl XUD_ClearStallByAddr.maxcores -.set XUD_ClearStallByAddr.nstackwords, 0 -.set XUD_ClearStallByAddr.maxchanends, 0 -.set XUD_ClearStallByAddr.maxtimers, 0 -.set XUD_ClearStallByAddr.maxcores, 1 -.globl XUD_ClearStallByAddr.locnoside -.globl XUD_ClearStallByAddr.locnochandec -.globl XUD_ClearStallByAddr.locnoglobalaccess -.globl XUD_ClearStallByAddr.locnointerfaceaccess -.globl XUD_ClearStallByAddr.locnonotificationselect -.set XUD_ClearStallByAddr.locnoside, 1 -.set XUD_ClearStallByAddr.locnochandec, 1 -.set XUD_ClearStallByAddr.locnoglobalaccess, 1 -.set XUD_ClearStallByAddr.locnointerfaceaccess, 1 -.set XUD_ClearStallByAddr.locnonotificationselect, 1 - .globl XUD_ResetEpStateByAddr .type XUD_ResetEpStateByAddr, @function @@ -649,27 +294,25 @@ XUD_ClearStallByAddr_ResetDataPid: // Reset DATA PID to DATA0 .cc_top XUD_ResetEpStateByAddr.func .align FUNCTION_ALIGNMENT XUD_ResetEpStateByAddr: -#if defined(__XS2A__) || defined(__XS3A__) .issue_mode single - ENTSP_lu6 0 -#endif + ENTSP_lu6 0 ldc r1, 0x80 and r2, r0, r1 bf r2, XUD_ResetEpStateByAddr_OUT ldc r1, USB_PIDn_DATA0 bu XUD_ResetEpStateByAddr_ XUD_ResetEpStateByAddr_OUT: -#if defined(__XS3A__) - ldc r1, USB_PIDn_DATA0 -#else +#if defined(__XS2A__) ldc r1, USB_PID_DATA0 +#else + ldc r1, USB_PIDn_DATA0 #endif XUD_ResetEpStateByAddr_: zext r0, 7 // Check for IN bit set bf r2, NoOffset ldaw r0, r0[4] // Assume MAX_NUM_EP_OUT is 16 here! (r0 = r0 + 4 * 4) NoOffset: - ldc r2, 40 // Size of XUD_ep_info struct TODO. FIXME! + ldc r2, 48 // Size of XUD_ep_info struct TODO. FIXME! mul r0, r0, r2 ldw r2, cp[ep_info_address] add r0, r2, r0 diff --git a/lib_xud/src/user/client/XUD_EpFunctions.c b/lib_xud/src/user/client/XUD_EpFunctions.c new file mode 100644 index 00000000..82fcc325 --- /dev/null +++ b/lib_xud/src/user/client/XUD_EpFunctions.c @@ -0,0 +1,242 @@ +// Copyright 2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "xud.h" +#include "XUD_USB_Defines.h" + +extern XUD_ep_info ep_info[USB_MAX_NUM_EP]; + +void XUD_SetStallByAddr(int epNum) +{ + if(epNum & 0x80) + { + epNum &= 0x7f; + epNum += 16; + } + + XUD_ep_info *ep = &ep_info[epNum]; + + unsigned *epReadyEntry = (unsigned *)ep->array_ptr; + + if(*epReadyEntry != 0) + { + /* Mark EP as not ready (and save that it was ready at Halting */ + ep->saved_array_ptr = *epReadyEntry; + *epReadyEntry = 0; + } + ep->halted = USB_PIDn_STALL; +} + +void XUD_ClearStallByAddr(int epNum) +{ + unsigned handshake = USB_PIDn_NAK; + + /* Reset data PID */ + XUD_ResetEpStateByAddr(epNum); + + if(epNum & 0x80) + { + epNum &= 0x7f; + epNum += 16; + handshake = 0; + } + + XUD_ep_info *ep = &ep_info[epNum]; + + /* Re-mark as ready if was ready before halting */ + if(ep->saved_array_ptr != 0) + { + unsigned *epReadyEntry = (unsigned *)ep->array_ptr; + *epReadyEntry = ep->saved_array_ptr; + ep->saved_array_ptr = 0; + } + + /* Mark EP as un-halted */ + ep->halted = handshake; +} + + +XUD_Result_t XUD_SetBuffer(XUD_ep e, unsigned char buffer[], unsigned datalength) +{ + volatile XUD_ep_info * ep = (XUD_ep_info*) e; + unsigned isReset; + unsigned tmp; + + while(1) + { + /* Check if we missed a reset */ + if(ep->resetting) + { + return XUD_RES_RST; + } + + /* If EP is marked as halted do not mark as ready.. */ + if(ep->halted == USB_PIDn_STALL) + { + continue; + } + + int lengthWords = datalength >> 2; + unsigned lengthTail = (datalength << 3) & 0x1f; // zext(5)? + + if((lengthTail == 0) && (lengthWords != 0)) + { + lengthWords -= 1; + lengthTail = 32; + } + + /* Store end of buffer address in EP structure */ + ep->buffer = (unsigned) &buffer[0] + (lengthWords * 4); + + /* XUD uses negative index */ + lengthWords *= -1; + ep->actualPid = lengthWords; /* Re-used of actualPid entry - TODO rename */ + ep->tailLength = lengthTail; + + unsigned * array_ptr = (unsigned *)ep->array_ptr; + *array_ptr = (unsigned) ep; + + /* Wait for XUD response */ + asm volatile("testct %0, res[%1]" : "=r"(isReset) : "r"(ep->client_chanend)); + + if(isReset) + { + return XUD_RES_RST; + } + + /* Data sent okay */ + asm volatile("in %0, res[%1]" : "=r"(tmp) : "r"(ep->client_chanend)); + + /* Don't do any PID toggling for Iso EP's */ + if(ep->epType != XUD_EPTYPE_ISO) + { + ep->pid ^= 0x88; + } + + return XUD_RES_OKAY; + } +} + +XUD_Result_t XUD_GetBuffer(XUD_ep e, unsigned char buffer[], unsigned *datalength) +{ + + volatile XUD_ep_info * ep = (XUD_ep_info*) e; + unsigned isReset; + unsigned length; + unsigned lengthTail; + + while(1) + { + /* Check if we missed a reset */ + if(ep->resetting) + { + return XUD_RES_RST; + } + + /* If EP is marked as halted do not mark as ready.. */ + if(ep->halted == USB_PIDn_STALL) + { + continue; + } + + /* Store buffer address in EP structure */ + ep->buffer = (unsigned) &buffer[0]; + + unsigned * array_ptr = (unsigned *)ep->array_ptr; + *array_ptr = (unsigned) ep; + + /* Wait for XUD response */ + asm volatile("testct %0, res[%1]" : "=r"(isReset) : "r"(ep->client_chanend)); + + if(isReset) + { + return XUD_RES_RST; + } + + /* Input packet length (words) */ + asm volatile("in %0, res[%1]" : "=r"(length) : "r"(ep->client_chanend)); + + /* Input tail length (bytes) */ + asm volatile("int %0, res[%1]" : "=r"(lengthTail) : "r"(ep->client_chanend)); + + /* Bits to bytes */ + lengthTail >>= 3; + + /* Words to bytes */ + length <<= 2; + + /* -2 length correction for CRC */ + *datalength = length + lengthTail - 2; + + /* Load received PID */ + unsigned receivedPid = ep->actualPid; + + /* Check received PID vs expected PID */ + if(receivedPid != ep->pid) + { + continue; + } + + // ISO = 0 + if(ep->epType != XUD_EPTYPE_ISO) + { +#ifdef __XS2A__ + ep->pid ^= 0x8; +#else + ep->pid ^= 0x88; +#endif + } + + return XUD_RES_OKAY; + } +} + +XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax) +{ + int i = 0; + XUD_Result_t result; + + /* Note: We could encompass this in the SetData function */ + if (datalength <= epMax) + { + /* Datalength is less than the maximum per transaction of the EP, so just send */ + result = XUD_SetBuffer(ep_in, buffer, datalength); + return result; + } + else + { + /* Send first packet out and reset PID */ + if((result = XUD_SetBuffer(ep_in, buffer, epMax)) != XUD_RES_OKAY) + { + return result; + } + + i += epMax; + datalength -= epMax; + + while (1) + { + unsigned char *bufferPtr = &buffer[i]; + + if (datalength > epMax) + { + /* PID Automatically toggled */ + if ((result = XUD_SetBuffer(ep_in, bufferPtr, epMax)) != XUD_RES_OKAY) + return result; + + datalength -= epMax; + i += epMax; + } + else + { + /* PID automatically toggled */ + if ((result = XUD_SetBuffer(ep_in, bufferPtr, datalength)) != XUD_RES_OKAY) + return result; + + break; //out of while loop + } + } + } + + return XUD_RES_OKAY; +} diff --git a/lib_xud/src/user/client/XUD_EpFunctions.xc b/lib_xud/src/user/client/XUD_EpFunctions.xc index 051f21fd..e82b70dd 100644 --- a/lib_xud/src/user/client/XUD_EpFunctions.xc +++ b/lib_xud/src/user/client/XUD_EpFunctions.xc @@ -7,7 +7,7 @@ #include #include "xud.h" - +#include "XUD_USB_Defines.h" static inline int min(int x, int y) { @@ -16,74 +16,20 @@ static inline int min(int x, int y) return y; } -XUD_Result_t XUD_GetBuffer(XUD_ep c, unsigned char buffer[], unsigned &datalength) -{ - return XUD_GetData(c, buffer, datalength); -} - // To be deprecated - In favour of XUD_GetControlBuffer() XUD_Result_t XUD_GetSetupBuffer(XUD_ep ep_out, unsigned char buffer[], unsigned &length) { return XUD_GetSetupData(ep_out, buffer, length); } -XUD_Result_t XUD_SetBuffer(XUD_ep c, unsigned char buffer[], unsigned datalength) -{ - /* No PID reset, 0 start index */ - return XUD_SetData(c, buffer, datalength, 0, 0); -} - void XUD_Kill(XUD_ep ep) { XUD_SetTestMode(ep, 0); } -XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax) -{ - int i = 0; - XUD_Result_t result; - - /* Note: We could encompass this in the SetData function */ - if (datalength <= epMax) - { - /* Datalength is less than the maximum per transaction of the EP, so just send */ - result = XUD_SetData(ep_in, buffer, datalength, 0, 0); - return result; - } - else - { - /* Send first packet out and reset PID */ - if((result = XUD_SetData(ep_in, buffer, epMax, 0, 0)) != XUD_RES_OKAY) - { - return result; - } - i+= epMax; - datalength-=epMax; - - while (1) - { - if (datalength > epMax) - { - /* PID Automatically toggled */ - if ((result = XUD_SetData(ep_in, buffer, epMax, i, 0)) != XUD_RES_OKAY) - return result; - - datalength-=epMax; - i += epMax; - } - else - { - /* PID automatically toggled */ - if ((result = XUD_SetData(ep_in, buffer, datalength, i, 0)) != XUD_RES_OKAY) - return result; - - break; //out of while loop - } - } - } - - return XUD_RES_OKAY; -} +#ifndef EP0_MAX_PACKET_SIZE +#define EP0_MAX_PACKET_SIZE 64 +#endif /* TODO Should take ep max length as a param - currently hardcoded as 64 (#11384) */ XUD_Result_t XUD_DoGetRequest(XUD_ep ep_out, XUD_ep ep_in, unsigned char buffer[], unsigned length, unsigned requested) @@ -93,20 +39,20 @@ XUD_Result_t XUD_DoGetRequest(XUD_ep ep_out, XUD_ep ep_in, unsigned char buffer[ unsigned sendLength = min(length, requested); XUD_Result_t result; - if ((result = XUD_SetBuffer_EpMax(ep_in, buffer, sendLength, 64)) != XUD_RES_OKAY) + if ((result = XUD_SetBuffer_EpMax(ep_in, buffer, sendLength, EP0_MAX_PACKET_SIZE)) != XUD_RES_OKAY) { return result; } /* USB 2.0 8.5.3.2: Send < 0 length packet when data-length % 64 is 0 * Note, we also don't want to try and send 2 zero-length packets i.e. if sendLength = 0 */ - if ((requested > length) && ((length % 64) == 0)) + if ((requested > length) && ((length % EP0_MAX_PACKET_SIZE) == 0)) { XUD_SetBuffer(ep_in, tmpBuffer, 0); } /* Status stage - this should return -1 for reset or 0 for 0 length status stage packet */ - return XUD_GetData(ep_out, tmpBuffer, rxlength); + return XUD_GetBuffer(ep_out, tmpBuffer, rxlength); } XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in) @@ -114,27 +60,39 @@ XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in) unsigned char tmp[8]; /* Send 0 length packet */ - return XUD_SetData(ep_in, tmp, 0, 0, 0); + return XUD_SetBuffer(ep_in, tmp, 0); } void XUD_SetStall(XUD_ep ep) { - /* Get EP address from XUD_ep structure */ - unsigned int epAddress; + asm volatile ("stw %0, %1[10]"::"r"(USB_PIDn_STALL), "r"(ep)); +} - asm ("ldw %0, %1[8]":"=r"(epAddress):"r"(ep)); +extern XUD_ep_info ep_info[USB_MAX_NUM_EP]; - XUD_SetStallByAddr(epAddress); +unsafe +{ + XUD_ep_info * unsafe ep_info_ = ep_info; } void XUD_ClearStall(XUD_ep ep) { - /* Get EP address from XUD_ep structure */ - unsigned int epAddress; + // Load EP addr and check for IN or OUT + unsigned epAddr; - asm ("ldw %0, %1[8]":"=r"(epAddress):"r"(ep)); - - XUD_ClearStallByAddr(epAddress); + asm volatile("ldw %0, %1[8]":"=r"(epAddr):"r"(ep)); + + if(epAddr & 0x80) + { + asm volatile ("stw %0, %1[10]"::"r"(0), "r"(ep)); + } + else + { + asm volatile ("stw %0, %1[10]"::"r"(USB_PIDn_NAK), "r"(ep)); + } + + /* Reset data PID */ + XUD_ResetEpStateByAddr(epAddr); } void XUD_CloseEndpoint(XUD_ep one) diff --git a/tests/README.rst b/tests/README.rst index 969a35b6..5256de8c 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -2,11 +2,29 @@ Lib_xud Tests ============= +Set up envirnment +................. + +In infr_scripts_pl, run: +``source ./SetupEnv`` + +In test_support, run: +``./Build.pl build install`` + + Installation and prerequiste for running pytest -pip install pytest +............................................... + +``pip install pytest`` + +To run all tests: + +``pytest -n 4 --enabletracing --xcov [test level]`` + +test level: smoke < default < extended + +To run specific test: -To run all tests, simply type: -pytest -s +``pytest -n 4 --enabletracing --xcov [test level] .py`` -To run specific test, type: -pytest .py +test level: smoke < default < extended diff --git a/tests/conftest.py b/tests/conftest.py index bec350c6..1394fb27 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,23 +3,33 @@ from pathlib import Path import os import shutil +import time import sys +import re +from filelock import FileLock import pytest from helpers import get_usb_clk_phy, do_usb_test import Pyxsim +from xcoverage.xcov import xcov_process, xcov_combine, combine_process # Note, no current support for XS2 so don't copy XS2 xn files -XN_FILES = ["test_xs3_600.xn", "test_xs3_800.xn", "test_xs3_540.xn", "test_xs3_500.xn"] - +XN_FILES = [ + "test_xs3_600.xn", + "test_xs3_800.xn", +] +combine_test = combine_process(os.path.dirname(os.path.abspath(__file__))) +xcov_comb = xcov_combine() + +# Note, HS tests will be skipped unless 85MIPS are available to lib_xud PARAMS = { "extended": { "arch": ["xs3"], "ep": [1, 2, 4], "address": [0, 1, 127], "bus_speed": ["HS", "FS"], - "dummy_threads": [0, 5, 6], + "dummy_threads": [0, 3, 5], # Note, plus 2 for test cores "core_freq": [600, 800], }, "default": { @@ -27,15 +37,15 @@ "ep": [1, 2], "address": [0, 1], "bus_speed": ["HS", "FS"], - "dummy_threads": [0, 6], + "dummy_threads": [0, 5], # Note, plus 2 for test cores "core_freq": [600], }, "smoke": { "arch": ["xs3"], "ep": [1], "address": [1], - "bus_speed": ["HS"], - "dummy_threads": [6], + "bus_speed": ["HS", "FS"], + "dummy_threads": [5], # Note, plus 2 for test cores "core_freq": [600], }, } @@ -44,6 +54,18 @@ def pytest_addoption(parser): parser.addoption("--smoke", action="store_true", help="Smoke test") parser.addoption("--extended", action="store_true", help="Extended test") + parser.addoption( + "--clean", + action="store_true", + default=False, + help="clean build file", + ) + parser.addoption( + "--xcov", + action="store_true", + default=False, + help="Enable xcov", + ) parser.addoption( "--enabletracing", action="store_true", @@ -54,17 +76,23 @@ def pytest_addoption(parser): def pytest_configure(config): os.environ["enabletracing"] = str(config.getoption("enabletracing")) + os.environ["xcov"] = str(config.getoption("xcov")) + os.environ["clean"] = str(config.getoption("clean")) def pytest_generate_tests(metafunc): try: PARAMS = metafunc.module.PARAMS # noqa F401 - if metafunc.config.getoption("smoke"): + if metafunc.config.getoption("clean"): + params = PARAMS.get("extended", PARAMS["default"]) + elif metafunc.config.getoption("smoke"): params = PARAMS.get("smoke", PARAMS["default"]) elif metafunc.config.getoption("extended"): params = PARAMS.get("extended", PARAMS["default"]) else: params = PARAMS["default"] + if metafunc.config.getoption("xcov"): + os.environ["enabletracing"] = "True" except AttributeError: params = {} @@ -93,7 +121,7 @@ def test_arch(arch: str) -> str: return arch -@pytest.fixture +@pytest.fixture() def test_file(request): return str(request.node.fspath) @@ -115,11 +143,17 @@ def test_RunUsbSession( capfd, ): + xcov = eval(os.getenv("xcov")) + + total_threads = dummy_threads + 2 # 1 thread for xud another for test code + if (core_freq / total_threads < 85.0) and bus_speed == "HS": + pytest.skip("HS requires 85 MIPS") + tester_list = [] output = [] # TODO it would be good to sanity check core_freq == xe.freq - (clk_60, usb_phy) = get_usb_clk_phy(core_freq, verbose=False, arch=arch) + (clk_60, usb_phy) = get_usb_clk_phy(verbose=False, arch=arch) tester_list.extend( do_usb_test( arch, @@ -134,18 +168,37 @@ def test_RunUsbSession( test_file, ) ) - cap_output, err = capfd.readouterr() - output.append(cap_output.split("\n")) - sys.stdout.write("\n") - results = Pyxsim.run_tester(output, tester_list) - - # TODO only one result - for result in results: - if not result: - print(cap_output) - sys.stderr.write(err) - assert result + testname, _ = os.path.splitext(os.path.basename(test_file)) + desc = f"{arch}_{core_freq}_{dummy_threads}_{ep}_{address}_{bus_speed}" + disasm = f"{testname}/bin/{desc}/{testname}_{desc}.dump" + trace = f"logs/xsim_trace_{testname}_{desc}.txt" + xcov_dir = f"{testname}/bin/{desc}" + + if not eval(os.getenv("clean")): + cap_output, err = capfd.readouterr() + output.append(cap_output.split("\n")) + + sys.stdout.write("\n") + results = Pyxsim.run_tester(output, tester_list) + + # TODO only one result + for result in results: + if not result: + print(cap_output) + sys.stderr.write(err) + else: + if eval(os.getenv("xcov")): + # calculate code coverage for each tests + coverage = xcov_process(disasm, trace, xcov_dir) + # generate coverage file for each source code included + xcov_comb.run_combine(xcov_dir) + # delete trace file and disasm file + if os.path.exists(trace): + os.remove(trace) + assert result + else: + pass def copy_common_xn_files( @@ -173,8 +226,8 @@ def delete_test_specific_xn_files(test_dir, source_dir="src", xn_files=XN_FILES) @pytest.fixture(scope="session", autouse=True) def worker_id(request): - if hasattr(request.config, "slaveinput"): - return request.config.slaveinput["slaveid"] + if hasattr(request.config, "workerinput"): + return request.config.workerinput["workerid"] # Master means not executing with multiple workers return "master" @@ -185,20 +238,21 @@ def worker_id(request): def copy_xn_files(worker_id, request): # Attempt to only run copy/delete once.. - if worker_id in ("master", "gw0"): - + if worker_id: session = request.node - + combine_test.remove_tmp_testresult(combine_test.tpath) # There will be duplicates (same test name with different params) sos # treat as set + global test_dirs test_dirs = set([]) - + # test_dir_list = [] # Go through collected tests and copy over XN files for item in session.items: full_path = item.fspath test_dir = Path(full_path).with_suffix("") # Strip suffix test_dir = os.path.basename(test_dir) # Strip path leaving filename test_dirs.add(test_dir) + # test_dir_list.append(test_dir) for test_dir in test_dirs: copy_common_xn_files(test_dir) @@ -215,3 +269,45 @@ def copy_xn_files(worker_id, request): # Setup tear down # Deletion removed for now - doesn't seem important # request.addfinalizer(delete_xn_files) + + +@pytest.fixture(scope="session", autouse=True) +def xcoverage_combination(tmp_path_factory, worker_id, request): + if eval(os.getenv("xcov")): + # run xcoverage combine test at the end of pytest + root_tmp_dir = tmp_path_factory.getbasetemp().parent + + fn = root_tmp_dir / "data.json" + + def follow(nfile, n): + nf = open(nfile, "r") + lines = len(nf.readlines()) + while lines != n: + nf.close() + nf = open(nfile, "r") + lines = len(nf.readlines()) + time.sleep(0.5) + + def run_at_end(): + wkc = os.getenv("PYTEST_XDIST_WORKER_COUNT") + if wkc: + follow(fn, int(wkc)) + coverage = combine_test.do_combine_test(test_dirs) + combine_test.generate_merge_src() + # teardowm - remove tmp file + combine_test.remove_tmp_testresult(combine_test.tpath) + + def status(): + f = open(fn, "a") + f.write(str(worker_id + "\n")) + + if worker_id == "master": + request.addfinalizer(run_at_end) + return + + with FileLock(str(fn) + ".lock"): + if fn.is_file(): + request.addfinalizer(status) + else: + fn.write_text(str(worker_id) + "\n") + request.addfinalizer(run_at_end) diff --git a/tests/helpers.py b/tests/helpers.py index f67256d0..43ac65c5 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -8,11 +8,9 @@ from usb_clock import Clock from usb_phy_utmi import UsbPhyUtmi import Pyxsim +import subprocess -ARCHITECTURE_CHOICES = ["xs2", "xs3"] -BUSSPEED_CHOICES = ["FS", "HS"] args = {"arch": "xs3"} -clean_only = False def create_if_needed(folder): @@ -22,16 +20,15 @@ def create_if_needed(folder): def get_usb_clk_phy( - coreFreqMhz, verbose=True, do_timeout=True, complete_fn=None, - dut_exit_time=350000, + dut_exit_time=350000 * 1000 * 1000, # in fs arch="xs2", ): if arch == "xs2": - clk = Clock("XS1_USB_CLK", Clock.CLK_60MHz, coreFreqMhz) + clk = Clock("XS1_USB_CLK", Clock.CLK_60MHz) phy = UsbPhyUtmi( "XS1_USB_RXD", "XS1_USB_RXA", # rxa @@ -51,7 +48,7 @@ def get_usb_clk_phy( ) elif arch == "xs3": - clk = Clock("XS1_USB_CLK", Clock.CLK_60MHz, coreFreqMhz) + clk = Clock("XS1_USB_CLK", Clock.CLK_60MHz) phy = UsbPhyUtmi( "XS1_USB_RXD", "XS1_USB_RXA", # rxa @@ -93,6 +90,19 @@ def run_on(**kwargs): return True +def generate_elf_disasm(binary, split_dir, disasm): + cmd_elf = ( + "xobjdump --split " + binary + " --split-dir " + split_dir + " > /dev/null 2>&1" + ) + cmd_disasm = "xobjdump -S " + binary + " -o " + disasm + try: + subprocess.run(cmd_elf, shell=True, check=True) + subprocess.run(cmd_disasm, shell=True, check=True) + except: + print("Error running build disasm") + sys.exit(1) + + FIXTURE_TO_DEFINE = { "core_freq": "TEST_FREQ", "arch": "TEST_ARCH", @@ -119,6 +129,8 @@ def do_usb_test( ): build_options = [] + xcov = eval(os.getenv("xcov")) + # Flags for makefile for k, v in FIXTURE_TO_DEFINE.items(): build_options += [str(v) + "=" + str(locals()[k])] @@ -140,12 +152,23 @@ def do_usb_test( # Do not need to clean since different build will different params go to # separate binaries + if eval(os.getenv("clean")): + clean_only = True + else: + clean_only = False + build_success, _ = Pyxsim._build( - binary, do_clean=False, build_options=build_options + binary, do_clean=False, clean_only=clean_only, build_options=build_options ) assert len(sessions) == 1, "Multiple sessions not yet supported" if build_success: + + if eval(os.getenv("xcov")): + split_dir = f"{testname}/bin/{desc}/" + disasm = f"{testname}/bin/{desc}/{testname}_{desc}.dump" + generate_elf_disasm(binary, split_dir, disasm) + for session in sessions: phy.session = session @@ -169,7 +192,7 @@ def do_usb_test( ) tester_list.append(tester) - simargs = get_sim_args(testname, clk, arch) + simargs = get_sim_args(testname, desc) simthreads = [clk, phy] + extra_tasks run_on_simulator(binary, simthreads, simargs=simargs) else: @@ -205,17 +228,16 @@ def create_expect(session, filename, verbose=False): print("Test done\n") -def get_sim_args(testname, clk, arch="xs2"): +def get_sim_args(testname, desc): sim_args = [] if eval(os.getenv("enabletracing")): log_folder = create_if_needed("logs") - filename = "{log}/xsim_trace_{test}_{clk}_{arch}".format( + filename = "{log}/xsim_trace_{test}_{desc}".format( log=log_folder, test=testname, - clk=clk.get_name(), - arch=arch, + desc=desc, ) sim_args += [ diff --git a/tests/shared_src/shared.h b/tests/shared_src/shared.h index eda08a01..cd2cdc39 100644 --- a/tests/shared_src/shared.h +++ b/tests/shared_src/shared.h @@ -84,17 +84,22 @@ typedef enum t_runMode RUNMODE_DIE } t_runMode; - #pragma unsafe arrays -XUD_Result_t SendTxPacket(XUD_ep ep, int length, int epNum) +void GenTxPacketBuffer(unsigned char buffer[], int length, int epNum) { - unsigned char buffer[1024]; - - for (int i = 0; i < length; i++) unsafe { buffer[i] = g_txDataCheck[epNum]++; } + return; +} + +#pragma unsafe arrays +XUD_Result_t SendTxPacket(XUD_ep ep, int length, int epNum) +{ + unsigned char buffer[1024]; + + GenTxPacketBuffer(buffer, length, epNum); return XUD_SetBuffer(ep, buffer, length); } diff --git a/tests/shared_src/test_control_basic_get.xc b/tests/shared_src/test_control_basic_get.xc new file mode 100644 index 00000000..1ce1e297 --- /dev/null +++ b/tests/shared_src/test_control_basic_get.xc @@ -0,0 +1,70 @@ +// Copyright 2016-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* Endpoint type tables */ +XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, + XUD_EPTYPE_BUL, + XUD_EPTYPE_BUL, + XUD_EPTYPE_BUL, + XUD_EPTYPE_BUL}; +XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; + + +int TestEp_Control(XUD_ep ep0_out, XUD_ep ep0_in, int epNum) +{ + unsigned int slength; + unsigned int length; + XUD_Result_t sres; + XUD_Result_t res; + + /* Buffer for Setup data */ + unsigned char sbuffer[120]; + unsigned char buffer[120]; + + for(int i = PKT_LENGTH_START; i <= PKT_LENGTH_END; i++) + { + unsafe + { + GenTxPacketBuffer(buffer, i, epNum); + + /* Wait for Setup data */ + sres = XUD_GetSetupBuffer(ep0_out, sbuffer, slength); + + res = XUD_DoGetRequest(ep0_out, ep0_in, buffer, i, i); + + /* Do some checking */ + if(slength != 8) + { + return FAIL_RX_DATAERROR; + } + + if(res != XUD_RES_OKAY) + { + return FAIL_RX_BAD_RETURN_CODE; + } + + if(sres != XUD_RES_OKAY) + { + return FAIL_RX_BAD_RETURN_CODE; + } + + if(RxDataCheck(sbuffer, slength, epNum, 8)) + { + return FAIL_RX_DATAERROR; + } + + } + } + return 0; +} + +unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) +{ + XUD_ep c_ep0_out = XUD_InitEp(c_ep_out[0]); + XUD_ep c_ep0_in = XUD_InitEp(c_ep_in[0]); + + unsigned failed = TestEp_Control(c_ep0_out, c_ep0_in, 0); + + XUD_Kill(c_ep0_out); + return failed; +} diff --git a/tests/shared_src/test_xs3_700.xn b/tests/shared_src/test_xs3_700.xn new file mode 100644 index 00000000..afd525af --- /dev/null +++ b/tests/shared_src/test_xs3_700.xn @@ -0,0 +1,24 @@ + + + + tileref tile[2] + + + + + + + + + + + + + + + + + + diff --git a/tests/test_bulk_loopback.py b/tests/test_bulk_loopback.py index 49d60fef..c0cddb5f 100644 --- a/tests/test_bulk_loopback.py +++ b/tests/test_bulk_loopback.py @@ -35,7 +35,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -45,7 +45,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, ) ) @@ -59,7 +59,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback_kill, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -69,7 +69,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback_kill, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_notready.py b/tests/test_bulk_notready.py index f95d8ee8..668360ae 100644 --- a/tests/test_bulk_notready.py +++ b/tests/test_bulk_notready.py @@ -10,9 +10,6 @@ @pytest.fixture def test_session(ep, address, bus_speed): - if bus_speed == "FS": - pytest.xfail("Known fail when bus_speed = FS") - pktLength = 10 ied = 500 @@ -26,7 +23,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_rx_basic.py b/tests/test_bulk_rx_basic.py index 6a783410..431dbdeb 100644 --- a/tests/test_bulk_rx_basic.py +++ b/tests/test_bulk_rx_basic.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_rx_basic_badcrc32.py b/tests/test_bulk_rx_basic_badcrc32.py index 940c51d8..bde1b80f 100644 --- a/tests/test_bulk_rx_basic_badcrc32.py +++ b/tests/test_bulk_rx_basic_badcrc32.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) @@ -36,7 +36,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=6000, ) @@ -49,7 +49,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=12, interEventDelay=6000, badDataCrc=True, @@ -64,7 +64,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=12, interEventDelay=6000, ) @@ -77,7 +77,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=13, interEventDelay=6000, ) @@ -89,7 +89,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=14, interEventDelay=6000, ) diff --git a/tests/test_bulk_rx_basic_badpid.py b/tests/test_bulk_rx_basic_badpidseq.py similarity index 93% rename from tests/test_bulk_rx_basic_badpid.py rename to tests/test_bulk_rx_basic_badpidseq.py index 833a72e4..5500646a 100644 --- a/tests/test_bulk_rx_basic_badpid.py +++ b/tests/test_bulk_rx_basic_badpidseq.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, interEventDelay=interEventDelay, ) @@ -38,7 +38,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=interEventDelay, resend=True, @@ -52,7 +52,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=12, interEventDelay=interEventDelay, ) @@ -63,7 +63,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=13, interEventDelay=interEventDelay, ) @@ -74,7 +74,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=14, interEventDelay=interEventDelay, ) diff --git a/tests/test_bulk_rx_basic_badpid/Makefile b/tests/test_bulk_rx_basic_badpidseq/Makefile similarity index 100% rename from tests/test_bulk_rx_basic_badpid/Makefile rename to tests/test_bulk_rx_basic_badpidseq/Makefile diff --git a/tests/test_bulk_rx_basic_badpid/src/main.xc b/tests/test_bulk_rx_basic_badpidseq/src/main.xc similarity index 100% rename from tests/test_bulk_rx_basic_badpid/src/main.xc rename to tests/test_bulk_rx_basic_badpidseq/src/main.xc diff --git a/tests/test_bulk_rx_basic_invalidpid.py b/tests/test_bulk_rx_basic_invalidpid.py new file mode 100644 index 00000000..bcf758a2 --- /dev/null +++ b/tests/test_bulk_rx_basic_invalidpid.py @@ -0,0 +1,90 @@ +# Copyright 2016-2021 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +import pytest + +from conftest import PARAMS, test_RunUsbSession # noqa F401 +from usb_session import UsbSession +from usb_transaction import UsbTransaction +from usb_packet import ( + TokenPacket, + TxDataPacket, + USB_PID, +) + + +@pytest.fixture +def test_session(ep, address, bus_speed): + + session = UsbSession( + bus_speed=bus_speed, run_enumeration=False, device_address=address + ) + + # The large inter-frame gap is to give the DUT time to print its output + interEventDelay = 500 + + # Valid OUT transaction + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=10, + interEventDelay=interEventDelay, + ) + ) + + # OUT Transaction with invalid DATA PID. XCORE should ignore packet - no ACK + session.add_event( + TokenPacket( + pid=USB_PID["OUT"], + address=address, + endpoint=ep, + interEventDelay=interEventDelay, + ) + ) + + session.add_event( + TxDataPacket( + dataPayload=session.getPayload_out(ep, 11, resend=True), + pid=USB_PID["DATA1"] & 0xF, + ) + ) + + # Send some valid OUT transactions + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=11, + interEventDelay=interEventDelay, + ) + ) + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=12, + interEventDelay=interEventDelay, + ) + ) + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=13, + interEventDelay=interEventDelay, + ) + ) + + return session diff --git a/tests/test_stall_epready/Makefile b/tests/test_bulk_rx_basic_invalidpid/Makefile similarity index 100% rename from tests/test_stall_epready/Makefile rename to tests/test_bulk_rx_basic_invalidpid/Makefile diff --git a/tests/test_bulk_rx_basic_invalidpid/src/main.xc b/tests/test_bulk_rx_basic_invalidpid/src/main.xc new file mode 100644 index 00000000..731d385c --- /dev/null +++ b/tests/test_bulk_rx_basic_invalidpid/src/main.xc @@ -0,0 +1,29 @@ +// Copyright 2016-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include "shared.h" + +#define EP_COUNT_OUT (6) +#define EP_COUNT_IN (6) + +#ifndef PKT_LENGTH_START +#define PKT_LENGTH_START (10) +#endif + +#ifndef PKT_LENGTH_END +#define PKT_LENGTH_END (13) +#endif + +#include "shared.h" + +XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; +XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; + +unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) +{ + unsigned fail = TestEp_Rx(c_ep_out[TEST_EP_NUM], TEST_EP_NUM, PKT_LENGTH_START, PKT_LENGTH_END); + + return fail; +} + +#include "test_main.xc" + diff --git a/tests/test_bulk_rx_basic_nodata.py b/tests/test_bulk_rx_basic_nodata.py index d92c670a..eb5275ba 100644 --- a/tests/test_bulk_rx_basic_nodata.py +++ b/tests/test_bulk_rx_basic_nodata.py @@ -11,7 +11,11 @@ @pytest.fixture -def test_session(ep, address, bus_speed): +def test_session(ep, address, bus_speed, core_freq, dummy_threads): + + total_threads = dummy_threads + 2 # 1 thread for xud another for test code + if (core_freq / total_threads < 100.0) and bus_speed == "HS": + pytest.xfail("Test doesn't pass without 100MIPS (issue #277)") # The large inter-event delay is to give the DUT time to perform checking ied = 500 @@ -28,7 +32,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=length, interEventDelay=ied, ) diff --git a/tests/test_bulk_rx_basic_rxerror.py b/tests/test_bulk_rx_basic_rxerror.py index 7e27cdaa..97167cb2 100644 --- a/tests/test_bulk_rx_basic_rxerror.py +++ b/tests/test_bulk_rx_basic_rxerror.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) @@ -37,7 +37,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=ied, rxeAssertDelay_data=5, @@ -51,7 +51,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=ied, ) @@ -64,7 +64,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=12, interEventDelay=ied, ) @@ -76,7 +76,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=13, interEventDelay=ied, rxeAssertDelay_data=1, @@ -90,7 +90,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=13, interEventDelay=ied, ) @@ -102,7 +102,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=14, interEventDelay=ied, ) diff --git a/tests/test_bulk_rx_multiep.py b/tests/test_bulk_rx_multiep.py index a303db30..7127e110 100644 --- a/tests/test_bulk_rx_multiep.py +++ b/tests/test_bulk_rx_multiep.py @@ -29,7 +29,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -39,7 +39,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=4, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -49,7 +49,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=5, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -59,7 +59,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=6, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_rx_traffic.py b/tests/test_bulk_rx_traffic.py index 733a892e..d413169b 100644 --- a/tests/test_bulk_rx_traffic.py +++ b/tests/test_bulk_rx_traffic.py @@ -30,7 +30,7 @@ def test_session(ep, address, bus_speed): deviceAddress=trafficAddress1, endpointNumber=trafficEp1, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=ied, ) @@ -42,7 +42,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=ied, ) @@ -54,7 +54,7 @@ def test_session(ep, address, bus_speed): deviceAddress=trafficAddress2, endpointNumber=trafficEp2, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=ied, ) diff --git a/tests/test_bulk_tx_badack.py b/tests/test_bulk_tx_badack.py index ff360d59..e262d292 100644 --- a/tests/test_bulk_tx_badack.py +++ b/tests/test_bulk_tx_badack.py @@ -43,7 +43,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) diff --git a/tests/test_bulk_tx_basic.py b/tests/test_bulk_tx_basic.py index f967784a..9da26eaf 100644 --- a/tests/test_bulk_tx_basic.py +++ b/tests/test_bulk_tx_basic.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_tx_basic_noack.py b/tests/test_bulk_tx_basic_noack.py index fbb548e5..9c99b3d2 100644 --- a/tests/test_bulk_tx_basic_noack.py +++ b/tests/test_bulk_tx_basic_noack.py @@ -42,7 +42,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) diff --git a/tests/test_bulk_tx_basic_short.py b/tests/test_bulk_tx_basic_short.py index fb1e878e..2acb9f93 100644 --- a/tests/test_bulk_tx_basic_short.py +++ b/tests/test_bulk_tx_basic_short.py @@ -24,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, ) ) diff --git a/tests/test_bulk_tx_multiep.py b/tests/test_bulk_tx_multiep.py index 73a57fee..c1b298ec 100644 --- a/tests/test_bulk_tx_multiep.py +++ b/tests/test_bulk_tx_multiep.py @@ -30,7 +30,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) @@ -41,7 +41,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep + 1, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) @@ -52,7 +52,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep + 2, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) @@ -63,7 +63,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep + 3, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=ied, ) diff --git a/tests/test_control_basic_get.py b/tests/test_control_basic_get.py index 220df7e8..46c649ef 100644 --- a/tests/test_control_basic_get.py +++ b/tests/test_control_basic_get.py @@ -14,6 +14,7 @@ USB_PID, ) from usb_session import UsbSession +from usb_transaction import UsbTransaction # Only test on EP 0 - Update params PARAMS = deepcopy(PARAMS) @@ -24,56 +25,46 @@ @pytest.fixture def test_session(ep, address, bus_speed): - ied = 500 + start_length = 0 + end_length = start_length + 10 session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) - # SETUP transaction - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, - ) - ) - session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], - ) - ) - session.add_event(RxHandshakePacket()) + for pktLength in range(start_length, end_length): - # IN transaction - # Note, quite big gap to avoid nak - session.add_event( - TokenPacket( - pid=USB_PID["IN"], - address=address, - endpoint=ep, - interEventDelay=10000, + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, + ) ) - ) - session.add_event( - RxDataPacket( - dataPayload=session.getPayload_in(ep, 10), - pid=USB_PID["DATA1"], + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="IN", + dataLength=pktLength, + ) ) - ) - session.add_event(TxHandshakePacket()) - # Send 0 length OUT transaction - session.add_event( - TokenPacket( - pid=USB_PID["OUT"], - address=address, - endpoint=ep, - interEventDelay=ied, + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="OUT", + dataLength=0, + ) ) - ) - session.add_event(TxDataPacket(length=0, pid=USB_PID["DATA1"])) - session.add_event(RxHandshakePacket()) return session diff --git a/tests/test_control_basic_get/src/main.xc b/tests/test_control_basic_get/src/main.xc index e5657420..b880a8fd 100644 --- a/tests/test_control_basic_get/src/main.xc +++ b/tests/test_control_basic_get/src/main.xc @@ -2,67 +2,18 @@ // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include "shared.h" -#define EP_COUNT_OUT (5) -#define EP_COUNT_IN (5) +#define EP_COUNT_OUT (5) +#define EP_COUNT_IN (5) -/* Endpoint type tables */ -XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, - XUD_EPTYPE_BUL, - XUD_EPTYPE_BUL, - XUD_EPTYPE_BUL, - XUD_EPTYPE_BUL}; -XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; +#ifndef PKT_LENGTH_START +#define PKT_LENGTH_START (0) +#endif +#ifndef PKT_LENGTH_END +#define PKT_LENGTH_END (9) +#endif -int TestEp_Control(XUD_ep c_ep0_out, XUD_ep c_ep0_in, int epNum) -{ - unsigned int slength; - unsigned int length; - XUD_Result_t sres; - XUD_Result_t res; +#include "test_control_basic_get.xc" - /* Buffer for Setup data */ - unsigned char sbuffer[120]; - unsigned char buffer[120]; - - unsafe - { - /* Wait for Setup data */ - sres = XUD_GetSetupBuffer(c_ep0_out, sbuffer, slength); - - res = SendTxPacket(c_ep0_in, 10, epNum); - - res = XUD_GetBuffer(c_ep0_out, buffer, length); - - if(length != 0) - { - return FAIL_RX_DATAERROR; - } - - /* Do some checking */ - if(res != XUD_RES_OKAY) - { - return FAIL_RX_BAD_RETURN_CODE; - } - - if(RxDataCheck(sbuffer, slength, epNum, 8)) - { - return FAIL_RX_DATAERROR; - } - - return 0; - } -} - -unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) -{ - XUD_ep c_ep0_out = XUD_InitEp(c_ep_out[0]); - XUD_ep c_ep0_in = XUD_InitEp(c_ep_in[0]); - - unsigned failed = TestEp_Control(c_ep0_out, c_ep0_in, 0); - - XUD_Kill(c_ep0_out); - return failed; -} #include "test_main.xc" diff --git a/tests/test_control_basic_get_epmax.py b/tests/test_control_basic_get_epmax.py new file mode 100644 index 00000000..fb59b90f --- /dev/null +++ b/tests/test_control_basic_get_epmax.py @@ -0,0 +1,85 @@ +# Copyright 2016-2021 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. +from copy import deepcopy + +import pytest + +from conftest import PARAMS, test_RunUsbSession # noqa F401 +from usb_packet import ( + TokenPacket, + TxDataPacket, + RxDataPacket, + TxHandshakePacket, + RxHandshakePacket, + USB_PID, +) +from usb_session import UsbSession +from usb_transaction import UsbTransaction + +# Only test on EP 0 - Update params +PARAMS = deepcopy(PARAMS) +for k in PARAMS: + PARAMS[k].update({"ep": [0]}) + + +@pytest.fixture +def test_session(ep, address, bus_speed): + + # Note, EP0_MAX_PACKET_SIZE set to 8 in test to speed things up + maxPktLength = 8 + + startLength = 8 + endLength = 20 + + session = UsbSession( + bus_speed=bus_speed, run_enumeration=False, device_address=address + ) + + for dataLength in range(startLength, endLength + 1): + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, + interEventDelay=1000, # Large delay to allow for packet generation + ) + ) + + thisDataLength = dataLength + + while thisDataLength > 0: + + pktLength = maxPktLength + + if thisDataLength < maxPktLength: + pktLength = thisDataLength + + thisDataLength = thisDataLength - pktLength + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="IN", + dataLength=pktLength, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="OUT", + dataLength=0, + ) + ) + + return session diff --git a/tests/test_control_basic_get_epmax/Makefile b/tests/test_control_basic_get_epmax/Makefile new file mode 100644 index 00000000..0cfecb60 --- /dev/null +++ b/tests/test_control_basic_get_epmax/Makefile @@ -0,0 +1,3 @@ +TEST_FLAGS = -DXUD_BYPASS_RESET=1 -DEP0_MAX_PACKET_SIZE=8 + +include ../test_makefile.mak diff --git a/tests/test_control_basic_get_epmax/src/main.xc b/tests/test_control_basic_get_epmax/src/main.xc new file mode 100644 index 00000000..1c6c9a5b --- /dev/null +++ b/tests/test_control_basic_get_epmax/src/main.xc @@ -0,0 +1,19 @@ +// Copyright 2016-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include "shared.h" + +#define EP_COUNT_OUT (5) +#define EP_COUNT_IN (5) + +#ifndef PKT_LENGTH_START +#define PKT_LENGTH_START (8) +#endif + +#ifndef PKT_LENGTH_END +#define PKT_LENGTH_END (20) +#endif + +#include "test_control_basic_get.xc" + +#include "test_main.xc" + diff --git a/tests/test_control_basic_set.py b/tests/test_control_basic_set.py index 231e0640..0ff0cff2 100644 --- a/tests/test_control_basic_set.py +++ b/tests/test_control_basic_set.py @@ -14,6 +14,7 @@ USB_PID, ) from usb_session import UsbSession +from usb_transaction import UsbTransaction # Only test on EP 0 - Update params PARAMS = deepcopy(PARAMS) @@ -26,57 +27,41 @@ def test_session(ep, address, bus_speed): ied = 500 - # if bus_speed == "HS" and dummy_threads > 4: - # pytest.xfail("Known fail when dummy threads > 4") - session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) - # SETUP transaction - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, - ) - ) session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, ) ) - session.add_event(RxHandshakePacket()) - # OUT transaction - # Note, quite big gap to avoid nak session.add_event( - TokenPacket( - pid=USB_PID["OUT"], - address=address, - endpoint=ep, - interEventDelay=10000, + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="OUT", + dataLength=10, ) ) - session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 10), - pid=USB_PID["DATA1"], - ) - ) - session.add_event(RxHandshakePacket()) # Expect 0 length IN transaction session.add_event( - TokenPacket( - pid=USB_PID["IN"], - address=address, - endpoint=ep, - interEventDelay=ied, + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="IN", + dataLength=0, ) ) - session.add_event(RxDataPacket(dataPayload=[], pid=USB_PID["DATA1"])) - session.add_event(TxHandshakePacket()) - return session diff --git a/tests/test_control_traffic.py b/tests/test_control_traffic.py index b062e589..6092d427 100644 --- a/tests/test_control_traffic.py +++ b/tests/test_control_traffic.py @@ -14,6 +14,7 @@ USB_PID, ) from usb_session import UsbSession +from usb_transaction import UsbTransaction # Only test on EP 0 - Update params PARAMS = deepcopy(PARAMS) @@ -29,93 +30,86 @@ def test_session(ep, address, bus_speed): trafficAddress1 = (address + 1) % 128 trafficAddress2 = (address + 127) % 128 + start_length = 0 + end_length = start_length + 10 + session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) - # SETUP to another address (Note, DUT would not see ACK) - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=trafficAddress1, - endpoint=ep, - ) - ) - session.add_event( - TxDataPacket( - dataPayload=[1, 2, 3, 4, 5, 6, 7, 8], - pid=USB_PID["DATA0"], - ) - ) + for pktLength in range(start_length, end_length): - # SETUP transaction to DUT - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, + # SETUP to another address (Note, DUT would not see ACK) + session.add_event( + TokenPacket( + pid=USB_PID["SETUP"], + address=trafficAddress1, + endpoint=ep, + ) ) - ) - session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], + session.add_event( + TxDataPacket( + dataPayload=[1, 2, 3, 4, 5, 6, 7, 8], + pid=USB_PID["DATA0"], + ) ) - ) - session.add_event(RxHandshakePacket()) - - # IN transaction - # Note, quite big gap to avoid nak - session.add_event( - TokenPacket( - pid=USB_PID["IN"], - address=address, - endpoint=ep, - interEventDelay=10000, + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, + ) ) - ) - session.add_event( - RxDataPacket( - dataPayload=session.getPayload_in(ep, 10), - pid=USB_PID["DATA1"], + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="IN", + dataLength=pktLength, + ) ) - ) - session.add_event(TxHandshakePacket()) - - # SETUP to another address (Note, DUT would not see ACK) - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=trafficAddress2, - endpoint=ep, + + # SETUP to another address (Note, DUT would not see ACK) + session.add_event( + TokenPacket( + pid=USB_PID["SETUP"], + address=trafficAddress2, + endpoint=ep, + ) ) - ) - session.add_event( - TxDataPacket( - dataPayload=[1, 2, 3, 4, 5, 6, 7, 8], - pid=USB_PID["DATA0"], + session.add_event( + TxDataPacket( + dataPayload=[1, 2, 3, 4, 5, 6, 7, 8], + pid=USB_PID["DATA0"], + ) ) - ) - session.add_event( - TokenPacket( - pid=USB_PID["IN"], - address=trafficAddress2, - endpoint=ep, - interEventDelay=1000, + session.add_event( + TokenPacket( + pid=USB_PID["IN"], + address=trafficAddress2, + endpoint=ep, + interEventDelay=1000, + ) ) - ) - # Send 0 length OUT transaction - session.add_event( - TokenPacket( - pid=USB_PID["OUT"], - address=address, - endpoint=ep, - interEventDelay=ied, + # Send 0 length OUT transaction + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="OUT", + dataLength=0, + ) ) - ) - session.add_event(TxDataPacket(length=0, pid=USB_PID["DATA1"])) - session.add_event(RxHandshakePacket()) return session diff --git a/tests/test_device_attach.py b/tests/test_device_attach.py index 78b26167..07ed4237 100644 --- a/tests/test_device_attach.py +++ b/tests/test_device_attach.py @@ -9,6 +9,7 @@ from usb_session import UsbSession from usb_transaction import UsbTransaction from usb_signalling import UsbDeviceAttach +from usb_phy import USB_PKT_TIMINGS # Only need to run device attach tests for one ep/address PARAMS = deepcopy(PARAMS) @@ -22,11 +23,13 @@ def test_session(ep, address, bus_speed): pktLength = 10 frameNumber = 52 # Note, for frame number 52 we expect A5 34 40 on the bus + interEventDelay = USB_PKT_TIMINGS["TX_TO_TX_PACKET_DELAY"] + session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address, - initial_delay=19000, + initial_delay=19000 * 1000 * 1000, # fs ) session.add_event(UsbDeviceAttach()) @@ -39,9 +42,9 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, - interEventDelay=0, + interEventDelay=interEventDelay, ) ) @@ -55,9 +58,9 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, - interEventDelay=0, + interEventDelay=interEventDelay, ) ) diff --git a/tests/test_invalidtoken.py b/tests/test_invalidtoken.py index 6d966a28..e5e22da2 100644 --- a/tests/test_invalidtoken.py +++ b/tests/test_invalidtoken.py @@ -51,7 +51,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) @@ -73,7 +73,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=6000, ) @@ -95,7 +95,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=12, interEventDelay=6000, ) @@ -106,7 +106,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=13, interEventDelay=6000, ) @@ -117,7 +117,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=14, interEventDelay=6000, ) diff --git a/tests/test_iso_loopback.py b/tests/test_iso_loopback.py index 284f65ae..bd6bf122 100644 --- a/tests/test_iso_loopback.py +++ b/tests/test_iso_loopback.py @@ -27,7 +27,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback, endpointType="ISO", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -42,7 +42,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback, endpointType="ISO", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=498, ) @@ -57,7 +57,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback_kill, endpointType="ISO", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -67,7 +67,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_loopback_kill, endpointType="ISO", - direction="IN", + transType="IN", dataLength=pktLength, ) ) diff --git a/tests/test_iso_rx_basic.py b/tests/test_iso_rx_basic.py index 90aac9ab..6b257844 100644 --- a/tests/test_iso_rx_basic.py +++ b/tests/test_iso_rx_basic.py @@ -11,21 +11,24 @@ def test_session(ep, address, bus_speed): start_length = 10 - end_length = start_length + 5 + end_length = start_length + 4 session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) - for pktLength in range(start_length, end_length): + interTransactionDelay = 500 + + for pktLength in range(start_length, end_length + 1): session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="ISO", - direction="OUT", + transType="OUT", dataLength=pktLength, + interEventDelay=interTransactionDelay, ) ) diff --git a/tests/test_iso_rxtx_fastpacket.py b/tests/test_iso_rxtx_fastpacket.py index 040c6886..187ed5d1 100644 --- a/tests/test_iso_rxtx_fastpacket.py +++ b/tests/test_iso_rxtx_fastpacket.py @@ -26,7 +26,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="ISO", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=20, ) @@ -38,7 +38,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="ISO", - direction="IN", + transType="IN", dataLength=pktLength, interEventDelay=58, ) diff --git a/tests/test_iso_tx_basic.py b/tests/test_iso_tx_basic.py index 7765f70b..3df1d131 100644 --- a/tests/test_iso_tx_basic.py +++ b/tests/test_iso_tx_basic.py @@ -14,10 +14,7 @@ def test_session(ep, address, bus_speed): end_length = start_length + 5 session = UsbSession( - bus_speed=bus_speed, - run_enumeration=False, - device_address=address, - initial_delay=100000, + bus_speed=bus_speed, run_enumeration=False, device_address=address ) for pktLength in range(start_length, end_length): @@ -27,7 +24,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="ISO", - direction="IN", + transType="IN", dataLength=pktLength, ) ) diff --git a/tests/test_makefile.mak b/tests/test_makefile.mak index 27658d3c..36fc9abe 100644 --- a/tests/test_makefile.mak +++ b/tests/test_makefile.mak @@ -16,10 +16,14 @@ SHARED_CODE = ../../shared_src COMMON_FLAGS = -DDEBUG_PRINT_ENABLE \ -O3 \ + -g \ -I$(SHARED_CODE) \ -DUSB_TILE=tile[0] \ -DXUD_SIM_XSIM=1 \ -DXUD_TEST_SPEED_HS=1 \ + -Xmapper --retain \ + -g \ + -save-temps \ $(CFLAGS) TEST_FLAGS ?= diff --git a/tests/test_ping_rx_basic.py b/tests/test_ping_rx_basic.py index 9f095699..2d2261ad 100644 --- a/tests/test_ping_rx_basic.py +++ b/tests/test_ping_rx_basic.py @@ -49,7 +49,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep + 1, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) @@ -83,7 +83,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, interEventDelay=6000, ) @@ -116,7 +116,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep + 1, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) diff --git a/tests/test_ping_stall.py b/tests/test_ping_stall.py index b3f9584e..b952e6ac 100644 --- a/tests/test_ping_stall.py +++ b/tests/test_ping_stall.py @@ -47,7 +47,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_ctrl, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -59,7 +59,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) @@ -70,7 +70,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) diff --git a/tests/test_sof_basic.py b/tests/test_sof_basic.py index b5ecb8b2..250a6a5a 100644 --- a/tests/test_sof_basic.py +++ b/tests/test_sof_basic.py @@ -6,6 +6,7 @@ from usb_session import UsbSession from usb_transaction import UsbTransaction from usb_packet import CreateSofToken +from usb_transaction import INTER_TRANSACTION_DELAY @pytest.fixture @@ -24,16 +25,26 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=10, ) ) - session.add_event(CreateSofToken(frameNumber)) - session.add_event(CreateSofToken(frameNumber + 1)) - session.add_event(CreateSofToken(frameNumber + 2)) - session.add_event(CreateSofToken(frameNumber + 3)) - session.add_event(CreateSofToken(frameNumber + 4)) + session.add_event( + CreateSofToken(frameNumber, interEventDelay=INTER_TRANSACTION_DELAY) + ) + session.add_event( + CreateSofToken(frameNumber + 1, interEventDelay=INTER_TRANSACTION_DELAY) + ) + session.add_event( + CreateSofToken(frameNumber + 2, interEventDelay=INTER_TRANSACTION_DELAY) + ) + session.add_event( + CreateSofToken(frameNumber + 3, interEventDelay=INTER_TRANSACTION_DELAY) + ) + session.add_event( + CreateSofToken(frameNumber + 4, interEventDelay=INTER_TRANSACTION_DELAY) + ) # Finish with valid transaction session.add_event( @@ -42,7 +53,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=11, interEventDelay=6000, ) diff --git a/tests/test_stall_basic.py b/tests/test_stall_basic.py index a478f1bb..34f660b5 100644 --- a/tests/test_stall_basic.py +++ b/tests/test_stall_basic.py @@ -10,9 +10,6 @@ @pytest.fixture def test_session(ep, address, bus_speed): - if bus_speed == "FS": - pytest.xfail("Known failure at FS") - pktLength = 10 session = UsbSession( @@ -21,6 +18,29 @@ def test_session(ep, address, bus_speed): ep_ctrl = ep + 1 + # Valid transactions on test EP's + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + ) + ) + # Expect test EP's to be halted session.add_event( UsbTransaction( @@ -28,7 +48,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, halted=True, ) @@ -40,7 +60,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, halted=True, ) @@ -52,7 +72,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", halted=True, ) ) @@ -63,7 +83,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", halted=True, ) ) @@ -75,18 +95,19 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep_ctrl, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, ) ) + # Check EP no working as normal session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=1000, ) @@ -98,16 +119,68 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="IN", dataLength=pktLength, ) ) - return session + # EP now re-halted + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + halted=True, + ) + ) + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + halted=True, + ) + ) + + # Valid transaction to another EP informing test code to clear stall + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep_ctrl, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + ) + ) + + # Check EP now working as normal + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + ) + ) -# for result in RunUsbTest( -# gen_test_session, test_arch, test_ep, test_address, -# test_bus_speed, __file__ -# ): -# assert result + return session diff --git a/tests/test_stall_basic/src/main.xc b/tests/test_stall_basic/src/main.xc index 4283bfb6..1d2440c8 100644 --- a/tests/test_stall_basic/src/main.xc +++ b/tests/test_stall_basic/src/main.xc @@ -33,26 +33,39 @@ unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) { unsigned failed = 0; uint8_t outBuffer[128]; - uint8_t inBuffer[128]; + uint8_t inBuffer0[128]; + uint8_t inBuffer1[128]; + uint8_t inBuffer2[128]; unsigned length; XUD_Result_t result; - for(size_t i = 0; i < sizeof(outBuffer); i++) - inBuffer[i] = i; + for(size_t i = 0; i < PKT_LENGTH_START; i++) + { + inBuffer0[i] = i; + inBuffer1[i] = i + PKT_LENGTH_START; + inBuffer2[i] = i + PKT_LENGTH_START + PKT_LENGTH_START; + } - /* Stall EPs */ XUD_ep ep_out = XUD_InitEp(c_ep_out[TEST_EP_NUM]); - XUD_SetStall(ep_out); - XUD_ep ep_in = XUD_InitEp(c_ep_in[TEST_EP_NUM]); - XUD_SetStall(ep_in); - XUD_ep ep_ctrl = XUD_InitEp(c_ep_out[CTRL_EP_NUM]); + + /* Valid transaction on test OUT EP */ + /* This is somewhat important as this will toggle the expected PID - which should be reset on an un-stall */ + result = XUD_GetBuffer(ep_out, outBuffer, length); + failed = (result != XUD_RES_OKAY); + + result = XUD_SetBuffer(ep_in, inBuffer0, PKT_LENGTH_START); + failed |= (result != XUD_RES_OKAY); + + /* Stall test EPs */ + XUD_SetStall(ep_in); + XUD_SetStall(ep_out); /* Valid transaction on another EP, clear STALL on the test EP's */ result = XUD_GetBuffer(ep_ctrl, outBuffer, length); failed = (result != XUD_RES_OKAY); - + /* Clear stall on the test EP's */ XUD_ClearStall(ep_out); XUD_ClearStall(ep_in); @@ -61,7 +74,26 @@ unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) result = XUD_GetBuffer(ep_out, outBuffer, length); failed |= (result != XUD_RES_OKAY); - result = XUD_SetBuffer(ep_in, inBuffer, PKT_LENGTH_START); + result = XUD_SetBuffer(ep_in, inBuffer1, PKT_LENGTH_START); + failed |= (result != XUD_RES_OKAY); + + /* Stall both EP's using Addr */ + XUD_SetStallByAddr(TEST_EP_NUM); + XUD_SetStallByAddr(TEST_EP_NUM | 0x80); + + /* Valid transaction on another EP, clear STALL on the test EP's */ + result = XUD_GetBuffer(ep_ctrl, outBuffer, length); + failed = (result != XUD_RES_OKAY); + + /* Clear stall on both EPs using Addr */ + XUD_ClearStallByAddr(TEST_EP_NUM); + XUD_ClearStallByAddr(TEST_EP_NUM | 0x80); + + /* Ensure test EP's now operate as expected */ + result = XUD_GetBuffer(ep_out, outBuffer, length); + failed |= (result != XUD_RES_OKAY); + + result = XUD_SetBuffer(ep_in, inBuffer2, PKT_LENGTH_START); failed |= (result != XUD_RES_OKAY); return failed; diff --git a/tests/test_stall_control.py b/tests/test_stall_control.py index e8b5e310..b46a58f4 100644 --- a/tests/test_stall_control.py +++ b/tests/test_stall_control.py @@ -34,104 +34,78 @@ def test_session(ep, address, bus_speed): ) # Ctrl transaction 0 - - # SETUP transaction - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, - ) - ) session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, ) ) - session.add_event(RxHandshakePacket()) - # OUT transaction - # Note, quite big gap to avoid nak - session.add_event( - TokenPacket( - pid=USB_PID["OUT"], - address=address, - endpoint=ep, - interEventDelay=10000, - ) - ) session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 10), - pid=USB_PID["DATA1"], + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="OUT", + dataLength=10, ) ) - session.add_event(RxHandshakePacket()) # Expect 0 length IN transaction session.add_event( - TokenPacket( - pid=USB_PID["IN"], - address=address, - endpoint=ep, - interEventDelay=ied, + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="IN", + dataLength=0, ) ) - session.add_event(RxDataPacket(dataPayload=[], pid=USB_PID["DATA1"])) - session.add_event(TxHandshakePacket()) # Ctrl transaction 1 - - # SETUP transaction - session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, - interEventDelay=10000, - ) - ) session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, ) ) - session.add_event(RxHandshakePacket()) - # Check that the EP is now Halted + # Check that the EP is now Halted - i.e. as if the previous request could not be handled session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="CONTROL", - direction="IN", + transType="IN", dataLength=pktLength, halted=True, interEventDelay=1000, ) ) + # Check that EP is un-Halted on a SETUP # Ctrl transaction 2 - - # SETUP transaction session.add_event( - TokenPacket( - pid=USB_PID["SETUP"], - address=address, - endpoint=ep, - interEventDelay=10000, - ) - ) - session.add_event( - TxDataPacket( - dataPayload=session.getPayload_out(ep, 8), - pid=USB_PID["DATA0"], + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="CONTROL", + transType="SETUP", + dataLength=8, ) ) - session.add_event(RxHandshakePacket()) session.add_event( UsbTransaction( @@ -139,11 +113,8 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="CONTROL", - direction="IN", + transType="IN", dataLength=pktLength, - halted=False, - interEventDelay=1000, - resetDataPid=True, ) ) @@ -152,12 +123,9 @@ def test_session(ep, address, bus_speed): session, deviceAddress=address, endpointNumber=ep, - endpointType="BULK", - direction="OUT", + endpointType="CONTROL", + transType="OUT", dataLength=0, - halted=False, - interEventDelay=1000, - resetDataPid=True, ) ) diff --git a/tests/test_stall_epready/src/main.xc b/tests/test_stall_epready/src/main.xc deleted file mode 100644 index 384405c2..00000000 --- a/tests/test_stall_epready/src/main.xc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016-2021 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - - -#define EP_COUNT_OUT (6) -#define EP_COUNT_IN (6) - -#ifndef PKT_LENGTH_START -#define PKT_LENGTH_START (10) -#endif - -#ifndef TEST_EP_NUM -#define TEST_EP_NUM (1) -#endif - -#ifndef CTRL_EP_NUM -#define CTRL_EP_NUM (TEST_EP_NUM + 1) -#endif - -#include "shared.h" - -/* Endpoint type tables */ -XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; -XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; - -unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) -{ - unsigned failed = 0; - uint8_t outBuffer[128]; - uint8_t ctrlBuffer[128]; - uint8_t inBuffer[128]; - unsigned length; - XUD_Result_t result; - - for(size_t i = 0; i < sizeof(outBuffer); i++) - inBuffer[i] = i; - - XUD_ep ep_ctrl = XUD_InitEp(c_ep_out[CTRL_EP_NUM]); - - XUD_ep ep_out = XUD_InitEp(c_ep_out[TEST_EP_NUM]); - XUD_ep ep_in = XUD_InitEp(c_ep_in[TEST_EP_NUM]); - XUD_SetStall(ep_out); - XUD_SetStall(ep_in); - - XUD_SetReady_Out(ep_out, outBuffer); - XUD_SetReady_In(ep_in, inBuffer, PKT_LENGTH_START); - XUD_SetReady_Out(ep_ctrl, ctrlBuffer); - - unsigned loop0 = 1; - unsigned loop1 = 1; - while(loop0 | loop1) - { - select - { - case XUD_GetData_Select(c_ep_out[TEST_EP_NUM], ep_out, length, result): - loop0 = 0; - break; - - case XUD_GetData_Select(c_ep_out[CTRL_EP_NUM], ep_ctrl, length, result): - XUD_ClearStall(ep_out); - XUD_ClearStall(ep_in); - break; - - case XUD_SetData_Select(c_ep_in[TEST_EP_NUM], ep_in, result): - loop1 = 0; - break; - } - failed |= (result != XUD_RES_OKAY); - } - - return failed; -} - -#include "test_main.xc" diff --git a/tests/test_stall_epready_in.py b/tests/test_stall_epready_in.py new file mode 100644 index 00000000..f5611095 --- /dev/null +++ b/tests/test_stall_epready_in.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# Copyright 2016-2021 XMOS LIMITED. +# This Software is subject to the terms of the XMOS Public Licence: Version 1. + +# Directed test for (github) issue #58 +import pytest + +from conftest import PARAMS, test_RunUsbSession # noqa F401 +from usb_session import UsbSession +from usb_transaction import UsbTransaction + + +@pytest.fixture +def test_session(ep, address, bus_speed): + + pktLength = 10 + + session = UsbSession( + bus_speed=bus_speed, run_enumeration=False, device_address=address + ) + + ep_ctrl = ep + 1 + + # Expect test EP's to be halted + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + halted=True, + ) + ) + + # Inform DUT to un-halt OUT EP via ctrl EP + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep_ctrl, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + ) + ) + + # Expect normal transaction on IN EP + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + ) + ) + pktLength += 1 + + # ---- + + # Expect normal transaction on IN EP + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + ) + ) + pktLength += 1 + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep_ctrl, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + interEventDelay=500, + ) + ) + + # Expect EP to now be re-halted + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + halted=True, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep_ctrl, + endpointType="BULK", + transType="OUT", + dataLength=pktLength, + interEventDelay=500, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep, + endpointType="BULK", + transType="IN", + dataLength=pktLength, + ) + ) + + return session diff --git a/tests/test_stall_epready_in/Makefile b/tests/test_stall_epready_in/Makefile new file mode 100644 index 00000000..a2c9ee98 --- /dev/null +++ b/tests/test_stall_epready_in/Makefile @@ -0,0 +1,3 @@ +TEST_FLAGS = -DXUD_BYPASS_RESET=1 + +include ../test_makefile.mak diff --git a/tests/test_stall_epready_in/src/main.xc b/tests/test_stall_epready_in/src/main.xc new file mode 100644 index 00000000..5136c936 --- /dev/null +++ b/tests/test_stall_epready_in/src/main.xc @@ -0,0 +1,114 @@ +// Copyright 2016-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + + +#define EP_COUNT_OUT (6) +#define EP_COUNT_IN (6) + +#ifndef PKT_LENGTH_START +#define PKT_LENGTH_START (10) +#endif + +#ifndef TEST_EP_NUM +#define TEST_EP_NUM (1) +#endif + +#ifndef CTRL_EP_NUM +#define CTRL_EP_NUM (TEST_EP_NUM + 1) +#endif + +#include "shared.h" + +/* Endpoint type tables */ +XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; +XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; + +unsigned test_ctrl(chanend c_ctrl, chanend c) +{ + uint8_t ctrlBuffer[128]; + unsigned length; + XUD_Result_t result; + uint32_t failed = 0; + + XUD_ep ep_ctrl = XUD_InitEp(c_ctrl); + + c <: 1; + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_ClearStallByAddr(TEST_EP_NUM | 0x80); /* Set IN bit */ + + c <: 1; + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_SetStallByAddr(TEST_EP_NUM | 0x80); + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_ClearStallByAddr(TEST_EP_NUM | 0x80); + + return failed; +} + + +#define BUFFER_SIZE 128 +unsigned test_ep(chanend c_ep_out, chanend c_ep_in, chanend c) +{ + uint32_t failed = 0; + uint8_t inBuffer[3][BUFFER_SIZE]; + unsigned length = PKT_LENGTH_START; + XUD_Result_t result; + unsigned x = 0; + + for(size_t i = 0; i < 3; i++) + { + for(size_t j = 0; j < length; j++) + { + inBuffer[i][j] = x++; + } + length++; + } + + length = PKT_LENGTH_START; + + XUD_ep ep_in = XUD_InitEp(c_ep_in); + XUD_SetStall(ep_in); + + c :> x; + + /* First test marking EP ready whilst halted + * Then subsequently marked un-halted - this should pause until un-halted */ + XUD_SetBuffer(ep_in, inBuffer[0], length++); + + /* Additional normal IN transaction */ + XUD_SetBuffer(ep_in, inBuffer[1], length++); + + c :> x; + + /* Next test EP marked ready then subsequently marked as halted */ + XUD_SetBuffer(ep_in, inBuffer[2], length); + + /* TODO not currently set */ + return failed; +} + +unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) +{ + unsigned failedCtrl = 0; + unsigned failedEp = 0; + chan c; + + par + { + failedCtrl = test_ctrl(c_ep_out[CTRL_EP_NUM], c); + failedEp = test_ep(c_ep_out[TEST_EP_NUM], c_ep_in[TEST_EP_NUM], c); + } + + return failedCtrl | failedEp; +} + +#include "test_main.xc" diff --git a/tests/test_stall_epready.py b/tests/test_stall_epready_out.py similarity index 72% rename from tests/test_stall_epready.py rename to tests/test_stall_epready_out.py index a864d198..13309ae7 100644 --- a/tests/test_stall_epready.py +++ b/tests/test_stall_epready_out.py @@ -28,68 +28,84 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, halted=True, ) ) + # Inform DUT to un-halt OUT EP via ctrl EP session.add_event( UsbTransaction( session, deviceAddress=address, - endpointNumber=ep, + endpointNumber=ep_ctrl, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, - halted=True, ) ) + # Expect normal transaction on OUT EP session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", - halted=True, + transType="OUT", + dataLength=pktLength, ) ) + # ---- + + # Expect normal transaction on OUT EP session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", - halted=True, + transType="OUT", + dataLength=pktLength, ) ) - # Inform DUT to un halt EP's session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep_ctrl, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, + interEventDelay=500, ) ) - # Expect normal transactions - # DUT will exit after one normal transaction per EP. + # Expect EP to now be re-halted session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", + dataLength=pktLength, + halted=True, + ) + ) + + session.add_event( + UsbTransaction( + session, + deviceAddress=address, + endpointNumber=ep_ctrl, + endpointType="BULK", + transType="OUT", dataLength=pktLength, + interEventDelay=500, ) ) @@ -99,7 +115,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="IN", + transType="OUT", dataLength=pktLength, ) ) diff --git a/tests/test_stall_epready_out/Makefile b/tests/test_stall_epready_out/Makefile new file mode 100644 index 00000000..a2c9ee98 --- /dev/null +++ b/tests/test_stall_epready_out/Makefile @@ -0,0 +1,3 @@ +TEST_FLAGS = -DXUD_BYPASS_RESET=1 + +include ../test_makefile.mak diff --git a/tests/test_stall_epready_out/src/main.xc b/tests/test_stall_epready_out/src/main.xc new file mode 100644 index 00000000..ba85e424 --- /dev/null +++ b/tests/test_stall_epready_out/src/main.xc @@ -0,0 +1,101 @@ +// Copyright 2016-2021 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + + +#define EP_COUNT_OUT (6) +#define EP_COUNT_IN (6) + +#ifndef PKT_LENGTH_START +#define PKT_LENGTH_START (10) +#endif + +#ifndef TEST_EP_NUM +#define TEST_EP_NUM (1) +#endif + +#ifndef CTRL_EP_NUM +#define CTRL_EP_NUM (TEST_EP_NUM + 1) +#endif + +#include "shared.h" + +/* Endpoint type tables */ +XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; +XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL, XUD_EPTYPE_BUL}; + +unsigned test_ctrl(chanend c_ctrl, chanend c) +{ + uint8_t ctrlBuffer[128]; + unsigned length; + XUD_Result_t result; + uint32_t failed = 0; + + XUD_ep ep_ctrl = XUD_InitEp(c_ctrl); + + c <: 1; + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_ClearStallByAddr(TEST_EP_NUM); + + c <: 1; + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_SetStallByAddr(TEST_EP_NUM); + + XUD_GetBuffer(ep_ctrl, ctrlBuffer, length); + failed |= (length != PKT_LENGTH_START); + + XUD_ClearStallByAddr(TEST_EP_NUM); + + return failed; +} + +unsigned test_ep(chanend c_ep_out, chanend c) +{ + uint32_t failed = 0; + uint8_t outBuffer[128]; + unsigned length; + XUD_Result_t result; + unsigned x; + + XUD_ep ep_out = XUD_InitEp(c_ep_out); + XUD_SetStall(ep_out); + + c :> x; + + /* First test marking EP ready whilst halted + Then subsequently marked un-halted - this should pause until un-halted */ + XUD_GetBuffer(ep_out, outBuffer, length); + + /* Additional normal OUT transaction */ + XUD_GetBuffer(ep_out, outBuffer, length); + + c :> x; + + /* Next test EP marked ready then subsequently marked as halted */ + XUD_GetBuffer(ep_out, outBuffer, length); + + return failed; + +} + +unsigned test_func(chanend c_ep_out[EP_COUNT_OUT], chanend c_ep_in[EP_COUNT_IN]) +{ + unsigned failedCtrl = 0; + unsigned failedEp = 0; + chan c; + + par + { + failedCtrl = test_ctrl(c_ep_out[CTRL_EP_NUM], c); + failedEp = test_ep(c_ep_out[TEST_EP_NUM], c); + } + + return failedCtrl | failedEp; +} + +#include "test_main.xc" diff --git a/tests/test_suspend_resume.py b/tests/test_suspend_resume.py index 088d00be..0b260779 100644 --- a/tests/test_suspend_resume.py +++ b/tests/test_suspend_resume.py @@ -7,6 +7,7 @@ from usb_signalling import UsbSuspend, UsbResume from usb_session import UsbSession from usb_transaction import UsbTransaction +from usb_phy import USB_PKT_TIMINGS @pytest.fixture @@ -15,6 +16,8 @@ def test_session(ep, address, bus_speed): pktLength = 10 frameNumber = 52 # Note, for frame number 52 we expect A5 34 40 on the bus + interEventDelay = USB_PKT_TIMINGS["TX_TO_TX_PACKET_DELAY"] + session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) @@ -25,7 +28,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=0, ) @@ -39,15 +42,16 @@ def test_session(ep, address, bus_speed): frameNumber = frameNumber + 1 pktLength = pktLength + 1 session.add_event(CreateSofToken(frameNumber, interEventDelay=2000)) + session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, - interEventDelay=0, + interEventDelay=interEventDelay, ) ) diff --git a/tests/test_suspend_resume_invalidls.py b/tests/test_suspend_resume_invalidls.py index 47535be7..fda9f623 100644 --- a/tests/test_suspend_resume_invalidls.py +++ b/tests/test_suspend_resume_invalidls.py @@ -7,6 +7,7 @@ from usb_signalling import UsbSuspend, UsbResume from usb_session import UsbSession from usb_transaction import UsbTransaction +from usb_phy import USB_PKT_TIMINGS @pytest.fixture @@ -15,6 +16,8 @@ def test_session(ep, address, bus_speed): pktLength = 10 frameNumber = 52 # Note, for frame number 52 we expect A5 34 40 on the bus + interEventDelay = USB_PKT_TIMINGS["TX_TO_TX_PACKET_DELAY"] + session = UsbSession( bus_speed=bus_speed, run_enumeration=False, device_address=address ) @@ -25,7 +28,7 @@ def test_session(ep, address, bus_speed): deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, interEventDelay=0, ) @@ -39,15 +42,16 @@ def test_session(ep, address, bus_speed): frameNumber = frameNumber + 1 pktLength = pktLength + 1 session.add_event(CreateSofToken(frameNumber, interEventDelay=2000)) + session.add_event( UsbTransaction( session, deviceAddress=address, endpointNumber=ep, endpointType="BULK", - direction="OUT", + transType="OUT", dataLength=pktLength, - interEventDelay=0, + interEventDelay=interEventDelay, ) ) diff --git a/tests/usb_clock.py b/tests/usb_clock.py index 8ecc4e8c..37c8d62f 100644 --- a/tests/usb_clock.py +++ b/tests/usb_clock.py @@ -7,12 +7,11 @@ class Clock(SimThread): CLK_60MHz = 0x0 - def __init__(self, port, clk, coreFreq_Mhz): + def __init__(self, port, clk): self._running = True self._clk = clk if clk == self.CLK_60MHz: - self._period = float(1000000000.0 / 60000000.0) - self._period *= (1.0 / coreFreq_Mhz) * 1000.0 + self._period_fs = 16666667 self._name = "60Mhz" else: raise ValueError("Unsupported Clock Frequency") @@ -25,21 +24,13 @@ def run(self): while True: - time += self._period / 2 + time += self._period_fs / 2 self.wait_until(time) self._val = 1 - self._val if self._running: self.xsi.drive_periph_pin(self._port, self._val) - @property - def period_ns(self): - return self._period - - @property - def period_us(self): - return self._period / 1000 - def is_high(self): return self._val == 1 diff --git a/tests/usb_event.py b/tests/usb_event.py index f5e3db5f..1896d7db 100644 --- a/tests/usb_event.py +++ b/tests/usb_event.py @@ -4,21 +4,14 @@ class UsbEvent(ABC): - def __init__(self, time=0, interEventDelay=None): + def __init__(self, time=0): self._time = time - self._interEventDelay = interEventDelay # TODO so we want to use relative delays or absolute times? @property def time(self): return self._time - # NOTE: its not always sensible for an event to used the IED - for example - # an Rx Packet - @property - def interEventDelay(self): - return self._interEventDelay - @abstractmethod def expected_output(self, bus_speed, offset=0): pass diff --git a/tests/usb_packet.py b/tests/usb_packet.py index e98c7803..a49b8c81 100644 --- a/tests/usb_packet.py +++ b/tests/usb_packet.py @@ -62,15 +62,16 @@ import usb_phy -USB_DATA_VALID_COUNT = {"FS": 39, "HS": 0} +USB_DATA_VALID_COUNT = {"FS": 40, "HS": 1} # In USB clocks # Pad delay not currently simulated in xsim for USB or OTP, so add this # delay here -RXA_END_DELAY = 2 -RXA_START_DELAY = 5 # Taken from RTL sim +RXA_END_DELAY = 0 # Taken from RTL sim +RXA_START_DELAY = {"FS": 1, "HS": 5} # Taken from RTL sim and UTMI spec 6.4.2 +# Note, will get muiltiplied by USB_DATA_VALID_COUNT before use -# TODO shoud we have a PID class? +# TODO should we have a PID class? # TODO remove the inverted check bits USB_PID = { "OUT": 0xE1, @@ -87,7 +88,12 @@ } -def CreateSofToken(frameNumber, badCrc=False, interEventDelay=1000): +def CreateSofToken( + frameNumber, + badCrc=False, + interEventDelay=usb_phy.USB_PKT_TIMINGS["TX_TO_TX_PACKET_DELAY"], +): + ep = (frameNumber >> 7) & 0xF address = (frameNumber) & 0x7F @@ -191,8 +197,7 @@ def __init__(self, **kwargs): self.data_bytes = kwargs.pop("data_bytes", None) self.num_data_bytes = kwargs.pop("length", 0) self.bad_crc = kwargs.pop("bad_crc", False) - ied = kwargs.pop("interEventDelay", None) - super().__init__(interEventDelay=ied) + super().__init__() @property def event_count(self): @@ -295,16 +300,16 @@ def drive(self, usb_phy, bus_speed): # Tx from host i.e. xCORE Rx class TxPacket(UsbPacket): def __init__(self, **kwargs): - self.rxa_start_delay = kwargs.pop("rxa_start_delay", 2) + self.rxa_start_delay = kwargs.pop("rxa_start_delay", RXA_START_DELAY) self.rxa_end_delay = kwargs.pop("rxa_end_delay", RXA_END_DELAY) self.rxe_assert_time = kwargs.pop("rxe_assert_time", 0) self.rxe_assert_length = kwargs.pop("rxe_assert_length", 1) - ied = kwargs.pop( + self.interEventDelay = kwargs.pop( "interEventDelay", usb_phy.USB_PKT_TIMINGS["TX_TO_TX_PACKET_DELAY"], ) - super().__init__(**kwargs, interEventDelay=ied) + super().__init__(**kwargs) def expected_output(self, bus_speed, offset=0): expected_output = "Packet:\tHOST -> DEVICE\n" @@ -320,8 +325,6 @@ def drive(self, usb_phy, bus_speed): if xsi.sample_port_pins(usb_phy._txv) == 1: print("ERROR: Unexpected packet from xCORE (TxPacket 0)") - rxv_count = USB_DATA_VALID_COUNT[bus_speed] - usb_phy.wait_for_clocks(self.interEventDelay) print( @@ -334,34 +337,49 @@ def drive(self, usb_phy, bus_speed): xsi.drive_periph_pin(usb_phy._rxa, 1) # Wait for RXA start delay - rxa_start_delay = RXA_START_DELAY + rxa_start_delay = (RXA_START_DELAY[bus_speed]) * USB_DATA_VALID_COUNT[bus_speed] - while rxa_start_delay != 0: + while rxa_start_delay > 1: wait(lambda x: usb_phy._clock.is_high()) wait(lambda x: usb_phy._clock.is_low()) rxa_start_delay = rxa_start_delay - 1 - for (i, byte) in enumerate(self.get_bytes(do_tokens=False)): + packetBytes = self.get_bytes(do_tokens=False) + + for (i, byte) in enumerate(packetBytes): + + rxv_count = USB_DATA_VALID_COUNT[bus_speed] # xCore should not be trying to send if we are trying to send.. if xsi.sample_port_pins(usb_phy._txv) == 1: print("ERROR: Unexpected packet from xCORE (TxPacket 1)") - wait(lambda x: usb_phy._clock.is_low()) - wait(lambda x: usb_phy._clock.is_high()) - wait(lambda x: usb_phy._clock.is_low()) - xsi.drive_periph_pin(usb_phy._rxdv, 1) xsi.drive_periph_pin(usb_phy._rxd, byte) if (self.rxe_assert_time != 0) and (self.rxe_assert_time == i): xsi.drive_periph_pin(usb_phy._rxer, 1) - while rxv_count != 0: + # Subtract 1 since we always drive for atleast one cycle.. + rxv_count -= 1 + + while rxv_count > USB_DATA_VALID_COUNT[bus_speed] // 2: wait(lambda x: usb_phy._clock.is_high()) wait(lambda x: usb_phy._clock.is_low()) - xsi.drive_periph_pin(usb_phy._rxdv, 0) rxv_count = rxv_count - 1 + # RxV high for 1 cycle + xsi.drive_periph_pin(usb_phy._rxdv, 1) + wait(lambda x: usb_phy._clock.is_high()) + wait(lambda x: usb_phy._clock.is_low()) + xsi.drive_periph_pin(usb_phy._rxdv, 0) + + # Don't delay on last byte (effects FS only) + if i < len(packetBytes) - 1: + while rxv_count > 0: + wait(lambda x: usb_phy._clock.is_high()) + wait(lambda x: usb_phy._clock.is_low()) + rxv_count = rxv_count - 1 + # xCore should not be trying to send if we are trying to send.. # We assume that the Phy internally blocks the TXValid signal # to the Transmit State Machine until the Rx packet has @@ -370,11 +388,9 @@ def drive(self, usb_phy, bus_speed): # if xsi.sample_port_pins(usb_phy._txv) == 1: # print("ERROR: Unexpected packet from xCORE (TxPacket 2)") - rxv_count = USB_DATA_VALID_COUNT[bus_speed] - # Wait for last byte - wait(lambda x: usb_phy._clock.is_high()) - wait(lambda x: usb_phy._clock.is_low()) + # wait(lambda x: usb_phy._clock.is_high()) + # wait(lambda x: usb_phy._clock.is_low()) xsi.drive_periph_pin(usb_phy._rxdv, 0) xsi.drive_periph_pin(usb_phy._rxer, 0) @@ -402,7 +418,7 @@ def get_bytes(self, do_tokens=False): if do_tokens: byte_list.append(self.pid) else: - byte_list.append(self.pid | ((~self.pid) << 4)) + byte_list.append(self.pid) # | ((~self.pid) << 4)) for b in self.data_bytes: byte_list.append(b) return byte_list @@ -425,7 +441,7 @@ def get_bytes(self, do_tokens=False): if do_tokens: byte_list.append(self.pid) else: - byte_list.append(self.pid | (((~self.pid) & 0xF) << 4)) + byte_list.append(self.pid) # | (((~self.pid) & 0xF) << 4)) packet_bytes = self.get_packet_bytes() for byte in packet_bytes: @@ -481,6 +497,7 @@ def __str__(self): # Always TX class TokenPacket(TxPacket): def __init__(self, **kwargs): + super().__init__(**kwargs) self.endpoint = kwargs.pop("endpoint", 0) self.valid = kwargs.pop("valid", 1) diff --git a/tests/usb_phy.py b/tests/usb_phy.py index faf21f29..31e1c2f5 100644 --- a/tests/usb_phy.py +++ b/tests/usb_phy.py @@ -56,11 +56,13 @@ USB_PKT_TIMINGS_TIGHT = { - "TX_TO_RX_PACKET_TIMEOUT": 14, # Timeout between sending DUT a packet + "TX_TO_RX_PACKET_TIMEOUT": 18, # Timeout between sending DUT a packet # and the expected response (in USB # clocks). This is SIE decision time in # UTMI spec - "TX_TO_TX_PACKET_DELAY": 4, # Delay between transmitting two packets + # TODO this needs reducing to 14! + "TX_TO_TX_PACKET_DELAY": 6, # Delay between transmitting two packets + # TODO this needs reducing to 4! } diff --git a/tests/usb_phy_utmi.py b/tests/usb_phy_utmi.py index 1644b5b2..28906572 100644 --- a/tests/usb_phy_utmi.py +++ b/tests/usb_phy_utmi.py @@ -17,7 +17,7 @@ def __init__( xcvrsel, termsel, clock, - initial_delay=64000, + initial_delay=140000000000, # in fs verbose=False, do_timeout=True, complete_fn=None, diff --git a/tests/usb_session.py b/tests/usb_session.py index 2e8cf1fa..30c104d1 100644 --- a/tests/usb_session.py +++ b/tests/usb_session.py @@ -87,25 +87,25 @@ def _pid_toggle(pid_table, n): def data_pid_in(self, n, togglePid=True, resetDataPid=False): if resetDataPid: - self._pidTable_in[n] = usb_packet.USB_PID["DATA1"] - pid = self._pidTable_in[n] - return pid + self._pidTable_in[n] = usb_packet.USB_PID["DATA0"] pid = self._pidTable_in[n] + if togglePid: self._pid_toggle(self._pidTable_in, n) + return pid def data_pid_out(self, n, togglePid=True, resetDataPid=False): if resetDataPid: - self._pidTable_out[n] = usb_packet.USB_PID["DATA1"] - pid = self._pidTable_out[n] - return pid + self._pidTable_out[n] = usb_packet.USB_PID["DATA0"] pid = self._pidTable_out[n] + if togglePid: self._pid_toggle(self._pidTable_out, n) + return pid def __str__(self): diff --git a/tests/usb_signalling.py b/tests/usb_signalling.py index afb671a1..5405739d 100644 --- a/tests/usb_signalling.py +++ b/tests/usb_signalling.py @@ -4,10 +4,13 @@ from usb_event import UsbEvent from usb_phy import USB_LINESTATE, USB_TIMINGS +TIMESTEP_TO_NS = 1000000 # fs to ns + class UsbDeviceAttach(UsbEvent): def __init__(self, interEventDelay=0): - super().__init__(interEventDelay=interEventDelay) + self.interEventDelay = interEventDelay + super().__init__() def __str__(self): return "DeviceAttach" @@ -26,11 +29,15 @@ def event_count(self): return 1 def drive(self, usb_phy, bus_speed): + def time(): + time = xsi.get_time() + return time / TIMESTEP_TO_NS + + def wait_until_ns(time): + usb_phy.wait_until(time * TIMESTEP_TO_NS) wait = usb_phy.wait - wait_until_ns = usb_phy.wait_until xsi = usb_phy.xsi - time = xsi.get_time print("DeviceAttach") tConnect_ns = time() @@ -190,7 +197,8 @@ def __init__( ): self._duration = duration self._glitches = glitches - super().__init__(interEventDelay=interEventDelay) + self.interEventDelay = interEventDelay + super().__init__() def expected_output(self, bus_speed, offset=0): expected_output = "RESUME\n" @@ -211,6 +219,10 @@ def event_count(self): return 1 def drive(self, usb_phy, bus_speed): + def get_time_ns(): + time = xsi.get_time() + return time / TIMESTEP_TO_NS + xsi = usb_phy.xsi wait = usb_phy.wait wait_for_clocks = usb_phy.wait_for_clocks @@ -219,7 +231,7 @@ def drive(self, usb_phy, bus_speed): if xsi.sample_port_pins(usb_phy._txv) == 1: print("ERROR: Unexpected packet from xCORE") - resumeStartTime_ns = xsi.get_time() + resumeStartTime_ns = get_time_ns() print("RESUME") @@ -236,7 +248,7 @@ def drive(self, usb_phy, bus_speed): wait_for_clocks(1) - currentTime_ns = xsi.get_time() + currentTime_ns = get_time_ns() if ( currentTime_ns >= (resumeStartTime_ns + glitchTime) @@ -255,7 +267,7 @@ def drive(self, usb_phy, bus_speed): while True: wait_for_clocks(1) - currentTime_ns = xsi.get_time() + currentTime_ns = get_time_ns() if currentTime_ns >= glitchTime + duration: break @@ -268,7 +280,7 @@ def drive(self, usb_phy, bus_speed): ): break - endResumeStartTime_ns = xsi.get_time() + endResumeStartTime_ns = get_time_ns() # Drive end of resume signalling xsi.drive_periph_pin(usb_phy._ls, USB_LINESTATE["IDLE"]) @@ -277,7 +289,7 @@ def drive(self, usb_phy, bus_speed): wait(lambda x: usb_phy._clock.is_high()) wait(lambda x: usb_phy._clock.is_low()) - currentTime_ns = xsi.get_time() + currentTime_ns = get_time_ns() if currentTime_ns >= endResumeStartTime_ns + ( USB_TIMINGS["RESUME_SE0_US"] * 1000 ): @@ -305,7 +317,8 @@ class UsbSuspend(UsbEvent): # clks? def __init__(self, duration_ns, interEventDelay=0): self._duration_ns = duration_ns - super().__init__(interEventDelay=interEventDelay) + self.interEventDelay = interEventDelay + super().__init__() def expected_output(self, bus_speed, offset=0): expected_output = "SUSPEND START. WAITING FOR DUT TO ENTER FS\n" @@ -321,6 +334,9 @@ def event_count(self): return 1 def drive(self, usb_phy, bus_speed): + def get_time_ns(): + time = xsi.get_time() + return time / TIMESTEP_TO_NS xsi = usb_phy.xsi wait = usb_phy.wait @@ -329,7 +345,7 @@ def drive(self, usb_phy, bus_speed): if xsi.sample_port_pins(usb_phy._txv) == 1: print("ERROR: Unexpected packet from xCORE") - suspendStartTime_ns = xsi.get_time() + suspendStartTime_ns = get_time_ns() # print("SUSPEND START TIME: " + str(suspendStartTime_ns)) assert self.interEventDelay == 0 @@ -355,7 +371,7 @@ def drive(self, usb_phy, bus_speed): # Wait for DUT to move into FS mode if xcvr == 1 and termsel == 1: - fsTime_ns = xsi.get_time() + fsTime_ns = get_time_ns() timeToFs_ns = fsTime_ns - suspendStartTime_ns # print("DEVICE ENTERED FS AT TIME " + str(fsTime_ns/1000) + "(after " + str(timeToFs_ns/1000) +" uS)") # noqa F401 print("DEVICE ENTERED FS MODE") @@ -368,7 +384,7 @@ def drive(self, usb_phy, bus_speed): xsi.drive_periph_pin(usb_phy._ls, USB_LINESTATE["FS_J"]) break - time_ns = xsi.get_time() - suspendStartTime_ns + time_ns = get_time_ns() - suspendStartTime_ns if time_ns > (USB_TIMINGS["IDLE_TO_FS_MAX_US"] * 1000): print("ERROR: DUT DID NOT ENTER FS MODE IN TIME") @@ -389,7 +405,7 @@ def drive(self, usb_phy, bus_speed): if not (xcvr == 1 and termsel == 1): print("ERROR: DUT moved out of FS mode unexpectly during suspend") - time_ns = xsi.get_time() - suspendStartTime_ns + time_ns = get_time_ns() - suspendStartTime_ns if time_ns >= self._duration_ns: print("SUSPEND END") break diff --git a/tests/usb_transaction.py b/tests/usb_transaction.py index 003b3dec..2a8df1bf 100644 --- a/tests/usb_transaction.py +++ b/tests/usb_transaction.py @@ -9,15 +9,15 @@ RxHandshakePacket, RxDataPacket, TxHandshakePacket, + USB_DATA_VALID_COUNT, ) -from usb_packet import USB_DATA_VALID_COUNT +from usb_phy import USB_PKT_TIMINGS INTER_TRANSACTION_DELAY = 500 -USB_DIRECTIONS = ["OUT", "IN"] +USB_TRANS_TYPES = ["OUT", "IN", "SETUP"] USB_EP_TYPES = ["CONTROL", "BULK", "ISO", "INTERRUPT"] - # TODO UsbTransaction_IN and UsbTransaction_OUT class UsbTransaction(UsbEvent): def __init__( @@ -26,7 +26,7 @@ def __init__( deviceAddress=0, endpointNumber=0, endpointType="BULK", - direction="OUT", + transType="OUT", bus_speed="HS", eventTime=0, dataLength=0, @@ -36,12 +36,12 @@ def __init__( rxeAssertDelay_data=0, halted=False, resetDataPid=False, - ): # TODO Enums when we move to py3 + ): self._deviceAddress = deviceAddress self._endpointNumber = endpointNumber self._endpointType = endpointType - self._direction = direction + self._transType = transType self._datalength = dataLength self._bus_speed = bus_speed self._badDataCrc = badDataCrc @@ -49,20 +49,20 @@ def __init__( self._halted = halted assert endpointType in USB_EP_TYPES - assert direction in USB_DIRECTIONS + assert transType in USB_TRANS_TYPES # Populate packet list for a (valid) transaction self._packets = [] # TODO would it be better to generate packets on the fly in drive() # rather than create a packet list? - if direction == "OUT": + if transType in ["OUT", "SETUP"]: packets = [] packets.append( TokenPacket( interEventDelay=interEventDelay, - pid=USB_PID["OUT"], + pid=USB_PID[transType], address=self._deviceAddress, endpoint=self._endpointNumber, data_valid_count=self.data_valid_count, @@ -80,6 +80,9 @@ def __init__( else: togglePid = True + if halted: + resetDataPid = True + expectHandshake = ( (not self._badDataCrc) and (not self._rxeAssertDelay_data) @@ -97,9 +100,20 @@ def __init__( endpointNumber, dataLength, resend=resend ) - pid = session.data_pid_out( - endpointNumber, togglePid=togglePid, resetDataPid=resetDataPid - ) + # Reset data PID's on SETUP transaction + if transType == "SETUP": + pid = session.data_pid_out( + endpointNumber, togglePid=True, resetDataPid=True + ) + + # If SETUP trans then we need to reset and toggle the corresponding IN EP's PID also + in_pid = session.data_pid_in( + endpointNumber, togglePid=True, resetDataPid=True + ) + else: + pid = session.data_pid_out( + endpointNumber, togglePid=togglePid, resetDataPid=resetDataPid + ) # Add data packet to packets list packets.append( @@ -135,12 +149,18 @@ def __init__( self._badDataCrc or self._rxeAssertDelay_data or self._endpointType == "ISO" + or halted ): togglePid = False else: togglePid = True - pid = session.data_pid_in(endpointNumber, togglePid=togglePid) + if halted: + resetDataPid = True + + pid = session.data_pid_in( + endpointNumber, togglePid=togglePid, resetDataPid=resetDataPid + ) # Add data packet to packets list if not halted: @@ -154,7 +174,7 @@ def __init__( if halted: self._packets.append(RxHandshakePacket(pid=USB_PID["STALL"])) - super().__init__(time=eventTime, interEventDelay=interEventDelay) + super().__init__(time=eventTime) # TODO ideally USBTransaction doesnt know about data_valid_count @property diff --git a/xmos_cpm.cmake b/xmos_cpm.cmake new file mode 100644 index 00000000..1dece795 --- /dev/null +++ b/xmos_cpm.cmake @@ -0,0 +1,38 @@ +set(XUD_XC_SRCS + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_Main.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_DeviceAttach.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_HAL.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_Signalling.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_IOLoopCall.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_Support.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_User.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_UserResume.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_TestMode.xc + + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/control/xud_device.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/control/xud_std_requests.xc + + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/client/XUD_EpFunctions.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/client/XUD_SetDevAddr.xc +) +set(XUD_C_SRCS + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_Default.c + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_SetCrcTableAddr.c +) +set(XUD_ASM_SRCS + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/client/XUD_EpFuncs.S + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_USBTile_Support.S + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_IoLoop.S + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_CRC5_Table_Addr.S + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_CRC5_Table.S + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_User.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_UserResume.xc + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core/XUD_TestMode.S +) +set(XUD_SRCS ${XUD_XC_SRCS} ${XUD_C_SRCS} ${XUD_ASM_SRCS}) +set(XUD_INCLUDE_DIRS + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/api + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/core + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user + ${CMAKE_BINARY_DIR}/lib_xud/lib_xud/src/user/class +)