diff --git a/aftb_sparse.h b/aftb_sparse.h index 59d8e0d..0d2fffb 100644 --- a/aftb_sparse.h +++ b/aftb_sparse.h @@ -17,15 +17,59 @@ #ifdef USE_SPARSE_FUSEMAP +// compacting statistics - disabled by default +#define COMPACT_STAT 0 + #define SPFUSES 128 unsigned char fuseType[SPFUSES]; //sparse fuses index uint16_t sparseFusemapStat = 0; //bit 15: use sparse fusemaps, bits 0-11 : sparse fusemap size in bytes +uint8_t sparseCompactCounter = 0; uint16_t sparseCacheBitPos = 0; uint16_t sparseCacheOffset = 0; uint16_t sparseCacheHit = 0; uint8_t sparseCacheIndex = 0; +#if COMPACT_STAT +uint8_t sparseCompactRun = 0; +uint8_t sparseCompactAct = 0; +#endif + + +// reverse search of the fuse group index based on the byte position in the sparse array +// returns the group index +static uint16_t getFuseGroupIndex(uint16_t fuseOffsetBytePos) { + uint16_t groupPos = 0; + uint16_t i = 0; + uint16_t fuseOffset = 0; + + //calculate fusemap offset + while (1) { + uint8_t rec = fuseType[i]; + // speed optimised special case: all 8 bits are 0 (4 * 32 bits) + if (rec == 0) { + groupPos += 4; //4 groups in the byte + } else { + uint8_t j = 0; + //4 types per byte + while (j < 4) { + if ((rec & 0b11) == 1) { // type 0 & 3 - no byte stored in fusemap + if (fuseOffset == fuseOffsetBytePos) { + return groupPos; + } + fuseOffset += 4; // 32 bits in the group, fuse byte offset advances by 4 bytes + } + groupPos++; //check next group + rec >>= 2; + j++; + } + } + i++; //next byte from the fuseTypes + } +} + + +// get position of the fuse bit in the sparse array static uint16_t getFusePositionAndType(uint16_t bitPos) { uint16_t counter = 0; uint8_t i = 0; @@ -94,9 +138,57 @@ static void insertFuseGroup(uint16_t dataPos, uint16_t bitPos) { fusemap[dataPos] = 0; } + +static void sparseCompactFuseMap(void) { + uint16_t i, j; + uint16_t total = (sparseFusemapStat & 0x7FF) >> 2; // max is 2048 bytes, and convert to the group index + uint32_t* fuses = (uint32_t*) fusemap; + + if (total < 2) { + return; + } + +#if COMPACT_STAT + sparseCompactRun++; //statistics +#endif + + i = total - 1; + while(i) { + // remove 4 fusemap bytes at a position when the bits are all 1's + if (fuses[i] == 0xFFFFFFFF) { + if (i < total - 1) { + uint16_t fuseGroup = getFuseGroupIndex(i << 2); //ensure the int32 index is converted to int8/byte index +#if COMPACT_STAT + sparseCompactAct++; //statistics +#endif + /// shift the fuses by 4 bytes to the left + for (j = i; j < total - 1 ; j++) { + fuses[j] = fuses[j + 1]; + } + total--; + fuseType[fuseGroup >> 2] |= (3 << ((fuseGroup & 0b11) << 1)); //set type 3 at the fuse group record + sparseFusemapStat -= 4; // fuse map total size reduced by 4 bytes + } + } + i--; + } + //destory cache + sparseCacheBitPos = 0; + sparseCacheOffset = 0; + sparseCacheIndex = 0; +} + static inline uint16_t sparseSetFuseBit(uint16_t bitPos) { uint8_t type; - uint16_t pos = getFusePositionAndType(bitPos); + uint16_t pos; + + //try to reduce the size of the fuse map by finding and removing blocks with all 1's + sparseCompactCounter ++; + if (sparseCompactCounter == 255) { + sparseCompactFuseMap(); + } + + pos = getFusePositionAndType(bitPos); type = pos & 0b11; pos >>= 2; //trim the type to get the byte position in fuse map if (type == 0) { //we need to write the bit into a group that has all bits 0 so far @@ -123,8 +215,14 @@ static inline uint16_t sparseGetFuseBit(uint16_t bitPos) { static void sparsePrintStat() { Serial.print(F("sp bytes=")); Serial.println(sparseFusemapStat & 0x7FF, DEC); - Serial.print("chit="); + Serial.print(F("c_hit=")); Serial.println(sparseCacheHit, DEC); +#if COMPACT_STAT + Serial.print(F("compact run=")); + Serial.print(sparseCompactRun, DEC); + Serial.print(F(" cnt=")); + Serial.println(sparseCompactAct, DEC); +#endif } static void sparseInit(char clearArray) { @@ -136,9 +234,14 @@ static void sparseInit(char clearArray) { } sparseFusemapStat = (1 << 15); + sparseCompactCounter = 0; sparseCacheBitPos = 0; sparseCacheOffset = 0; sparseCacheIndex = 0; +#if COMPACT_STAT + sparseCompactRun = 0; + sparseCompactAct = 0; +#endif } static inline void sparseDisable(void) { sparseFusemapStat = 0;