From ba3caf3a15e82cbec82520bd15fd5caae1f718c7 Mon Sep 17 00:00:00 2001 From: ole00 Date: Sat, 16 Dec 2023 19:16:53 +0000 Subject: [PATCH] sparse fusemap: added support for compacting Compacting searches for fuse blocks where all 32 bits are set to 1. If such block is found then it is removed from the fuse array (reducing its top position) and then the fuse type of such block is changed to 3. Note that the fuse bit is never changed from 1 to 0, therefore there is no need to cover these cases in the code (ie. converting block type 3 to block type 1). Compacting happens after every 256 fuse writes. Compacting is required to be able to read erased GALs where all fuse bits are initialised to 1. --- aftb_sparse.h | 107 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) 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;