Skip to content

Commit

Permalink
[usbdev_mem] Packet memory T-L test
Browse files Browse the repository at this point in the history
Simple test of TL access to usbdev packet memory.

Extend the usbdev DIF to provide raw buffer access; this
implementation is a compromise between maximal performance
(which would be 50% faster) and conformity with DIF/mock rules.

Perform memory read/write using mmio routines and then using the
DIF raw buffer-handling API. Passes in t-l sim and on CW310 FPGA.

Signed-off-by: Adrian Lees <[email protected]>
  • Loading branch information
alees24 authored and engdoreis committed Nov 15, 2024
1 parent a771270 commit 2972bc5
Show file tree
Hide file tree
Showing 5 changed files with 437 additions and 0 deletions.
107 changes: 107 additions & 0 deletions sw/device/lib/dif/dif_usbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <assert.h>

#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/memory.h"

#include "usbdev_regs.h" // Generated.

Expand Down Expand Up @@ -1012,3 +1013,109 @@ dif_result_t dif_usbdev_set_phy_pins_state(
reg_val);
return kDifOk;
}

dif_result_t dif_usbdev_buffer_raw_write(const dif_usbdev_t *usbdev, uint8_t id,
const uint8_t *src, size_t src_len) {
if (usbdev == NULL || src == NULL || misalignment32_of((uintptr_t)src) ||
src_len > USBDEV_BUFFER_ENTRY_SIZE_BYTES) {
return kDifBadArg;
}

// We're writing to the start of the buffer.
ptrdiff_t buffer_offset = (ptrdiff_t)get_buffer_addr(id, 0U);
const uint32_t *restrict ews = (uint32_t *)(src + (src_len & ~15u));
const uint32_t *restrict ws = (uint32_t *)src;

// Transfer blocks of 4 x 32-bit words at a time; use the mmio_ routines for
// compliance and to operate correctly with the DIF mocks, although this
// results in transfers taking 50% longer because of the additional addressing
// arithmetic and increased loop overheads.
while (ws < ews) {
mmio_region_write32(usbdev->base_addr, buffer_offset, ws[0]);
mmio_region_write32(usbdev->base_addr, buffer_offset + 4, ws[1]);
mmio_region_write32(usbdev->base_addr, buffer_offset + 8, ws[2]);
mmio_region_write32(usbdev->base_addr, buffer_offset + 12, ws[3]);
buffer_offset += 16;
ws += 4;
}
src_len &= 15u;

if (src_len) {
// Remaining whole words
ews = ws + (src_len >> 2);
while (ws < ews) {
mmio_region_write32(usbdev->base_addr, buffer_offset, *ws++);
buffer_offset += 4;
}
src_len &= 3u;
if (src_len) {
// Remaining individual bytes
const uint8_t *restrict bs = (uint8_t *)ws;
uint32_t d = bs[0];
if (src_len > 1) {
d |= ((uint32_t)bs[1] << 8);
if (src_len > 2) {
d |= ((uint32_t)bs[2] << 16);
}
}
// Note: we can only perform full 32-bit writes to the packet buffer but
// any additional byte(s) will be ignored. Attempting byte-level writes
// would raise exceptions.
mmio_region_write32(usbdev->base_addr, buffer_offset, d);
}
}

return kDifOk;
}

