From 2a1b81e3c50f5e37530c8318b7fb7767ba771979 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 6 Jan 2023 11:51:17 +0700 Subject: [PATCH] minimize tu_fifo size to 16 - remove non_used_index_space - packed overwritable with item_size --- src/common/tusb_fifo.c | 37 ++++++++++++++++++------------------- src/common/tusb_fifo.h | 40 +++++++++++++++++++--------------------- src/device/usbd.c | 2 ++ 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index d3875a7d4..4dfe7bd81 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -68,22 +68,19 @@ typedef enum bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable) { - if (depth > 0x8000) return false; // Maximum depth is 2^15 items + // Limit index space to 2*depth - this allows for a fast "modulo" calculation + // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable + // only if overflow happens once (important for unsupervised DMA applications) + if (depth > 0x8000) return false; _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->buffer = (uint8_t*) buffer; - f->depth = depth; - f->item_size = item_size; + f->buffer = (uint8_t*) buffer; + f->depth = depth; + f->item_size = (uint16_t) (item_size & 0x7FFF); f->overwritable = overwritable; - // Limit index space to 2*depth - this allows for a fast "modulo" calculation - // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable - // only if overflow happens once (important for unsupervised DMA applications) - //f->max_pointer_idx = (uint16_t) (2*depth - 1); - f->non_used_index_space = (uint16_t) (UINT16_MAX - (2*f->depth-1)); - f->rd_idx = f->wr_idx = 0; _ff_unlock(f->mutex_wr); @@ -331,7 +328,8 @@ static uint16_t advance_pointer(tu_fifo_t* f, uint16_t idx, uint16_t offset) uint16_t next_p = (uint16_t) (idx + offset); if ( (idx > next_p) || (next_p >= 2*f->depth) ) { - next_p = (uint16_t) (next_p + f->non_used_index_space); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*f->depth-1)); + next_p = (uint16_t) (next_p + non_used_index_space); } return next_p; @@ -346,7 +344,8 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) uint16_t new_p = (uint16_t) (p - offset); if ( (p < new_p) || (new_p >= 2*f->depth) ) { - new_p = (uint16_t) (new_p - f->non_used_index_space); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*f->depth-1)); + new_p = (uint16_t) (new_p - non_used_index_space); } return new_p; @@ -363,13 +362,15 @@ static inline uint16_t idx2ptr(uint16_t idx, uint16_t depth) // Works on local copies of w and r - return only the difference and as such can be used to determine an overflow static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = (uint16_t) (wr_idx-rd_idx); + uint16_t cnt; // In case we have non-power of two depth we need a further modification - if (rd_idx > wr_idx) + if (wr_idx >= rd_idx) { - // 2*f->depth - (rd_idx - wr_idx); - cnt = (uint16_t) (cnt - f->non_used_index_space); + cnt = (uint16_t) (wr_idx - rd_idx); + } else + { + cnt = (uint16_t) (2*f->depth - (rd_idx - wr_idx)); } return cnt; @@ -395,7 +396,7 @@ static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) // use DMAs, write functions do not allow such an error. static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) { - return (_tu_fifo_count(f, wr_idx, rd_idx) > f->depth); + return _tu_fifo_count(f, wr_idx, rd_idx) > f->depth; } // Works on local copies of w @@ -868,8 +869,6 @@ bool tu_fifo_clear(tu_fifo_t *f) _ff_lock(f->mutex_rd); f->rd_idx = f->wr_idx = 0; - //f->max_pointer_idx = (uint16_t) (2*f->depth-1); - f->non_used_index_space = (uint16_t) (UINT16_MAX - (2*f->depth-1)); _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index f72ff295b..2f60ec2f4 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -69,8 +69,8 @@ extern "C" { * | 0 | 1 | W | 3 | 4 | R | * * - Number of items in the fifo can be determined in either cases: - * - case W > R: Count = W - R - * - case W < R: Count = 2*depth - (R - W) + * - case W >= R: Count = W - R + * - case W < R: Count = 2*depth - (R - W) * * In non-overwritable mode, computed Count (in above 2 cases) is at most equal to depth. * However, in over-writable mode, write index can be repeatedly increased and count can be @@ -82,10 +82,10 @@ extern "C" { * ------------------------- * | R | 1 | 2 | 3 | W | 5 | * - * - Double Overflowed i.e index is out of allowed range [0,2*depth) e.g: + * - Double Overflowed i.e index is out of allowed range [0,2*depth) + * This occurs when we continue to write after 1st overflowed to 2nd overflowed. e.g: * write(3), write(1), write(2) - * Continue to write after overflowed to 2nd overflowed. - * We must prevent 2nd overflowed since it will cause incorrect computed of count, in above example + * This must be prevented since it will cause unrecoverable state, in above example * if not handled the fifo will be empty instead of continue-to-be full. Since we must not modify * read index in write() function, which cause race condition. We will re-position write index so that * after data is written it is a full fifo i.e W = depth - R @@ -106,17 +106,16 @@ extern "C" { */ typedef struct { - uint8_t* buffer ; ///< buffer pointer - uint16_t depth ; ///< max items - uint16_t item_size ; ///< size of each item + uint8_t* buffer ; // buffer pointer + uint16_t depth ; // max items - bool overwritable ; + struct TU_ATTR_PACKED { + uint16_t item_size : 15; // size of each item + bool overwritable : 1 ; // ovwerwritable when full + }; - uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length - //uint16_t max_pointer_idx ; ///< maximum absolute pointer index - - volatile uint16_t wr_idx ; ///< write index - volatile uint16_t rd_idx ; ///< read index + volatile uint16_t wr_idx ; // write index + volatile uint16_t rd_idx ; // read index #if OSAL_MUTEX_REQUIRED osal_mutex_t mutex_wr; @@ -133,13 +132,12 @@ typedef struct void * ptr_wrap ; ///< wrapped part start pointer } tu_fifo_buffer_info_t; -#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ -{ \ - .buffer = _buffer, \ - .depth = _depth, \ - .item_size = sizeof(_type), \ - .overwritable = _overwritable, \ - .non_used_index_space = (uint16_t)(UINT16_MAX - (2*(_depth)-1)), \ +#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \ +{ \ + .buffer = _buffer, \ + .depth = _depth, \ + .item_size = sizeof(_type), \ + .overwritable = _overwritable, \ } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ diff --git a/src/device/usbd.c b/src/device/usbd.c index f652a878e..6e0c6710d 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -388,6 +388,8 @@ bool tud_init (uint8_t rhport) TU_LOG(USBD_DBG, "USBD init on controller %u\r\n", rhport); TU_LOG_INT(USBD_DBG, sizeof(usbd_device_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_fifo_t)); + TU_LOG_INT(USBD_DBG, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev);