diff --git a/fifofast.h b/fifofast.h index 9363e2b..6773f03 100644 --- a/fifofast.h +++ b/fifofast.h @@ -42,11 +42,13 @@ // version numbering is based on "Semantic Versioning 2.0.0" (semver.org) #define FIFOFAST_VERSION_MAJOR 0 -#define FIFOFAST_VERSION_MINOR 2 -#define FIFOFAST_VERSION_PATCH 2 +#define FIFOFAST_VERSION_MINOR 3 +#define FIFOFAST_VERSION_PATCH 0 #define FIFOFAST_VERSION_SUFFIX #define FIFOFAST_VERSION_META +// For all development versions (0.x.x) the minor version is increased whenever a function was renamed + ////////////////////////////////////////////////////////////////////////// // Check requirements ////////////////////////////////////////////////////////////////////////// @@ -224,59 +226,37 @@ struct _fff__name_structp8(_id) _id = \ // _id: C conform identifier #define _fff_reset(_id) do{_id.read=0; _id.write=0; _id.level=0;} while (0) - -// TODO: remove is broken, reason unknown; details: -// _fff_remove(_id, amount) should have the same effect as while(amount){_fff_read(_id);amount--} - + // removes a certain number of elements or less, if not enough elements are available. // This function is especially useful after data has been used by _fff_peek(...) +// NOTE: This macro can only delete up to _fff_depth(_id)-1 elements! Workaround: Call twice or use +// _fff_reset(_id) instead. // _id: C conform identifier -// amount: Amount of elements which will be removed; must be 0 <= amount <= _fff_depth(_id); -// #define _fff_remove_broken(_id, amount) \ -// do{ \ -// uint8_t _amount = (amount); \ -// if(_fff_is_full(_id)) \ -// { \ -// _id.min_w++; \ -// _amount--; \ -// } \ -// if(_fff_mem_mask(_id)-_id.min_w > (_amount)) /*flush if equal*/ \ -// { \ -// _id.min_w += _amount; \ -// _id.read = _fff_wrap(_id, (_id.read+(_amount+1))); \ -// } \ -// else \ -// _fff_reset(_id); \ -// }while(0) - - +// amount: Amount of elements which will be removed #define _fff_remove(_id, amount) \ do{ \ - for (uint8_t _idx = amount; _idx > 0; _idx--) \ - {_fff_read(_id);} \ + if(amount > 0) \ + { \ + typeof(_id.level) _amount = (typeof(_id.level))amount; \ + if(amount > _id.level) \ + _amount = _id.level; \ + _fff_remove_lite(_id, _amount); \ + } \ }while(0) - -#define _fff_remove_fast(_id, amount) \ +// removes a certain number of elements. The user must ensure that the given amount of elements can +// be removed; 0 and _fff_depth(_id) are invallid amounts! If you require argument checking use +// _fff_remove(). +// This function is especially useful after data has been used by _fff_peek(...) +// _id: C conform identifier +// amount: Amount of elements which will be removed; must be 1 <= amount <= _fff_mem_level(_id); +#define _fff_remove_lite(_id, amount) \ do{ \ - if(!_fff_is_full) \ - { \ - if (_id.amount >= _id.level) \ - { \ - _id.level = 0; \ - _id.read = _id.write; \ - } \ - else \ - { \ - _id.level -= amount; \ - _id.read = _fff_wrap(_id, _id.read+amount) \ - } \ - } \ + if(!_fff_is_full(_id)) \ + _id.level -= amount; \ else \ - { \ - _id.level -= (amount-1) \ - _id.read = _fff_wrap(_id, _id.read+amount) \ - } \ + _id.level -= (amount-1); \ + _id.read = _fff_wrap(_id, _id.read+amount); \ }while(0) @@ -341,11 +321,6 @@ do{ \ _fff_write_lite(_id, newdata); \ }while(0) -// #define _fff_write_bulk(_id, cnt, pointer) -// do{ -// -// -// }while(0); // adds an element to the fifo, but does not write any data to it. instead, a pointer to the data // section is returned. The caller may write up to _fff_data_size(_id) bytes to this location. diff --git a/fifofast_demo.c b/fifofast_demo.c index 804f928..450d2cb 100644 --- a/fifofast_demo.c +++ b/fifofast_demo.c @@ -46,6 +46,7 @@ int main(void) volatile uint8_t dbg1 = 0; volatile uint8_t dbg2 = 0; volatile uint8_t dbg3 = 0; + volatile uint8_t dbg4 = 0; // for "_fff_read...()" macros only volatile uint8_t dbg_read0 = 0; @@ -138,6 +139,9 @@ int main(void) dbg2 = _fff_peek(fifo_uint8, 2); // = 0x55 dbg3 = _fff_peek(fifo_uint8, 3); // = 0x76 + // demonstrate "out of bounds" safety + dbg4 = _fff_peek(fifo_uint8, 4); // = 0x53 + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) dbg_mem_level = _fff_mem_level(fifo_uint8); // = 3 (see macro description) @@ -151,7 +155,6 @@ int main(void) // Test Cases READ ////////////////////////////////////////////////////////////////////////// - // TODO: level decremented wrongly if fifo is full // read 2 values with the fast '_lite' variant (we know we have written at least to entries) dbg_read0 = _fff_read_lite(fifo_uint8); // = 0x53 dbg_read1 = _fff_read_lite(fifo_uint8); // = 0x74 @@ -260,6 +263,125 @@ int main(void) asm volatile ("nop"); // easy breakpoint + ////////////////////////////////////////////////////////////////////////// + // Test Case REMOVE_LITE + ////////////////////////////////////////////////////////////////////////// + + // fill with any data (macros have been prooven o work before) + _fff_write_lite(fifo_uint8, 0x23); + _fff_write_lite(fifo_uint8, 0x24); + _fff_write_lite(fifo_uint8, 0x25); + _fff_write_lite(fifo_uint8, 0x26); + // fifo is now full + + // _remove 2 (Test case: fifo full before macro) + _fff_remove_lite(fifo_uint8, 2); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x25 + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x26 + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x23 (empty) + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x24 (empty) + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 2 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 1 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false) + dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false) + asm volatile ("nop"); // easy breakpoint + + // _remove 1 (Test case: fifo not full before and not empty after macro) + _fff_remove_lite(fifo_uint8, 1); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x26 + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x23 (empty) + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x24 (empty) + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x25 (empty) + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 1 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 2 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false) + dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false) + asm volatile ("nop"); // easy breakpoint + + // _remove 1 (Test case: fifo empty after macro) + _fff_remove_lite(fifo_uint8, 1); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x23 (empty) + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x24 (empty) + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x25 (empty) + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x26 (empty) + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!) + dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false) + asm volatile ("nop"); // easy breakpoint + + + ////////////////////////////////////////////////////////////////////////// + // Test Case REMOVE_LITE + ////////////////////////////////////////////////////////////////////////// + + // fill with any data (macros have been prooven o work before) + _fff_write_lite(fifo_uint8, 0x13); + _fff_write_lite(fifo_uint8, 0x14); + _fff_write_lite(fifo_uint8, 0x15); + _fff_write_lite(fifo_uint8, 0x16); + // fifo is now full + + // _remove 0 (Test case: amount <= 0 elements) + _fff_remove(fifo_uint8, 0); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x13 + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x14 + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x15 + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x16 + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false) + dbg_is_full = _fff_is_full(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!) + asm volatile ("nop"); // easy breakpoint + + // _remove 4 (Test case: amount > _fff_mem_level() w/ fifo full) + _fff_remove(fifo_uint8, 4); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x16 + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x13 (empty) + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x14 (empty) + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x15 (empty) + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 1 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 2 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // = 0 (= false) + dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false) + asm volatile ("nop"); // easy breakpoint + + // _remove 4 (Test case: amount > _fff_mem_level() w/ fifo not full) + _fff_remove(fifo_uint8, 4); + + dbg0 = _fff_peek(fifo_uint8, 0); // = 0x13 (empty) + dbg1 = _fff_peek(fifo_uint8, 1); // = 0x14 (empty) + dbg2 = _fff_peek(fifo_uint8, 2); // = 0x15 (empty) + dbg3 = _fff_peek(fifo_uint8, 3); // = 0x16 (empty) + + dbg_mem_depth = _fff_mem_depth(fifo_uint8); // = 4 (constant) + dbg_mem_mask = _fff_mem_mask(fifo_uint8); // = 3 (= 0b11, constant) + dbg_mem_level = _fff_mem_level(fifo_uint8); // = 0 (see macro description) + dbg_mem_free = _fff_mem_free(fifo_uint8); // = 3 (see macro description) + dbg_is_empty = _fff_is_empty(fifo_uint8); // != 0 (= true, note that the actually value is NOT guaranteed to be '1'!) + dbg_is_full = _fff_is_full(fifo_uint8); // = 0 (= false) + asm volatile ("nop"); // easy breakpoint + // End simulation while (1) asm volatile ("nop"); }