dif_result_t dif_usbdev_buffer_raw_read(const dif_usbdev_t *usbdev, uint8_t id,
uint8_t *dst, size_t dst_len) {
if (usbdev == NULL || dst == NULL || misalignment32_of((uintptr_t)dst) ||
dst_len > USBDEV_BUFFER_ENTRY_SIZE_BYTES) {
return kDifBadArg;
}

// We're reading from the start of the packet buffer.
ptrdiff_t buffer_offset = (ptrdiff_t)get_buffer_addr(id, 0U);
const uint32_t *restrict ewd = (uint32_t *)(dst + (dst_len & ~15u));
uint32_t *restrict wd = (uint32_t *)dst;

// Transfer blocks of 4 x 32-bit words at a time; use the mmio_ routines for
// compliance and to operate correctly with the DIF mocks, although this
// results in transfers taking 50% longer because of the additional addressing
// arithmetic and increased loop overheads.
while (wd < ewd) {
wd[0] = mmio_region_read32(usbdev->base_addr, buffer_offset);
wd[1] = mmio_region_read32(usbdev->base_addr, buffer_offset + 4);
wd[2] = mmio_region_read32(usbdev->base_addr, buffer_offset + 8);
wd[3] = mmio_region_read32(usbdev->base_addr, buffer_offset + 12);
buffer_offset += 16;
wd += 4;
}
dst_len &= 15u;

if (dst_len) {
// Remaining whole words
ewd = wd + (dst_len >> 2);
while (wd < ewd) {
*wd++ = mmio_region_read32(usbdev->base_addr, buffer_offset);
buffer_offset += 4;
}
dst_len &= 3u;
if (dst_len) {
// Remaining individual bytes
// Note: we can only perform full 32-bit reads from the packet buffer.
uint8_t *restrict bd = (uint8_t *)wd;
uint32_t d = mmio_region_read32(usbdev->base_addr, buffer_offset);
bd[0] = (uint8_t)d;
if (dst_len > 1) {
bd[1] = (uint8_t)(d >> 8);
if (dst_len > 2) {
bd[2] = (uint8_t)(d >> 16);
}
}
}
}

return kDifOk;
}
30 changes: 30 additions & 0 deletions sw/device/lib/dif/dif_usbdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,36 @@ dif_result_t dif_usbdev_set_phy_pins_state(
const dif_usbdev_t *usbdev, dif_toggle_t override_enable,
dif_usbdev_phy_pins_drive_t overrides);

/**
* Raw data transfer directly to the packet buffer memory. This is a faster
* implementation of the generic `mmio_memcpy_to_mmio32` that is specialized for
* the USB device and gives a significant performance improvement.
*
* @param usbdev A USB device.
* @param id Buffer number.
* @param src Source data.
* @param src_len Number of bytes to transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_raw_write(const dif_usbdev_t *usbdev, uint8_t id,
const uint8_t *src, size_t src_len);

/**
* Raw data transfer directly from the packet buffer memory. This is a faster
* implementation of the generic `mmio_memcpy_from_mmio32` that is specialized
* for the USB device and gives a significant performance improvemenet.
*
* @param usbdev A USB device.
* @param id Buffer number.
* @param dst Destination buffer.
* @param dst_len Number of bytes to transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_usbdev_buffer_raw_read(const dif_usbdev_t *usbdev, uint8_t id,
uint8_t *dst, size_t dst_len);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
120 changes: 120 additions & 0 deletions sw/device/lib/testing/usb_testutils_diags.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,109 @@
#define USBUTILS_MEM_FASTER 1
#endif

// Implement low-impact tracing of software execution, permitting the software
// and hardware behavior to be married, hopefully without modifying the
// behavior/performance, particularly in top-level simulation
#define USBUTILS_FUNCTION_POINTS 0

// Record the function points to a memory buffer instead, for use where test
// hardware is unavailable, eg. FPGA builds
#define USBUTILS_FUNCPT_USE_BUFFER 0

#if USBUTILS_MEM_FASTER
#include "sw/device/lib/base/mmio.h"
#endif

#if USBUTILS_FUNCTION_POINTS
// For access to ibex_mcycle_read()
#include "sw/device/lib/runtime/ibex.h"

// Function point file numbers
// (used to index filename table in usb_testutils_diags.c)
#define USBUTILS_FUNCPT_FILE_DIF_USBDEV 0x01U
#define USBUTILS_FUNCPT_FILE_USB_TESTUTILS 0x02U
#define USBUTILS_FUNCPT_FILE_USB_CONTROLEP 0x03U
#define USBUTILS_FUNCPT_FILE_USB_SIMPLESER 0x04U
#define USBUTILS_FUNCPT_FILE_USBDEV_TEST 0x05U
#define USBUTILS_FUNCPT_FILE_USBDEV_STRM_TEST 0x06U

#define USBUTILS_FUNCPT_LOG_ENTRIES 0x1000U
#define USBUTILS_FUNCPT_LOG_SIZE (USBUTILS_FUNCPT_LOG_ENTRIES * 4U)

#define USBUTILS_FUNCPT_ENTRY_SIGNATURE 0xAA55FF99U
/**
* Entry in function point stream
*/
typedef struct {
uint32_t sig;
uint32_t time;
uint32_t file_point;
uint32_t data;
} funcpt_entry_t;

