refactor hwfifo pull/push

This commit is contained in:
hathach
2026-01-02 23:57:48 +07:00
parent 36e8f9d7a1
commit b87c2fcc9f
3 changed files with 129 additions and 116 deletions

View File

@ -329,7 +329,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
#endif
// scatter read 4 bytes from two buffers. Parameter are not checked
// scatter read 4 bytes from two buffers (LE). Parameter are not checked
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *buf1, uint8_t len1, const uint8_t *buf2,
uint8_t len2) {
uint32_t result = 0;

View File

@ -114,7 +114,6 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
// copy data to/from fifo without updating read/write pointers
//--------------------------------------------------------------------+
#if CFG_TUSB_FIFO_HWFIFO_API
#if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
#define HWFIFO_ADDR_NEXT(_const, _hwfifo) \
_hwfifo = (_const volatile void *)((uintptr_t)(_hwfifo) + CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
@ -148,7 +147,7 @@ static void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_st
#endif
}
void tu_hwfifo_read_access_mode(const volatile void *hwfifo, uint8_t *dest, uint16_t len, uint8_t data_stride) {
void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, uint8_t data_stride) {
// Reading full available 16/32-bit hwfifo and write to fifo
while (len >= data_stride) {
stride_read(hwfifo, dest, data_stride);
@ -175,7 +174,7 @@ void tu_hwfifo_read_access_mode(const volatile void *hwfifo, uint8_t *dest, uint
}
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
void tu_hwfifo_write_access_mode(volatile void *hwfifo, const uint8_t *src, uint16_t len, uint8_t data_stride) {
void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, uint8_t data_stride) {
// Write full available 16/32 bit words to dest
while (len >= data_stride) {
stride_write(hwfifo, src, data_stride);
@ -200,122 +199,131 @@ void tu_hwfifo_write_access_mode(volatile void *hwfifo, const uint8_t *src, uint
#endif
}
}
#endif
// send n items to fifo WITHOUT updating write pointer
static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, uint8_t data_stride) {
(void)data_stride;
static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, uint8_t data_stride) {
uint16_t lin_bytes = f->depth - wr_ptr;
uint16_t wrap_bytes = n - lin_bytes;
uint8_t *ff_buf = f->buffer + wr_ptr;
#if CFG_TUSB_FIFO_HWFIFO_API
if (data_stride) {
const volatile void *hwfifo = (const volatile void *)app_buf;
if (n <= lin_bytes) {
// Linear only case
tu_hwfifo_read_access_mode(hwfifo, ff_buf, n, data_stride);
const volatile void *hwfifo = (const volatile void *)app_buf;
if (n <= lin_bytes) {
// Linear only case
tu_hwfifo_read(hwfifo, ff_buf, n, data_stride);
} else {
// Wrap around case
// Write full words to linear part of buffer
const uint32_t odd_mask = data_stride - 1;
uint16_t lin_even = lin_bytes & ~odd_mask;
tu_hwfifo_read(hwfifo, ff_buf, lin_even, data_stride);
ff_buf += lin_even;
// There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
// combine it with the wrapped part to form a full word for data stride
const uint8_t lin_odd = lin_bytes & odd_mask;
if (lin_odd > 0) {
const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
uint8_t buf_temp[4];
tu_hwfifo_read(hwfifo, buf_temp, lin_odd + wrap_odd, data_stride);
for (uint8_t i = 0; i < lin_odd; ++i) {
ff_buf[i] = buf_temp[i];
}
for (uint8_t i = 0; i < wrap_odd; ++i) {
f->buffer[i] = buf_temp[lin_odd + i];
}
wrap_bytes -= wrap_odd;
ff_buf = f->buffer + wrap_odd; // wrap around
} else {
// Wrap around case
// Write full words to linear part of buffer
const uint32_t odd_mask = data_stride - 1;
uint16_t lin_even = lin_bytes & ~odd_mask;
tu_hwfifo_read_access_mode(hwfifo, ff_buf, lin_even, data_stride);
ff_buf += lin_even;
// There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
// combine it with the wrapped part to form a full word for data stride
const uint8_t lin_odd = lin_bytes & odd_mask;
if (lin_odd > 0) {
const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
uint32_t tmp = 0;
stride_read(hwfifo, &tmp, data_stride);
HWFIFO_ADDR_NEXT(const, hwfifo);
tu_scatter_write32(tmp, ff_buf, lin_odd, f->buffer, wrap_odd);
wrap_bytes -= wrap_odd;
ff_buf = f->buffer + wrap_odd; // wrap around
} else {
ff_buf = f->buffer; // wrap around to beginning
}
// Write data wrapped part
if (wrap_bytes > 0) {
tu_hwfifo_read_access_mode(hwfifo, ff_buf, wrap_bytes, data_stride);
}
ff_buf = f->buffer; // wrap around to beginning
}
} else
#endif
{
// single byte access
if (n <= lin_bytes) {
// Linear only case
memcpy(ff_buf, app_buf, n);
} else {
// Wrap around case
memcpy(ff_buf, app_buf, lin_bytes); // linear part
memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
// Write data wrapped part
if (wrap_bytes > 0) {
tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, data_stride);
}
}
}
// get n items from fifo WITHOUT updating read pointer
static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, uint8_t data_stride) {
(void)data_stride;
static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, uint8_t data_stride) {
uint16_t lin_bytes = f->depth - rd_ptr;
uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
const uint8_t *ff_buf = f->buffer + rd_ptr;
#if CFG_TUSB_FIFO_HWFIFO_API
if (data_stride) {
volatile void *hwfifo = (volatile void *)app_buf;
volatile void *hwfifo = (volatile void *)app_buf;
if (n <= lin_bytes) {
// Linear only case
tu_hwfifo_write_access_mode(hwfifo, ff_buf, n, data_stride);
if (n <= lin_bytes) {
// Linear only case
tu_hwfifo_write(hwfifo, ff_buf, n, data_stride);
} else {
// Wrap around case
// Read full words from linear part
const uint32_t odd_mask = data_stride - 1;
uint16_t lin_even = lin_bytes & ~odd_mask;
tu_hwfifo_write(hwfifo, ff_buf, lin_even, data_stride);
ff_buf += lin_even;
// There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
const uint8_t lin_odd = lin_bytes & odd_mask;
if (lin_odd > 0) {
const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
uint8_t buf_temp[4];
for (uint8_t i = 0; i < lin_odd; ++i) {
buf_temp[i] = ff_buf[i];
}
for (uint8_t i = 0; i < wrap_odd; ++i) {
buf_temp[lin_odd + i] = f->buffer[i];
}
tu_hwfifo_write(hwfifo, buf_temp, lin_odd + wrap_odd, data_stride);
wrap_bytes -= wrap_odd;
ff_buf = f->buffer + wrap_odd; // wrap around
} else {
// Wrap around case
// Read full words from linear part
const uint32_t odd_mask = data_stride - 1;
uint16_t lin_even = lin_bytes & ~odd_mask;
tu_hwfifo_write_access_mode(hwfifo, ff_buf, lin_even, data_stride);
ff_buf += lin_even;
// There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
const uint8_t lin_odd = lin_bytes & odd_mask;
if (lin_odd > 0) {
const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
const uint32_t scatter = tu_scatter_read32(ff_buf, lin_odd, f->buffer, wrap_odd);
stride_write(hwfifo, &scatter, data_stride);
HWFIFO_ADDR_NEXT(, hwfifo);
wrap_bytes -= wrap_odd;
ff_buf = f->buffer + wrap_odd; // wrap around
} else {
ff_buf = f->buffer; // wrap around to beginning
}
// Read data wrapped part
if (wrap_bytes > 0) {
tu_hwfifo_write_access_mode(hwfifo, ff_buf, wrap_bytes, data_stride);
}
ff_buf = f->buffer; // wrap around to beginning
}
} else
// Read data wrapped part
if (wrap_bytes > 0) {
tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, data_stride);
}
}
}
#endif
{
// single byte access
if (n <= lin_bytes) {
// Linear only
memcpy(app_buf, ff_buf, n);
} else {
// Wrap around
memcpy(app_buf, ff_buf, lin_bytes); // linear part
memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
}
// send n items to fifo WITHOUT updating write pointer
static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
uint16_t lin_bytes = f->depth - wr_ptr;
uint16_t wrap_bytes = n - lin_bytes;
uint8_t *ff_buf = f->buffer + wr_ptr;
if (n <= lin_bytes) {
// Linear only case
memcpy(ff_buf, app_buf, n);
} else {
// Wrap around case
memcpy(ff_buf, app_buf, lin_bytes); // linear part
memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
}
}
// get n items from fifo WITHOUT updating read pointer
static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr) {
uint16_t lin_bytes = f->depth - rd_ptr;
uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
const uint8_t *ff_buf = f->buffer + rd_ptr;
// single byte access
if (n <= lin_bytes) {
// Linear only
memcpy(app_buf, ff_buf, n);
} else {
// Wrap around
memcpy(app_buf, ff_buf, lin_bytes); // linear part
memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
}
}
@ -385,7 +393,15 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
ff_pull_n(f, p_buffer, n, rd_ptr, data_stride);
#if CFG_TUSB_FIFO_HWFIFO_API
if (data_stride > 0) {
hwff_pull_n(f, p_buffer, n, rd_ptr, data_stride);
} else
#endif
{
ff_pull_n(f, p_buffer, n, rd_ptr);
}
return n;
}
@ -473,7 +489,14 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
ff_push_n(f, buf8, n, wr_ptr, data_stride);
#if CFG_TUSB_FIFO_HWFIFO_API
if (data_stride > 0) {
hwff_push_n(f, buf8, n, wr_ptr, data_stride);
} else
#endif
{
ff_push_n(f, buf8, n, wr_ptr);
}
f->wr_idx = advance_index(f->depth, wr_idx, n);
TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx);

View File

@ -129,7 +129,6 @@ typedef struct {
osal_mutex_t mutex_wr;
osal_mutex_t mutex_rd;
#endif
} tu_fifo_t;
typedef struct {
@ -237,21 +236,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_read_to_fifo(const volati
}
#if CFG_TUSB_FIFO_HWFIFO_API
// read from hwfifo to buffer with access mode
void tu_hwfifo_read_access_mode(const volatile void *hwfifo, uint8_t *dest, uint16_t len, uint8_t data_stride);
// read from hwfifo to buffer with default data stride
TU_ATTR_ALWAYS_INLINE static inline void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len) {
tu_hwfifo_read_access_mode(hwfifo, dest, len, CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE);
}
// read from hwfifo to buffer
void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, uint8_t data_stride);
// write to hwfifo from buffer with access mode
void tu_hwfifo_write_access_mode(volatile void *hwfifo, const uint8_t *src, uint16_t len, uint8_t data_stride);
void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, uint8_t data_stride);
// write to hwfifo from buffer with default data stride
TU_ATTR_ALWAYS_INLINE static inline void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len) {
tu_hwfifo_write_access_mode(hwfifo, src, len, CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE);
}
#endif
//--------------------------------------------------------------------+