blob: eb2be17868603f70487cb3586f46afd257bf367a [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_HW_DV_DPI_USBDPI_USBDPI_H_
#define OPENTITAN_HW_DV_DPI_USBDPI_USBDPI_H_
#define TOOL_VERILATOR 1
#define TOOL_INCISIVE 0
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#if USBDPI_STANDALONE
// For stricter compilation checks, and building faster standalone
typedef uint32_t svBitVecVal;
#else
#include <svdpi.h>
#endif
#include "usb_monitor.h"
#include "usb_transfer.h"
#include "usbdpi_stream.h"
// Shall we employ a proper simulation of the frame interval (1ms)?
// TODO - until such time as we can perform multiple control transfers in a
// single bus frame, this is impractical because the simulation takes too
// long and is apt to time out
#define FULL_FRAME 0
// How many bits in our frame
//
// (frames on a Full Speed USB link are 1ms, with 12Mbps signalling, but the
// USB device supports only data transfers of up to 64 bytes, so a 1ms
// frame interval makes the simulation needlessly long)
#if FULL_FRAME
#define FRAME_INTERVAL 12000 // 12Mbps, 1ms frame time
#else
#define FRAME_INTERVAL 6000 // 0.5ms
#endif
// How many bits after start to assert VBUS
#define SENSE_AT 20 * 8
// Logging level (parameter to module)
#define LOG_MON 0x01 // USB monitor logging (packet level)
#define LOG_BIT 0x08 // bit level
// Error insertion
#define INSERT_ERR_CRC 0
#define INSERT_ERR_PID 0
#define INSERT_ERR_BITSTUFF 0
#define INSERT_ERR_DATA_TOGGLE 0
// Endpoints used during top-level tests
#define ENDPOINT_ZERO 0 // Endpoint Zero (for the Default Control Pipe)
#define ENDPOINT_SERIAL0 1 // For basic serial communications test
#define ENDPOINT_SERIAL1 2 // Second serial channel
#define ENDPOINT_ISOCHRONOUS 3 // For basic testing of Isochronous transfers
#define ENDPOINT_UNIMPLEMENTED \
15 // For testing of response to unimplemented
// endpoints
#define D2P_BITS 11
#define D2P_DP 1024
#define D2P_DP_EN 512
#define D2P_DN 256
#define D2P_DN_EN 128
#define D2P_D 64
#define D2P_D_EN 32
#define D2P_SE0 16
#define D2P_TX_USE_D_SE0 8
#define D2P_DPPU 4
#define D2P_DNPU 2
#define D2P_RX_ENABLE 1
// Either pullup (dp/dn swapped if the pullup is on DN)
#define D2P_PU (D2P_DPPU | D2P_DNPU)
#define P2D_SENSE 1
#define P2D_DN 2
#define P2D_DP 4
#define P2D_D 8
/* Remember these go LSB first */
/* Sync is KJKJKJKK */
#define USB_SYNC 0x2AU
/* USB Packet IDentifiers */
#define USB_PID_OUT 0xE1U
#define USB_PID_IN 0x69U
#define USB_PID_SOF 0xA5U
#define USB_PID_SETUP 0x2DU
#define USB_PID_DATA0 0xC3U
#define USB_PID_DATA1 0x4BU
#define USB_PID_ACK 0xD2U
#define USB_PID_NAK 0x5AU
#define USB_PID_STALL 0x1EU
#define USB_PID_NYET 0x96U
#define USB_PID_PING 0xB4U
/* USB Standard Request Codes */
#define USB_REQ_GET_STATUS 0x00U
#define USB_REQ_CLEAR_FEATURE 0x01U
#define USB_REQ_SET_FEATURE 0x03U
#define USB_REQ_SET_ADDRESS 0x05U
#define USB_REQ_GET_DESCRIPTOR 0x06U
#define USB_REQ_SET_DESCRIPTOR 0x07U
#define USB_REQ_GET_CONFIGURATION 0x08U
#define USB_REQ_SET_CONFIGURATION 0x09U
#define USB_REQ_GET_INTERFACE 0x0AU
#define USB_REQ_SET_INTERFACE 0x0BU
#define USB_REQ_SYNCH_FRAME 0x0CU
/* USB Descriptor Types */
#define USB_DESC_TYPE_DEVICE 0x01U
#define USB_DESC_TYPE_CONFIGURATION 0x02U
#define USB_DESC_TYPE_STRING 0x03U
#define USB_DESC_TYPE_INTERFACE 0x04U
#define USB_DESC_TYPE_ENDPOINT 0x05U
#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
#define USB_DESC_TYPE_OTHER_SPEED_CONFIG 0x07U
#define USB_DESC_TYPE_INTERFACE_POWER 0x08U
// Device address to be used for the USBDEV IP block
#define USBDEV_ADDRESS 2
// Unknown device address (check USBDEV ignores traffic to other devices)
#define UKDEV_ADDRESS 6
// Maximum number of endpoints implemented by the USBDEV IP
#define USBDEV_MAX_ENDPOINTS 12U
// Maximum number of endpoints supported by the DPI model
#define USBDPI_MAX_ENDPOINTS 16U
// Maximum number of bidirection LFSR-generated byte streams that may be
// supported simultaneously
#define USBDPI_MAX_STREAMS (USBDPI_MAX_ENDPOINTS - 1U)
// Maximum number of simultaneous transfer descriptors
// (The host model may simply avoid polling for further IN transfers
// whilst there are no further desciptors available)
#define USBDPI_MAX_TRANSFERS 0x10U
// Time intervals for common transactions, in bits
// (allowing for bit stuffing and bus turnaround etc; for setting timeouts)
#define USBDPI_INTERVAL_SETUP_STAGE 200U
// Return the time at which the given number of bit intervals shall have elapsed
#define USBDPI_TIMEOUT(ctx, bits) ((ctx)->tick_bits + (bits))
// Maximum length of test status message
#define USBDPI_MAX_TEST_MSG_LEN 80U
// Vendor-specific commands used for test framework
#define USBDPI_VENDOR_TEST_CONFIG 0x7CU
#define USBDPI_VENDOR_TEST_STATUS 0x7EU
// Next DATAx PID to be used (transmission) or expected (reception)
#define DATA_TOGGLE_ADVANCE(pid) \
((pid) == USB_PID_DATA1 ? USB_PID_DATA0 : USB_PID_DATA1)
#ifdef __cplusplus
extern "C" {
#endif
// USBDPI driver states
typedef enum {
ST_IDLE = 0,
ST_SEND = 1,
ST_GET = 2,
ST_SYNC = 3,
ST_EOP = 4,
ST_EOP0 = 5
} usbdpi_drv_state_t;
// Test steps
typedef enum {
STEP_BUS_RESET = 0u,
STEP_SET_DEVICE_ADDRESS,
STEP_GET_DEVICE_DESCRIPTOR,
STEP_GET_CONFIG_DESCRIPTOR,
STEP_GET_FULL_CONFIG_DESCRIPTOR,
STEP_SET_DEVICE_CONFIG,
// Read test configuration
// This is a bespoke 'vendor' command via which we inquire of the CPU
// software what behaviour is required
STEP_GET_TEST_CONFIG,
// Report test status (pass/failure) to the CPU software
STEP_SET_TEST_STATUS,
// usbdev_test
STEP_FIRST_READ,
STEP_READ_BAUD,
STEP_SECOND_READ,
STEP_SET_BAUD,
STEP_THIRD_READ,
STEP_TEST_ISO1,
STEP_TEST_ISO2,
STEP_ENDPT_UNIMPL_SETUP,
STEP_ENDPT_UNIMPL_OUT,
STEP_ENDPT_UNIMPL_IN,
STEP_DEVICE_UK_SETUP,
STEP_IDLE_START,
STEP_IDLE_END = STEP_IDLE_START + 4,
// usbdev_stream_test
STEP_STREAM_SERVICE = 0x20u,
// Disconnect the device and stop
STEP_BUS_DISCONNECT = 0x7fu
} usbdpi_test_step_t;
// Host states
typedef enum {
HS_STARTFRAME = 0,
HS_WAITACK = 1,
HS_SET_DATASTAGE = 2,
HS_DS_RXDATA = 3,
HS_DS_SENDACK = 4,
HS_DONEDADR = 5,
HS_REQDATA = 6,
HS_WAITDATA = 7,
HS_SENDACK = 8,
HS_WAIT_PKT = 9,
HS_ACKIFDATA = 10,
HS_SENDHI = 11,
HS_EMPTYDATA = 12,
HS_WAITACK2 = 13,
HS_STREAMOUT = 14,
HS_STREAMIN = 15,
HS_NEXTFRAME = 16
} usbdpi_host_state_t;
typedef enum usbdpi_bus_state {
kUsbIdle = 0,
kUsbControlSetup,
kUsbControlSetupAck,
kUsbControlDataOut,
kUsbControlDataOutAck,
kUsbControlStatusInToken,
kUsbControlStatusInData,
kUsbControlStatusInAck,
kUsbControlDataInToken,
kUsbControlDataInData,
kUsbControlDataInAck,
kUsbControlStatusOut,
kUsbControlStatusOutAck,
kUsbIsoToken,
kUsbIsoDataIn,
kUsbIsoDataOut,
kUsbBulkOut,
kUsbBulkOutAck,
kUsbBulkInToken,
kUsbBulkInData,
kUsbBulkInAck,
} usbdpi_bus_state_t;
/**
* USB DPI state information
*/
struct usbdpi_ctx {
// Bus signalling state
usbdpi_bus_state_t bus_state;
uint32_t driving;
int linebits;
int bit;
int byte;
/**
* Test number, retrieved from the software
*/
uint16_t test_number;
/**
* Test-specific arguments
*/
uint8_t test_arg[4];
/**
* Test status
* TODO - introduce enum indicating the test status, or borrow from
* the existing source tree; we indicate progress too in other places
*/
uint32_t test_status;
char test_msg[USBDPI_MAX_TEST_MSG_LEN];
/**
* Context for IN endpoints
*/
struct {
/**
* Next DATAx PID (DATA0 or DATA1) expected from device
*/
uint8_t next_data;
} ep_in[USBDPI_MAX_ENDPOINTS];
/**
* Context for OUT endpoints
*/
struct {
/**
* Next DATAx (DATA0 or DATA1) to be transmitted; advanced when ACKed
* and reset after SETUP packet transmitted
*/
uint8_t next_data;
} ep_out[USBDPI_MAX_ENDPOINTS];
/**
* Number of data streams being used
*/
uint8_t nstreams;
/**
* Stream number of next stream to attempt IN transfers
*/
uint8_t stream_in;
/**
* Stream number of next stream to attempt OUT transfers
*/
uint8_t stream_out;
/**
* Context for streaming data test (usbdev_stream_test)
*/
usbdpi_stream_t stream[USBDPI_MAX_STREAMS];
// Diagnostic logging and bus monitoring
int loglevel;
char mon_pathname[FILENAME_MAX];
/**
* USB monitor instance
*/
usb_monitor_ctx_t *mon;
/**
* Host controller state
*/
usbdpi_host_state_t hostSt;
/**
* Transfer currently being received from the DUT (NULL iff none)
*/
usbdpi_transfer_t *recving;
/***
* Transfer currently being sent to the DUT (NULL iff none)
*/
usbdpi_transfer_t *sending;
uint32_t last_pu;
uint8_t lastrxpid;
/**
* Count of clock cycles
*/
uint32_t tick;
/**
* Current time in USB bit intervals
*/
uint32_t tick_bits;
/**
* End time of recovery interval (following device attachment)
*/
uint32_t recovery_time;
/**
* Test step number
*/
usbdpi_test_step_t step;
// Bus framing
// Note: USB frame numbers are transmitted as 11-bit fields [0,0x7ffU]
uint16_t frame;
uint16_t framepend;
/**
* Time at which the current frame started (bit intervals)
*/
uint32_t frame_start;
/**
* Wait timeout for current operation (bit intervals)
*/
uint32_t wait;
/**
* DPI driver state
*/
usbdpi_drv_state_t state;
int baudrate_set_successfully;
/**
* Device address currently assigned to the DUT
*/
uint8_t dev_address;
/**
* Length of configuration descriptor
*/
uint16_t cfg_desc_len;
/**
* Linked-list of free transfer descriptors
*/
usbdpi_transfer_t *free;
/**
* Small pool of transfer descriptors
*/
usbdpi_transfer_t transfer_pool[USBDPI_MAX_TRANSFERS];
};
/**
* Create a USB DPI instance, returning a 'chandle' for later use
*/
void *usbdpi_create(const char *name, int loglevel);
/**
* Close a USB DPI instance
*/
void usbdpi_close(void *ctx_void);
/**
* Respond to device outputs
*/
void usbdpi_device_to_host(void *ctx_void, const svBitVecVal *usb_d2p);
/**
* Update DPI model outputs
*/
uint8_t usbdpi_host_to_device(void *ctx_void, const svBitVecVal *usb_d2p);
/**
* Return DPI model diagnostic information for viewing in waveforms
*/
void usbdpi_diags(void *ctx_void, svBitVecVal *diags);
/**
* Calculate 5-bit CRC used to check token packets
*/
uint32_t CRC5(uint32_t dwInput, int iBitcnt);
/**
* Calculate 16-bit CRC used to check data fields
*/
uint32_t CRC16(const uint8_t *data, int bytes);
#ifdef __cplusplus
}
#endif
#endif // OPENTITAN_HW_DV_DPI_USBDPI_USBDPI_H_