From 3e32fa36b86c502a35341f7f1aba62b89dae8fcb Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 8 Dec 2022 16:39:24 +0700 Subject: enhance tu fifo - rename wr/rd absolute to index, and rel to pointer. - fix crash with _tu_fifo_remaining() - change get_relative_pointer() to idx2ptr() and merge with _ff_mod() --- src/common/tusb_fifo.c | 205 +++++++++++++++++++++++++++++-------------------- src/common/tusb_fifo.h | 6 +- 2 files changed, 124 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index b857c6444..853614d28 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -34,6 +34,8 @@ #pragma diag_suppress = Pa082 #endif +#define TU_FIFO_DBG 0 + // implement mutex lock and unlock #if CFG_FIFO_MUTEX @@ -90,12 +92,9 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si return true; } -// Static functions are intended to work on local variables -static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth) -{ - while ( idx >= depth) idx -= depth; - return idx; -} +//--------------------------------------------------------------------+ +// Pull & Push +//--------------------------------------------------------------------+ // Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address // Code adapted from dcd_synopsys.c @@ -179,7 +178,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Write data to linear part of buffer memcpy(ff_buf, app_buf, nLin_bytes); - // Write data wrapped around + TU_ASSERT(nWrap_bytes <= f->depth, ); memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); } break; @@ -317,21 +316,24 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } } +//--------------------------------------------------------------------+ +// Index (free-running and real buffer pointer) +//--------------------------------------------------------------------+ + // Advance an absolute pointer +// "absolute" index is only in the range of [0..2*depth) static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx)) - { - p = (uint16_t) ((p + offset) + f->non_used_index_space); - } - else + uint16_t next_p = (uint16_t) (p + offset); + if ( (p > next_p) || (next_p > f->max_pointer_idx) ) { - p += offset; + next_p = (uint16_t) (next_p + f->non_used_index_space); } - return p; + + return next_p; } // Backward an absolute pointer @@ -340,30 +342,33 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx)) - { - p = (uint16_t) ((p - offset) - f->non_used_index_space); - } - else + uint16_t new_p = (uint16_t) (p - offset); + if ( (p < new_p) || (new_p > f->max_pointer_idx) ) { - p -= offset; + new_p = (uint16_t) (new_p - f->non_used_index_space); } - return p; + + return new_p; } -// get relative from absolute pointer -static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p) +// index to pointer, simply an modulo with minus +static inline uint16_t idx2ptr(uint16_t idx, uint16_t depth) { - return _ff_mod(p, f->depth); + while ( idx >= depth ) idx -= depth; + return idx; } // 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 wAbs, uint16_t rAbs) +static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = wAbs-rAbs; + uint16_t cnt = (uint16_t) (wr_idx-rd_idx); // In case we have non-power of two depth we need a further modification - if (rAbs > wAbs) cnt -= f->non_used_index_space; + if (rd_idx > wr_idx) + { + // 2*f->depth - (rd_idx - wr_idx); + cnt = (uint16_t) (cnt - f->non_used_index_space); + } return cnt; } @@ -400,39 +405,39 @@ static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs) +static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); // Check overflow and correct if required if (cnt > f->depth) { - _tu_fifo_correct_read_pointer(f, wAbs); + _tu_fifo_correct_read_pointer(f, wr_idx); cnt = f->depth; } // Skip beginning of buffer if (cnt == 0) return false; - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); // Peek data - _ff_pull(f, p_buffer, rRel); + _ff_pull(f, p_buffer, rd_ptr); return true; } // Works on local copies of w and r // Must be protected by mutexes since in case of an overflow read pointer gets modified -static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode) +static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs); + uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); // Check overflow and correct if required if (cnt > f->depth) { - _tu_fifo_correct_read_pointer(f, wAbs); - rAbs = f->rd_idx; + _tu_fifo_correct_read_pointer(f, wr_idx); + rd_idx = f->rd_idx; cnt = f->depth; } @@ -442,53 +447,80 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 // Check if we can read something at and after offset - if too less is available we read what remains if (cnt < n) n = cnt; - uint16_t rRel = get_relative_pointer(f, rAbs); + uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); // Peek data - _ff_pull_n(f, p_buffer, n, rRel, copy_mode); + _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); return n; } // Works on local copies of w and r -static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) { - return f->depth - _tu_fifo_count(f, wAbs, rAbs); + uint16_t const count = _tu_fifo_count(f, wr_idx, rd_idx); + return (f->depth > count) ? (f->depth - count) : 0; } static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { if ( n == 0 ) return 0; + TU_LOG(TU_FIFO_DBG, "rd = %u, wr = %02u, n = %u: ", f->rd_idx, f->wr_idx, n); + _ff_lock(f->mutex_wr); - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint8_t const* buf8 = (uint8_t const*) data; + uint16_t const remain = _tu_fifo_remaining(f, wr_idx, rd_idx); - if (!f->overwritable) + if ( n > remain) { - // Not overwritable limit up to full - n = tu_min16(n, _tu_fifo_remaining(f, w, r)); + if ( !f->overwritable ) + { + // limit up to full + n = remain; + } + else + { + // oldest data in fifo i.e read pointer data will be overwritten + // Note: we modify read data but we do not want to modify the read pointer within a write function! + // since it would end up in a race condition with read functions! + // Note2: race condition could still occur if tu_fifo_read() is called while we modify its buffer (corrupted data) + + if ( n >= f->depth ) + { + // Only copy last part + buf8 = buf8 + (n - f->depth) * f->item_size; + n = f->depth; + + // We start writing at the read pointer's position since we fill the complete + // buffer and we do not want to modify the read pointer within a write function! + // This would end up in a race condition with read functions! + wr_idx = rd_idx; + }else + { + // TODO shift out oldest data from read pointer !!! + } + } } - else if (n >= f->depth) + + if (n) { - // Only copy last part - buf8 = buf8 + (n - f->depth) * f->item_size; - n = f->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - w = r; - } + uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); - uint16_t wRel = get_relative_pointer(f, w); + TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_rel = %u", n, wr_ptr); - // Write data - _ff_push_n(f, buf8, n, wRel, copy_mode); + // Write data + _ff_push_n(f, buf8, n, wr_ptr, copy_mode); - // Advance pointer - f->wr_idx = advance_pointer(f, w, n); + // Advance pointer + f->wr_idx = advance_pointer(f, wr_idx, n); + + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + } _ff_unlock(f->mutex_wr); @@ -742,20 +774,20 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) _ff_lock(f->mutex_wr); bool ret; - uint16_t const w = f->wr_idx; + uint16_t const wr_idx = f->wr_idx; - if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) + if ( _tu_fifo_full(f, wr_idx, f->rd_idx) && !f->overwritable ) { ret = false; }else { - uint16_t wRel = get_relative_pointer(f, w); + uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); // Write data - _ff_push(f, data, wRel); + _ff_push(f, data, wr_ptr); // Advance pointer - f->wr_idx = advance_pointer(f, w, 1); + f->wr_idx = advance_pointer(f, wr_idx, 1); ret = true; } @@ -909,17 +941,19 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { // Operate on temporary values in case they change in between - uint16_t w = f->wr_idx, r = f->rd_idx; + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _tu_fifo_count(f, w, r); + uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, w); + _tu_fifo_correct_read_pointer(f, wr_idx); _ff_unlock(f->mutex_rd); - r = f->rd_idx; + + rd_idx = f->rd_idx; cnt = f->depth; } @@ -934,22 +968,24 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); + uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); // Copy pointer to buffer to start reading from - info->ptr_lin = &f->buffer[r]; + info->ptr_lin = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary - if (w > r) { + if (wr_ptr > rd_ptr) { // Non wrapping case info->len_lin = cnt; + info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - r; // Also the case if FIFO was full + info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + info->len_wrap = cnt - info->len_lin; info->ptr_wrap = f->buffer; } @@ -972,10 +1008,11 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) /******************************************************************************/ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { - uint16_t w = f->wr_idx, r = f->rd_idx; - uint16_t free = _tu_fifo_remaining(f, w, r); + uint16_t wr_idx = f->wr_idx; + uint16_t rd_idx = f->rd_idx; + uint16_t remain = _tu_fifo_remaining(f, wr_idx, rd_idx); - if (free == 0) + if (remain == 0) { info->len_lin = 0; info->len_wrap = 0; @@ -985,23 +1022,23 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - w = get_relative_pointer(f, w); - r = get_relative_pointer(f, r); + uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); + uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); // Copy pointer to buffer to start writing to - info->ptr_lin = &f->buffer[w]; + info->ptr_lin = &f->buffer[wr_ptr]; - if (w < r) + if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = r-w; + info->len_lin = rd_ptr-wr_ptr; info->len_wrap = 0; info->ptr_wrap = NULL; } else { - info->len_lin = f->depth - w; - info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth - info->ptr_wrap = f->buffer; // Always start of buffer + info->len_lin = f->depth - wr_ptr; + info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth + info->ptr_wrap = f->buffer; // Always start of buffer } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index e64ab4b6d..204d53081 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -101,10 +101,10 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si #if CFG_FIFO_MUTEX TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl) +void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t wr_mutex, tu_fifo_mutex_t rd_mutex) { - f->mutex_wr = write_mutex_hdl; - f->mutex_rd = read_mutex_hdl; + f->mutex_wr = wr_mutex; + f->mutex_rd = rd_mutex; } #endif -- cgit v1.3.1 From 82852774a74631e0916254022339c9713c44cb57 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 9 Dec 2022 18:20:09 +0700 Subject: add fifo implementation note - handle/fix double overflowed with write() - other minor clean upp --- src/common/tusb_fifo.c | 94 +++++++++++++++++++++++++++++--------------------- src/common/tusb_fifo.h | 63 ++++++++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 853614d28..df07a990c 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -81,8 +81,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si // 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_MAX - f->max_pointer_idx; + //f->max_pointer_idx = (uint16_t) (2*depth - 1); + f->non_used_index_space = UINT16_MAX - (2*f->depth-1); f->rd_idx = f->wr_idx = 0; @@ -320,15 +320,15 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Index (free-running and real buffer pointer) //--------------------------------------------------------------------+ -// Advance an absolute pointer +// Advance an absolute index // "absolute" index is only in the range of [0..2*depth) -static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +static uint16_t advance_pointer(tu_fifo_t* f, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - uint16_t next_p = (uint16_t) (p + offset); - if ( (p > next_p) || (next_p > f->max_pointer_idx) ) + 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); } @@ -343,7 +343,7 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index uint16_t new_p = (uint16_t) (p - offset); - if ( (p < new_p) || (new_p > f->max_pointer_idx) ) + if ( (p < new_p) || (new_p >= 2*f->depth) ) { new_p = (uint16_t) (new_p - f->non_used_index_space); } @@ -374,15 +374,15 @@ static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd } // Works on local copies of w and r -static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs) +static inline bool _tu_fifo_empty(uint16_t wr_idx, uint16_t rd_idx) { - return wAbs == rAbs; + return wr_idx == rd_idx; } // Works on local copies of w and r static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) { - return (_tu_fifo_count(f, wAbs, rAbs) == f->depth); + return _tu_fifo_count(f, wAbs, rAbs) == f->depth; } // Works on local copies of w and r @@ -391,9 +391,9 @@ static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) // write more than 2*depth-1 items in one rush without updating write pointer. Otherwise // write pointer wraps and you pointer states are messed up. This can only happen if you // use DMAs, write functions do not allow such an error. -static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) +static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) { - return (_tu_fifo_count(f, wAbs, rAbs) > f->depth); + return (_tu_fifo_count(f, wr_idx, rd_idx) > f->depth); } // Works on local copies of w @@ -466,44 +466,58 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu { if ( n == 0 ) return 0; - TU_LOG(TU_FIFO_DBG, "rd = %u, wr = %02u, n = %u: ", f->rd_idx, f->wr_idx, n); - _ff_lock(f->mutex_wr); uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; uint8_t const* buf8 = (uint8_t const*) data; + uint16_t overflowable_count = _tu_fifo_count(f, wr_idx, rd_idx); uint16_t const remain = _tu_fifo_remaining(f, wr_idx, rd_idx); - if ( n > remain) + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, _tu_fifo_count(f, wr_idx, rd_idx), remain, n); + + if ( !f->overwritable ) { - if ( !f->overwritable ) - { - // limit up to full - n = remain; - } - else + // limit up to full + n = tu_min16(n, remain); + } + else + { + // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, + // oldest data in fifo i.e at read pointer data will be overwritten + // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! + // Since it would end up in a race condition with read functions! + if ( n >= f->depth ) { - // oldest data in fifo i.e read pointer data will be overwritten - // Note: we modify read data but we do not want to modify the read pointer within a write function! - // since it would end up in a race condition with read functions! - // Note2: race condition could still occur if tu_fifo_read() is called while we modify its buffer (corrupted data) - - if ( n >= f->depth ) + // Only copy last part + if ( copy_mode == TU_FIFO_COPY_INC ) { - // Only copy last part - buf8 = buf8 + (n - f->depth) * f->item_size; - n = f->depth; - - // We start writing at the read pointer's position since we fill the complete - // buffer and we do not want to modify the read pointer within a write function! - // This would end up in a race condition with read functions! - wr_idx = rd_idx; + buf8 += (n - f->depth) * f->item_size; }else { - // TODO shift out oldest data from read pointer !!! + // TODO should read from hw fifo to discard data, however reading an odd number could + // accidentally discard data. } + + n = f->depth; + + // We start writing at the read pointer's position since we fill the whole buffer + wr_idx = rd_idx; + }else if (overflowable_count + n >= 2*f->depth) + { + // Double overflowed + // re-position write index to have a full fifo after pushed + wr_idx = advance_pointer(f, rd_idx, f->depth - n); + + // TODO we should also shift out n bytes from read index since we avoid changing rd index !! + // However memmove() is expensive due to actual copying + wrapping consideration. + // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory + // currently deliberately not implemented --> result in incorrect data read back + }else + { + // normal + single overflowed: just increase write index + // we will correct (re-position) read index later on in fifo_read() function } } @@ -511,12 +525,12 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu { uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); - TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_rel = %u", n, wr_ptr); + TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); // Write data _ff_push_n(f, buf8, n, wr_ptr, copy_mode); - // Advance pointer + // Advance index f->wr_idx = advance_pointer(f, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); @@ -850,8 +864,8 @@ 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_MAX - f->max_pointer_idx; + //f->max_pointer_idx = (uint16_t) (2*f->depth-1); + f->non_used_index_space = 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 204d53081..fd149b75c 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -52,18 +52,74 @@ extern "C" { #define tu_fifo_mutex_t osal_mutex_t #endif +/* Write/Read index is always in the range of: + * 0 .. 2*depth-1 + * The extra window allow us to determine the fifo state of empty or full with only 2 indexes + * Following are examples with depth = 3 + * + * - empty: W = R + * | + * ------------------------- + * | 0 | RW| 2 | 3 | 4 | 5 | + * + * - full 1: W > R + * | + * ------------------------- + * | 0 | R | 2 | 3 | W | 5 | + * + * - full 2: W < R + * | + * ------------------------- + * | 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) + * + * 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 + * temporarily larger than depth (overflowed condition) e.g + * + * - Overflowed 1: write(3), write(1) + * In this case we will adjust Read index when read()/peek() is called so that count = depth. + * | + * ------------------------- + * | R | 1 | 2 | 3 | W | 5 | + * + * - Double Overflowed: 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 + * 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 + * + * re-position W = 1 before write(2) + * Note: we should also move data from mem[4] to read index as well, but deliberately skipped here + * since it is an expensive operation !!! + * | + * ------------------------- + * | R | W | 2 | 3 | 4 | 5 | + * + * perform write(2), result is still a full fifo. + * + * | + * ------------------------- + * | R | 1 | 2 | W | 4 | 5 | + + */ typedef struct { uint8_t* buffer ; ///< buffer pointer uint16_t depth ; ///< max items uint16_t item_size ; ///< size of each item + bool overwritable ; uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length - uint16_t max_pointer_idx ; ///< maximum absolute pointer index + //uint16_t max_pointer_idx ; ///< maximum absolute pointer index - volatile uint16_t wr_idx ; ///< write pointer - volatile uint16_t rd_idx ; ///< read pointer + volatile uint16_t wr_idx ; ///< write index + volatile uint16_t rd_idx ; ///< read index #if CFG_FIFO_MUTEX tu_fifo_mutex_t mutex_wr; @@ -87,7 +143,6 @@ typedef struct .item_size = sizeof(_type), \ .overwritable = _overwritable, \ .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \ - .max_pointer_idx = 2*(_depth)-1, \ } #define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \ -- cgit v1.3.1 From ce064de6fd4416bb5368a2aaff4283f8e4b9fc36 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 10 Dec 2022 00:18:11 +0700 Subject: clean up --- src/common/tusb_fifo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index df07a990c..a3933416c 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -178,7 +178,8 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Write data to linear part of buffer memcpy(ff_buf, app_buf, nLin_bytes); - TU_ASSERT(nWrap_bytes <= f->depth, ); + // Write data wrapped around + // TU_ASSERT(nWrap_bytes <= f->depth, ); memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); } break; @@ -504,7 +505,8 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // We start writing at the read pointer's position since we fill the whole buffer wr_idx = rd_idx; - }else if (overflowable_count + n >= 2*f->depth) + } + else if (overflowable_count + n >= 2*f->depth) { // Double overflowed // re-position write index to have a full fifo after pushed -- cgit v1.3.1 From 04a5c03ea8ea70510c332f0fafb44daf0ec7c7fb Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 12 Dec 2022 11:54:33 +0700 Subject: fix int conversion warnings --- src/common/tusb_fifo.c | 4 ++-- src/common/tusb_fifo.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a3933416c..70f514df2 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -82,7 +82,7 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si // 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_MAX - (2*f->depth-1); + f->non_used_index_space = (uint16_t) (UINT16_MAX - (2*f->depth-1)); f->rd_idx = f->wr_idx = 0; @@ -867,7 +867,7 @@ bool tu_fifo_clear(tu_fifo_t *f) f->rd_idx = f->wr_idx = 0; //f->max_pointer_idx = (uint16_t) (2*f->depth-1); - f->non_used_index_space = UINT16_MAX - (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 fd149b75c..932214c81 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -136,13 +136,13 @@ 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_MAX - (2*(_depth)-1), \ +#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_DEF(_name, _depth, _type, _overwritable) \ -- cgit v1.3.1 From 660343d2001c0ee943bf3e24cab6f235d3930b33 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Dec 2022 16:55:25 +0700 Subject: update fifo per PanRe review --- src/common/tusb_fifo.c | 8 ++++++-- src/common/tusb_fifo.h | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 70f514df2..bbdd82982 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -352,9 +352,10 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) return new_p; } -// index to pointer, simply an modulo with minus +// index to pointer, simply an modulo with minus. static inline uint16_t idx2ptr(uint16_t idx, uint16_t depth) { + // Only run at most 3 times since index is limit in the range of [0..2*depth) while ( idx >= depth ) idx -= depth; return idx; } @@ -509,6 +510,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu else if (overflowable_count + n >= 2*f->depth) { // Double overflowed + // Index is bigger than the allowed range [0,2*depth) // re-position write index to have a full fifo after pushed wr_idx = advance_pointer(f, rd_idx, f->depth - n); @@ -518,7 +520,9 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // currently deliberately not implemented --> result in incorrect data read back }else { - // normal + single overflowed: just increase write index + // normal + single overflowed: + // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() + // Therefore we just increase write index // we will correct (re-position) read index later on in fifo_read() function } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 932214c81..972d29d50 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -54,7 +54,7 @@ extern "C" { /* Write/Read index is always in the range of: * 0 .. 2*depth-1 - * The extra window allow us to determine the fifo state of empty or full with only 2 indexes + * The extra window allow us to determine the fifo state of empty or full with only 2 indices * Following are examples with depth = 3 * * - empty: W = R @@ -86,7 +86,8 @@ extern "C" { * ------------------------- * | R | 1 | 2 | 3 | W | 5 | * - * - Double Overflowed: write(3), write(1), write(2) + * - Double Overflowed i.e index is out of allowed range [0,2*depth) 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 * if not handled the fifo will be empty instead of continue-to-be full. Since we must not modify @@ -94,7 +95,7 @@ extern "C" { * after data is written it is a full fifo i.e W = depth - R * * re-position W = 1 before write(2) - * Note: we should also move data from mem[4] to read index as well, but deliberately skipped here + * Note: we should also move data from mem[3] to read index as well, but deliberately skipped here * since it is an expensive operation !!! * | * ------------------------- -- cgit v1.3.1 From 9c73c1a532649630de5e55400632bcca90ebea06 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 6 Jan 2023 10:56:19 +0700 Subject: minor clean up --- src/common/tusb_fifo.c | 4 ++-- src/common/tusb_fifo.h | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 6862a6f43..d3875a7d4 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -39,12 +39,12 @@ // implement mutex lock and unlock #if CFG_FIFO_MUTEX -static inline void _ff_lock(tu_fifo_mutex_t mutex) +static inline void _ff_lock(osal_mutex_t mutex) { if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } -static inline void _ff_unlock(tu_fifo_mutex_t mutex) +static inline void _ff_unlock(osal_mutex_t mutex) { if (mutex) osal_mutex_unlock(mutex); } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index f1810e39c..f72ff295b 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -44,8 +44,6 @@ extern "C" { #include "common/tusb_common.h" #include "osal/osal.h" -#define tu_fifo_mutex_t osal_mutex_t - // mutex is only needed for RTOS // for OS None, we don't get preempted #define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED @@ -121,8 +119,8 @@ typedef struct volatile uint16_t rd_idx ; ///< read index #if OSAL_MUTEX_REQUIRED - tu_fifo_mutex_t mutex_wr; - tu_fifo_mutex_t mutex_rd; + osal_mutex_t mutex_wr; + osal_mutex_t mutex_rd; #endif } tu_fifo_t; @@ -155,7 +153,7 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si #if OSAL_MUTEX_REQUIRED TU_ATTR_ALWAYS_INLINE static inline -void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t wr_mutex, tu_fifo_mutex_t rd_mutex) +void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) { f->mutex_wr = wr_mutex; f->mutex_rd = rd_mutex; -- cgit v1.3.1 From 2a1b81e3c50f5e37530c8318b7fb7767ba771979 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 6 Jan 2023 11:51:17 +0700 Subject: 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(-) (limited to 'src') 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) + { + cnt = (uint16_t) (wr_idx - rd_idx); + } else { - // 2*f->depth - (rd_idx - wr_idx); - cnt = (uint16_t) (cnt - f->non_used_index_space); + 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); -- cgit v1.3.1 From 82457519fa050b2efd1b462ba88f7f258047c715 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 6 Jan 2023 12:11:55 +0700 Subject: minor clean up --- src/common/tusb_fifo.c | 68 ++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 4dfe7bd81..f72c8a12f 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -28,16 +28,15 @@ #include "osal/osal.h" #include "tusb_fifo.h" +#define TU_FIFO_DBG 0 + // Suppress IAR warning // Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement #if defined(__ICCARM__) #pragma diag_suppress = Pa082 #endif -#define TU_FIFO_DBG 0 - -// implement mutex lock and unlock -#if CFG_FIFO_MUTEX +#if OSAL_MUTEX_REQUIRED static inline void _ff_lock(osal_mutex_t mutex) { @@ -80,8 +79,8 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si f->depth = depth; f->item_size = (uint16_t) (item_size & 0x7FFF); f->overwritable = overwritable; - - f->rd_idx = f->wr_idx = 0; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -142,13 +141,13 @@ static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t } } -// send one item to FIFO WITHOUT updating write pointer +// send one item to fifo WITHOUT updating write pointer static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) { memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); } -// send n items to FIFO WITHOUT updating write pointer +// send n items to fifo WITHOUT updating write pointer static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) { uint16_t const nLin = f->depth - rel; @@ -227,13 +226,13 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t } } -// get one item from FIFO WITHOUT updating read pointer +// get one item from fifo WITHOUT updating read pointer static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) { memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); } -// get n items from FIFO WITHOUT updating read pointer +// get n items from fifo WITHOUT updating read pointer static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) { uint16_t const nLin = f->depth - rel; @@ -475,14 +474,14 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu uint16_t rd_idx = f->rd_idx; uint8_t const* buf8 = (uint8_t const*) data; - uint16_t overflowable_count = _tu_fifo_count(f, wr_idx, rd_idx); - uint16_t const remain = _tu_fifo_remaining(f, wr_idx, rd_idx); - TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, _tu_fifo_count(f, wr_idx, rd_idx), remain, n); + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", + rd_idx, wr_idx, _tu_fifo_count(f, wr_idx, rd_idx), _tu_fifo_remaining(f, wr_idx, rd_idx), n); if ( !f->overwritable ) { // limit up to full + uint16_t const remain = _tu_fifo_remaining(f, wr_idx, rd_idx); n = tu_min16(n, remain); } else @@ -508,23 +507,27 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // We start writing at the read pointer's position since we fill the whole buffer wr_idx = rd_idx; } - else if (overflowable_count + n >= 2*f->depth) - { - // Double overflowed - // Index is bigger than the allowed range [0,2*depth) - // re-position write index to have a full fifo after pushed - wr_idx = advance_pointer(f, rd_idx, f->depth - n); - - // TODO we should also shift out n bytes from read index since we avoid changing rd index !! - // However memmove() is expensive due to actual copying + wrapping consideration. - // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory - // currently deliberately not implemented --> result in incorrect data read back - }else + else { - // normal + single overflowed: - // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() - // Therefore we just increase write index - // we will correct (re-position) read index later on in fifo_read() function + uint16_t const overflowable_count = _tu_fifo_count(f, wr_idx, rd_idx); + if (overflowable_count + n >= 2*f->depth) + { + // Double overflowed + // Index is bigger than the allowed range [0,2*depth) + // re-position write index to have a full fifo after pushed + wr_idx = advance_pointer(f, rd_idx, f->depth - n); + + // TODO we should also shift out n bytes from read index since we avoid changing rd index !! + // However memmove() is expensive due to actual copying + wrapping consideration. + // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory + // currently deliberately not implemented --> result in incorrect data read back + }else + { + // normal + single overflowed: + // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read() + // Therefore we just increase write index + // we will correct (re-position) read index later on in fifo_read() function + } } } @@ -868,7 +871,8 @@ bool tu_fifo_clear(tu_fifo_t *f) _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); - f->rd_idx = f->wr_idx = 0; + f->rd_idx = 0; + f->wr_idx = 0; _ff_unlock(f->mutex_wr); _ff_unlock(f->mutex_rd); @@ -1031,9 +1035,9 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) if (remain == 0) { - info->len_lin = 0; + info->len_lin = 0; info->len_wrap = 0; - info->ptr_lin = NULL; + info->ptr_lin = NULL; info->ptr_wrap = NULL; return; } -- cgit v1.3.1 From a804a1ac09c34a4f69c0d2873a552a2a505d0492 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 16:48:07 +0700 Subject: simplify and remove _tu_fifo_empty, _tu_fifo_full. Also correct full condition check --- src/common/tusb_fifo.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index f72c8a12f..4b27bc589 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -38,12 +38,12 @@ #if OSAL_MUTEX_REQUIRED -static inline void _ff_lock(osal_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } -static inline void _ff_unlock(osal_mutex_t mutex) +TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { if (mutex) osal_mutex_unlock(mutex); } @@ -361,30 +361,14 @@ 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; - // In case we have non-power of two depth we need a further modification if (wr_idx >= rd_idx) { - cnt = (uint16_t) (wr_idx - rd_idx); + return (uint16_t) (wr_idx - rd_idx); } else { - cnt = (uint16_t) (2*f->depth - (rd_idx - wr_idx)); + return (uint16_t) (2*f->depth - (rd_idx - wr_idx)); } - - return cnt; -} - -// Works on local copies of w and r -static inline bool _tu_fifo_empty(uint16_t wr_idx, uint16_t rd_idx) -{ - return wr_idx == rd_idx; -} - -// Works on local copies of w and r -static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs) -{ - return _tu_fifo_count(f, wAbs, rAbs) == f->depth; } // Works on local copies of w and r @@ -601,7 +585,7 @@ uint16_t tu_fifo_count(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_empty(tu_fifo_t* f) { - return _tu_fifo_empty(f->wr_idx, f->rd_idx); + return f->wr_idx == f->rd_idx; } /******************************************************************************/ @@ -619,7 +603,7 @@ bool tu_fifo_empty(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_full(tu_fifo_t* f) { - return _tu_fifo_full(f, f->wr_idx, f->rd_idx); + return _tu_fifo_count(f, f->wr_idx, f->rd_idx) >= f->depth; } /******************************************************************************/ @@ -798,7 +782,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) bool ret; uint16_t const wr_idx = f->wr_idx; - if ( _tu_fifo_full(f, wr_idx, f->rd_idx) && !f->overwritable ) + if ( tu_fifo_full(f) && !f->overwritable ) { ret = false; }else -- cgit v1.3.1 From 507d5b10b049d865e5bb24f99038eed07d092e8f Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 17:14:17 +0700 Subject: simplify _tu_fifo_count() and _tu_fifo_remaining(), also rename to _ff_count() and _ff_remaining() --- src/common/tusb_fifo.c | 57 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 4b27bc589..cdb0df73f 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -358,8 +358,9 @@ static inline uint16_t idx2ptr(uint16_t idx, uint16_t depth) return idx; } -// 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) +// return only the index difference and as such can be used to determine an overflow i.e overflowable count +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { // In case we have non-power of two depth we need a further modification if (wr_idx >= rd_idx) @@ -367,24 +368,33 @@ static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd return (uint16_t) (wr_idx - rd_idx); } else { - return (uint16_t) (2*f->depth - (rd_idx - wr_idx)); + return (uint16_t) (2*depth - (rd_idx - wr_idx)); } } -// Works on local copies of w and r // BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" // Only one overflow is allowed for this function to work e.g. if depth = 100, you must not // write more than 2*depth-1 items in one rush without updating write pointer. Otherwise // write pointer wraps and you pointer states are messed up. This can only happen if you // 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) +TU_ATTR_ALWAYS_INLINE static inline +bool _ff_overflowed(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + return _ff_count(depth, wr_idx, rd_idx) > depth; +} + +// return remaining slot in fifo +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - return _tu_fifo_count(f, wr_idx, rd_idx) > f->depth; + uint16_t const count = _ff_count(depth, wr_idx, rd_idx); + return (depth > count) ? (depth - count) : 0; } // Works on local copies of w // For more details see _tu_fifo_overflow()! -static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) +TU_ATTR_ALWAYS_INLINE static inline +void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) { f->rd_idx = backward_pointer(f, wAbs, f->depth); } @@ -393,7 +403,7 @@ static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) // Must be protected by mutexes since in case of an overflow read pointer gets modified static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required if (cnt > f->depth) @@ -417,7 +427,7 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 // Must be protected by mutexes since in case of an overflow read pointer gets modified static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required if (cnt > f->depth) @@ -441,13 +451,6 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 return n; } -// Works on local copies of w and r -static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wr_idx, uint16_t rd_idx) -{ - uint16_t const count = _tu_fifo_count(f, wr_idx, rd_idx); - return (f->depth > count) ? (f->depth - count) : 0; -} - static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { if ( n == 0 ) return 0; @@ -460,12 +463,12 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu uint8_t const* buf8 = (uint8_t const*) data; TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", - rd_idx, wr_idx, _tu_fifo_count(f, wr_idx, rd_idx), _tu_fifo_remaining(f, wr_idx, rd_idx), n); + rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); if ( !f->overwritable ) { // limit up to full - uint16_t const remain = _tu_fifo_remaining(f, wr_idx, rd_idx); + uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx); n = tu_min16(n, remain); } else @@ -493,7 +496,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu } else { - uint16_t const overflowable_count = _tu_fifo_count(f, wr_idx, rd_idx); + uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); if (overflowable_count + n >= 2*f->depth) { // Double overflowed @@ -550,6 +553,10 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo return n; } +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + /******************************************************************************/ /*! @brief Get number of items in FIFO. @@ -567,7 +574,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo /******************************************************************************/ uint16_t tu_fifo_count(tu_fifo_t* f) { - return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth); + return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); } /******************************************************************************/ @@ -603,7 +610,7 @@ bool tu_fifo_empty(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_full(tu_fifo_t* f) { - return _tu_fifo_count(f, f->wr_idx, f->rd_idx) >= f->depth; + return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; } /******************************************************************************/ @@ -621,7 +628,7 @@ bool tu_fifo_full(tu_fifo_t* f) /******************************************************************************/ uint16_t tu_fifo_remaining(tu_fifo_t* f) { - return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx); + return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); } /******************************************************************************/ @@ -647,7 +654,7 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_overflowed(tu_fifo_t* f) { - return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx); + return _ff_overflowed(f->depth, f->wr_idx, f->rd_idx); } // Only use in case tu_fifo_overflow() returned true! @@ -949,7 +956,7 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _tu_fifo_count(f, wr_idx, rd_idx); + uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) @@ -1015,7 +1022,7 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t remain = _tu_fifo_remaining(f, wr_idx, rd_idx); + uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); if (remain == 0) { -- cgit v1.3.1 From 24bd1c95623377a81286f9d516da57c34451c515 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 17:27:26 +0700 Subject: update advance_pointer/backward_pointer to use depth instead of fifo, also rename to advance/backward_index --- src/common/tusb_fifo.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index cdb0df73f..8de58c4a4 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -319,35 +319,35 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Advance an absolute index // "absolute" index is only in the range of [0..2*depth) -static uint16_t advance_pointer(tu_fifo_t* f, uint16_t idx, uint16_t offset) +static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - uint16_t next_p = (uint16_t) (idx + offset); - if ( (idx > next_p) || (next_p >= 2*f->depth) ) + uint16_t new_idx = (uint16_t) (idx + offset); + if ( (idx > new_idx) || (new_idx >= 2*depth) ) { - 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); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx + non_used_index_space); } - return next_p; + return new_idx; } -// Backward an absolute pointer -static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset) +// Backward an absolute index +static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { // We limit the index space of p such that a correct wrap around happens // Check for a wrap around or if we are in unused index space - This has to be checked first!! // We are exploiting the wrap around to the correct index - uint16_t new_p = (uint16_t) (p - offset); - if ( (p < new_p) || (new_p >= 2*f->depth) ) + uint16_t new_idx = (uint16_t) (idx - offset); + if ( (idx < new_idx) || (new_idx >= 2*depth) ) { - 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); + uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); + new_idx = (uint16_t) (new_idx - non_used_index_space); } - return new_p; + return new_idx; } // index to pointer, simply an modulo with minus. @@ -394,9 +394,9 @@ uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) // Works on local copies of w // For more details see _tu_fifo_overflow()! TU_ATTR_ALWAYS_INLINE static inline -void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs) +void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wr_idx) { - f->rd_idx = backward_pointer(f, wAbs, f->depth); + f->rd_idx = backward_index(f->depth, wr_idx, f->depth); } // Works on local copies of w and r @@ -502,7 +502,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Double overflowed // Index is bigger than the allowed range [0,2*depth) // re-position write index to have a full fifo after pushed - wr_idx = advance_pointer(f, rd_idx, f->depth - n); + wr_idx = advance_index(f->depth, rd_idx, f->depth - n); // TODO we should also shift out n bytes from read index since we avoid changing rd index !! // However memmove() is expensive due to actual copying + wrapping consideration. @@ -528,7 +528,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu _ff_push_n(f, buf8, n, wr_ptr, copy_mode); // Advance index - f->wr_idx = advance_pointer(f, wr_idx, n); + f->wr_idx = advance_index(f->depth, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); } @@ -547,7 +547,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // Advance read pointer - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); _ff_unlock(f->mutex_rd); return n; @@ -690,7 +690,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer) bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx); // Advance pointer - f->rd_idx = advance_pointer(f, f->rd_idx, ret); + f->rd_idx = advance_index(f->depth, f->rd_idx, ret); _ff_unlock(f->mutex_rd); return ret; @@ -800,7 +800,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) _ff_push(f, data, wr_ptr); // Advance pointer - f->wr_idx = advance_pointer(f, wr_idx, 1); + f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } @@ -911,7 +911,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) /******************************************************************************/ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) { - f->wr_idx = advance_pointer(f, f->wr_idx, n); + f->wr_idx = advance_index(f->depth, f->wr_idx, n); } /******************************************************************************/ @@ -932,7 +932,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) /******************************************************************************/ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n) { - f->rd_idx = advance_pointer(f, f->rd_idx, n); + f->rd_idx = advance_index(f->depth, f->rd_idx, n); } /******************************************************************************/ -- cgit v1.3.1 From 248025bb6cdf361e93603204d89cbf58e9e3b0af Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 17:29:43 +0700 Subject: reverse idx2ptr() arguments to be consistent --- src/common/tusb_fifo.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 8de58c4a4..a0ce73ba0 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -351,7 +351,8 @@ static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) } // index to pointer, simply an modulo with minus. -static inline uint16_t idx2ptr(uint16_t idx, uint16_t depth) +TU_ATTR_ALWAYS_INLINE static inline +uint16_t idx2ptr(uint16_t depth, uint16_t idx) { // Only run at most 3 times since index is limit in the range of [0..2*depth) while ( idx >= depth ) idx -= depth; @@ -415,7 +416,7 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 // Skip beginning of buffer if (cnt == 0) return false; - uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data _ff_pull(f, p_buffer, rd_ptr); @@ -443,7 +444,7 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 // Check if we can read something at and after offset - if too less is available we read what remains if (cnt < n) n = cnt; - uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); @@ -520,7 +521,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu if (n) { - uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); @@ -794,7 +795,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data) ret = false; }else { - uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); // Write data _ff_push(f, data, wr_ptr); @@ -980,8 +981,8 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); - uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start reading from info->ptr_lin = &f->buffer[rd_ptr]; @@ -1034,8 +1035,8 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) } // Get relative pointers - uint16_t wr_ptr = idx2ptr(wr_idx, f->depth); - uint16_t rd_ptr = idx2ptr(rd_idx, f->depth); + uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start writing to info->ptr_lin = &f->buffer[wr_ptr]; -- cgit v1.3.1 From c29b7643a59f4baa266d13ef0a7bed864ad83eb2 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 18:50:19 +0700 Subject: simplify _ff_correct_read_index() --- src/common/tusb_fifo.c | 107 ++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a0ce73ba0..22d6e8e55 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -314,7 +314,44 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } //--------------------------------------------------------------------+ -// Index (free-running and real buffer pointer) +// Helper +//--------------------------------------------------------------------+ + +// return only the index difference and as such can be used to determine an overflow i.e overflowable count +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + // In case we have non-power of two depth we need a further modification + if (wr_idx >= rd_idx) + { + return (uint16_t) (wr_idx - rd_idx); + } else + { + return (uint16_t) (2*depth - (rd_idx - wr_idx)); + } +} + +// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" +// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not +// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise +// write pointer wraps and you pointer states are messed up. This can only happen if you +// use DMAs, write functions do not allow such an error. +TU_ATTR_ALWAYS_INLINE static inline +bool _ff_overflowed(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + return _ff_count(depth, wr_idx, rd_idx) > depth; +} + +// return remaining slot in fifo +TU_ATTR_ALWAYS_INLINE static inline +uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +{ + uint16_t const count = _ff_count(depth, wr_idx, rd_idx); + return (depth > count) ? (depth - count) : 0; +} + +//--------------------------------------------------------------------+ +// Index Helper //--------------------------------------------------------------------+ // Advance an absolute index @@ -334,6 +371,7 @@ static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) return new_idx; } +#if 0 // not used but // Backward an absolute index static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) { @@ -349,6 +387,7 @@ static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset) return new_idx; } +#endif // index to pointer, simply an modulo with minus. TU_ATTR_ALWAYS_INLINE static inline @@ -359,45 +398,24 @@ uint16_t idx2ptr(uint16_t depth, uint16_t idx) return idx; } -// return only the index difference and as such can be used to determine an overflow i.e overflowable count +// Works on local copies of w +// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms +// an full fifo i.e _ff_count() = depth TU_ATTR_ALWAYS_INLINE static inline -uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) +uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx) { - // In case we have non-power of two depth we need a further modification - if (wr_idx >= rd_idx) + uint16_t rd_idx; + if ( wr_idx >= f->depth ) { - return (uint16_t) (wr_idx - rd_idx); - } else + rd_idx = wr_idx - f->depth; + }else { - return (uint16_t) (2*depth - (rd_idx - wr_idx)); + rd_idx = wr_idx + f->depth; } -} -// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" -// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not -// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise -// write pointer wraps and you pointer states are messed up. This can only happen if you -// use DMAs, write functions do not allow such an error. -TU_ATTR_ALWAYS_INLINE static inline -bool _ff_overflowed(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) -{ - return _ff_count(depth, wr_idx, rd_idx) > depth; -} + f->rd_idx = rd_idx; -// return remaining slot in fifo -TU_ATTR_ALWAYS_INLINE static inline -uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) -{ - uint16_t const count = _ff_count(depth, wr_idx, rd_idx); - return (depth > count) ? (depth - count) : 0; -} - -// Works on local copies of w -// For more details see _tu_fifo_overflow()! -TU_ATTR_ALWAYS_INLINE static inline -void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wr_idx) -{ - f->rd_idx = backward_index(f->depth, wr_idx, f->depth); + return rd_idx; } // Works on local copies of w and r @@ -407,14 +425,14 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wr_idx); + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } // Skip beginning of buffer - if (cnt == 0) return false; + if ( cnt == 0 ) return false; uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); @@ -431,18 +449,17 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - if (cnt > f->depth) + if ( cnt > f->depth ) { - _tu_fifo_correct_read_pointer(f, wr_idx); - rd_idx = f->rd_idx; + rd_idx = _ff_correct_read_index(f, wr_idx); cnt = f->depth; } // Skip beginning of buffer - if (cnt == 0) return 0; + if ( cnt == 0 ) return 0; // Check if we can read something at and after offset - if too less is available we read what remains - if (cnt < n) n = cnt; + if ( cnt < n ) n = cnt; uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); @@ -662,7 +679,7 @@ bool tu_fifo_overflowed(tu_fifo_t* f) void tu_fifo_correct_read_pointer(tu_fifo_t* f) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, f->wr_idx); + _ff_correct_read_index(f, f->wr_idx); _ff_unlock(f->mutex_rd); } @@ -963,10 +980,9 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) if (cnt > f->depth) { _ff_lock(f->mutex_rd); - _tu_fifo_correct_read_pointer(f, wr_idx); + rd_idx = _ff_correct_read_index(f, wr_idx); _ff_unlock(f->mutex_rd); - rd_idx = f->rd_idx; cnt = f->depth; } @@ -988,7 +1004,8 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) info->ptr_lin = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary - if (wr_ptr > rd_ptr) { + if (wr_ptr > rd_ptr) + { // Non wrapping case info->len_lin = cnt; -- cgit v1.3.1 From 9e551c9f5cda2bd2bb1f53e34c5010babc534eb9 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 19:00:04 +0700 Subject: remove _ff_overflowed() due to lack of use --- src/common/tusb_fifo.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 22d6e8e55..d5eea83f7 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -331,17 +331,6 @@ uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) } } -// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" -// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not -// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise -// write pointer wraps and you pointer states are messed up. This can only happen if you -// use DMAs, write functions do not allow such an error. -TU_ATTR_ALWAYS_INLINE static inline -bool _ff_overflowed(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) -{ - return _ff_count(depth, wr_idx, rd_idx) > depth; -} - // return remaining slot in fifo TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) @@ -672,7 +661,7 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f) /******************************************************************************/ bool tu_fifo_overflowed(tu_fifo_t* f) { - return _ff_overflowed(f->depth, f->wr_idx, f->rd_idx); + return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; } // Only use in case tu_fifo_overflow() returned true! -- cgit v1.3.1 From c84de8f06bb42de78fec22dec8026f3a0c0899cc Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Jan 2023 19:40:06 +0700 Subject: minor clean up --- src/common/tusb_fifo.c | 100 +++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index d5eea83f7..a52c92267 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -97,13 +97,13 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si // TODO generalize with configurable 1 byte or 4 byte each read static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len) { - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf; // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; while(full_words--) { - tu_unaligned_write32(ff_buf, *rx_fifo); + tu_unaligned_write32(ff_buf, *reg_rx); ff_buf += 4; } @@ -111,7 +111,7 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { - uint32_t tmp32 = *rx_fifo; + uint32_t tmp32 = *reg_rx; memcpy(ff_buf, &tmp32, bytes_rem); } } @@ -120,24 +120,24 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t // where all data is written to a constant address in full word copies static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len) { - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; - // Pushing full available 32 bit words to const app address + // Write full available 32 bit words to const address uint16_t full_words = len >> 2; while(full_words--) { - *tx_fifo = tu_unaligned_read32(ff_buf); + *reg_tx = tu_unaligned_read32(ff_buf); ff_buf += 4; } - // Write the remaining 1-3 bytes into const app address + // Write the remaining 1-3 bytes into const address uint8_t const bytes_rem = len & 0x03; if ( bytes_rem ) { uint32_t tmp32 = 0; memcpy(&tmp32, ff_buf, bytes_rem); - *tx_fifo = tmp32; + *reg_tx = tmp32; } } @@ -148,21 +148,21 @@ static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel) } // send n items to fifo WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; + uint16_t const lin_count = f->depth - wr_ptr; + uint16_t const wrap_count = n - lin_count; - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if(n <= nLin) + if(n <= lin_count) { // Linear only memcpy(ff_buf, app_buf, n*f->item_size); @@ -172,17 +172,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around // Write data to linear part of buffer - memcpy(ff_buf, app_buf, nLin_bytes); + memcpy(ff_buf, app_buf, lin_bytes); // Write data wrapped around // TU_ASSERT(nWrap_bytes <= f->depth, ); - memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes); + memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: // Intended for hardware buffers from which it can be read word by word only - if(n <= nLin) + if(n <= lin_count) { // Linear only _ff_push_const_addr(ff_buf, app_buf, n*f->item_size); @@ -192,17 +192,18 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t // Wrap around case // Write full words to linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; + uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC; _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); ff_buf += nLin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32 = *rx_fifo; uint8_t * src_u8 = ((uint8_t *) &tmp32); @@ -220,7 +221,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t } // Write data wrapped part - if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); } break; } @@ -233,21 +234,21 @@ static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel) } // get n items from fifo WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode) +static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) { - uint16_t const nLin = f->depth - rel; - uint16_t const nWrap = n - nLin; // only used if wrapped + uint16_t const lin_count = f->depth - rd_ptr; + uint16_t const wrap_count = n - lin_count; // only used if wrapped - uint16_t nLin_bytes = nLin * f->item_size; - uint16_t nWrap_bytes = nWrap * f->item_size; + uint16_t lin_bytes = lin_count * f->item_size; + uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t* ff_buf = f->buffer + (rel * f->item_size); + uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size); switch (copy_mode) { case TU_FIFO_COPY_INC: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only memcpy(app_buf, ff_buf, n*f->item_size); @@ -257,15 +258,15 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around // Read data from linear part of buffer - memcpy(app_buf, ff_buf, nLin_bytes); + memcpy(app_buf, ff_buf, lin_bytes); // Read data wrapped part - memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes); + memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes); } break; case TU_FIFO_COPY_CST_FULL_WORDS: - if ( n <= nLin ) + if ( n <= lin_count ) { // Linear only _ff_pull_const_addr(app_buf, ff_buf, n*f->item_size); @@ -275,17 +276,18 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu // Wrap around case // Read full words from linear part of buffer - uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC; - _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes); - ff_buf += nLin_4n_bytes; + uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; + _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes); + ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf; - uint8_t rem = nLin_bytes & 0x03; + uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem); - nWrap_bytes -= remrem; + volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf; + + uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem); + wrap_bytes -= remrem; uint32_t tmp32=0; uint8_t * dst_u8 = (uint8_t *)&tmp32; @@ -297,7 +299,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu ff_buf = f->buffer; while(remrem--) *dst_u8++ = *ff_buf++; - *tx_fifo = tmp32; + *reg_tx = tmp32; } else { @@ -305,7 +307,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu } // Read data wrapped part - if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes); + if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); } break; @@ -413,6 +415,9 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 { uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + // nothing to peek + if ( cnt == 0 ) return false; + // Check overflow and correct if required if ( cnt > f->depth ) { @@ -420,9 +425,6 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16 cnt = f->depth; } - // Skip beginning of buffer - if ( cnt == 0 ) return false; - uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Peek data @@ -437,6 +439,9 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 { uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + // nothing to peek + if ( cnt == 0 ) return 0; + // Check overflow and correct if required if ( cnt > f->depth ) { @@ -444,9 +449,6 @@ static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint1 cnt = f->depth; } - // Skip beginning of buffer - if ( cnt == 0 ) return 0; - // Check if we can read something at and after offset - if too less is available we read what remains if ( cnt < n ) n = cnt; -- cgit v1.3.1