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.
This commit is contained in:
ole00 2023-12-16 19:16:53 +00:00
parent f3147397f9
commit ba3caf3a15
1 changed files with 105 additions and 2 deletions

View File

@ -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;