#if USBUTILS_FUNCPT_USE_BUFFER
// Record function points to RAM buffer for deferred reporting, eg. FPGA
#define USBUTILS_FUNCPT(pt, d) \
{ \
unsigned idx = usbutils_fpt_next; \
usbutils_fpt_next = \
(idx >= USBUTILS_FUNCPT_LOG_SIZE - 4U) ? 0U : (idx + 4U); \
functpt_enttry_t *e = (functpt_enttry_t *)&usbutils_fpt_log[idx]; \
e->sig = USBUTILS_FUNCPT_ENTRY_SIGNATURE; \
e->time = (uint32_t)ibex_mcycle_read(); \
e->file_point = (USBUTILS_FUNCPT_FILE << 16) | pt; \
e->data = (d); \
}

extern volatile unsigned usbutils_fpt_next;
extern uint32_t usbutils_fpt_log[];
#else
// Emit function points to special address for waveform viewing in simulation
// (this is the address used by DV simulation for logging output)
#define USBUTILS_FUNCPT(pt, d) \
{ \
volatile uint32_t *log_hw = (uint32_t *)0x411f0084u; \
uint32_t time = (uint32_t)ibex_mcycle_read(); \
*log_hw = USBUTILS_FUNCPT_ENTRY_SIGNATURE; \
*log_hw = time; \
*log_hw = (USBUTILS_FUNCPT_FILE << 16) | (pt); \
*log_hw = (d); \
}
#endif

/**
* Report the contents of the function point log
*/
void usbutils_funcpt_report(void);
#else
// Omit function point tracing
#define USBUTILS_FUNCPT(pt, d)
#endif

// For investigation of usbdev performance characteristics
#if USBUTILS_MEM_FASTER
/**
* Performant copying routine from usbdev packet buffer (MMIO)
*
* @param base MMIO base address
* @param offset MMIO word offset
* @param dest Buffer to receive data
* @param len Number of bytes to be copied
*/
void usbutils_memcpy_from_mmio32(mmio_region_t base, uint32_t offset,
void *dest, size_t len);
/**
* Performant copying routine to usbdev packet buffer (MMIO)
*
* @param base MMIO base address
* @param offset MMIO word offset
* @param src Data to be copied
* @param len Number of bytes to be copied
*/
void usbutils_memcpy_to_mmio32(mmio_region_t base, uint32_t offset,
const void *src, size_t len);
#endif

// Used for tracing what is going on. This may impact timing which is critical
// when simulating with the USB DPI module.
#define USBUTILS_ENABLE_TRC 0
Expand All @@ -35,12 +138,29 @@
} while (false)

#if USBUTILS_ENABLE_TRC
#if 0
// May be useful on FPGA CW310
#include "sw/device/lib/runtime/log.h"
#define TRC_S(s) LOG_INFO("%s", s)
#define TRC_I(i, b) LOG_INFO("0x%x", i)
#define TRC_C(c) LOG_INFO("%c", c)
#else
// Very low impact, for use in t-l simulation
#define USBDIAGS_LOG_EMIT(d) (*((volatile uint32_t *)0x411f0084u) = (d))

#define TRC_S(s) usbutils_log_text(s)
#define TRC_I(i, b) USBDIAGS_LOG_EMIT(i)
#define TRC_C(c) USBDIAGS_LOG_EMIT(0xcc000000u | (uint16_t)c)

// Faster string logging to minimise impact upon timing
inline void usbutils_log_text(const char *s) {
while (*s) {
USBDIAGS_LOG_EMIT(*s);
s++;
}
}
#endif
#else
#define TRC_S(s)
#define TRC_I(i, b)
#define TRC_C(c)
Expand Down
19 changes: 19 additions & 0 deletions sw/device/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4335,6 +4335,25 @@ opentitan_test(
],
)

opentitan_test(
name = "usbdev_mem_test",
srcs = ["usbdev_mem_test.c"],
exec_env = dicts.add(
EARLGREY_TEST_ENVS,
EARLGREY_SILICON_OWNER_ROM_EXT_ENVS,
),
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/dif:pinmux",
"//sw/device/lib/dif:usbdev",
"//sw/device/lib/runtime:log",
"//sw/device/lib/runtime:print",
"//sw/device/lib/testing:pinmux_testutils",
"//sw/device/lib/testing:usb_testutils",
"//sw/device/lib/testing/test_framework:ottf_main",
],
)

opentitan_test(
name = "usbdev_mixed_test",
srcs = ["usbdev_mixed_test.c"],
Expand Down
Loading

0 comments on commit 2972bc5

Please sign in to comment.