From f3147397f9d19d2462ac3b9f44e43bf6cbb36392 Mon Sep 17 00:00:00 2001 From: ole00 Date: Wed, 13 Dec 2023 22:02:42 +0000 Subject: [PATCH] sparse fusemap: use 32 bit fuse blocks Previously 16 bit fuse blocks were used and block types were stored in 1 bit. That did not allow to compact fusemaps where all bits were 1 - which is typically after the fuses are erased. So fuses of an erased chip would not fit into the sparse memory array. The solution was to extend the fuse block type storage from 1 bit to 2 bits and use that extra space to mark blocks as sparse when all bits in the block are 1's. Such block is now block type 3. To keep the fuseType array the same size as it was (128 bytes) the size of the block was extended from 16 bits to 32 bits. The block type is now: 0 - all bits in the fuse block are 0, no block data in the fuse array 3 - all bits in the fuse block are 1, no block data in the fuse array 1 - any combination of bits in the fuse block, data are stored in the fuse array 2 - reserved for future use. --- aftb_sparse.h | 56 ++++++++++++++++++++++++++++--------------------- afterburner.ino | 3 +++ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/aftb_sparse.h b/aftb_sparse.h index f6bbc32..59d8e0d 100644 --- a/aftb_sparse.h +++ b/aftb_sparse.h @@ -30,7 +30,7 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) { uint16_t counter = 0; uint8_t i = 0; uint8_t type; - uint16_t fuseOffset = (bitPos & 0b1000) ? 1 : 0; //set odd / even byte of the fuse offset + uint16_t fuseOffset = (bitPos & 0b11000) >> 3; //set odd / even byte of the fuse offset if (bitPos <= sparseCacheBitPos) { sparseCacheBitPos = 0; @@ -38,7 +38,7 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) { sparseCacheIndex = 0; } else { counter = sparseCacheBitPos; - fuseOffset += sparseCacheOffset & 0xFFE; + fuseOffset += sparseCacheOffset & 0xFFC; i = sparseCacheIndex; sparseCacheHit++; } @@ -46,28 +46,28 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) { //calculate fusemap offset while (1) { uint8_t rec = fuseType[i]; - // speed optimised special case: all 8 bits are 0 + // speed optimised special case: all 8 bits are 0 (4 * 32 bits) if (rec == 0) { counter += 128; if (counter > bitPos) { - return (fuseOffset << 1); // type is 0 + return (fuseOffset << 2); // type is 0 } sparseCacheBitPos = counter; sparseCacheOffset = fuseOffset; sparseCacheIndex = i + 1; } else { uint8_t j = 0; - //8 fuse types per byte - while (j < 8) { - counter += 16; - type = rec & 1; + //4 fuse types per byte + while (j < 4) { + counter += 32; + type = rec & 0b11; if (counter > bitPos) { - return (fuseOffset << 1) | type; + return (fuseOffset << 2) | type; } - if (type) { - fuseOffset += 2; + if (type == 1) { // type 0 & 3 - no byte stored in fusemap + fuseOffset += 4; } - rec >>= 1; + rec >>= 2; j++; } } @@ -76,39 +76,47 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) { } static void insertFuseGroup(uint16_t dataPos, uint16_t bitPos) { - int16_t i = bitPos >> 4; //group index + int16_t i = bitPos >> 5; //group index uint16_t totalFuseBytes = sparseFusemapStat & 0x7FF; // max is 2048 bytes - fuseType[i >> 3] |= (1 << (i & 7)); // set type 1 at the fuse group record + fuseType[i >> 2] |= (1 << ((i & 0b11) << 1)); // set type 1 at the fuse group record - //shift all data in the fuse map starting at data pos by 2 bytes (16 bits) + //shift all data in the fuse map starting at data pos by 4 bytes (32 bits) if (dataPos < totalFuseBytes) { for (i = totalFuseBytes - 1; i >= dataPos; i--) { - fusemap[i + 2] = fusemap[i]; + fusemap[i + 4] = fusemap[i]; } } - sparseFusemapStat = totalFuseBytes + 2; // we can ignore the sparse bit + sparseFusemapStat = totalFuseBytes + 4; // we can ignore the sparse bit //clean the emptied fusemap data fusemap[dataPos++] = 0; + fusemap[dataPos++] = 0; + fusemap[dataPos++] = 0; fusemap[dataPos] = 0; } static inline uint16_t sparseSetFuseBit(uint16_t bitPos) { uint8_t type; uint16_t pos = getFusePositionAndType(bitPos); - type = pos & 1; - pos >>= 1; //trim the type to get the byte position in fuse map + 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 - insertFuseGroup(pos & 0x7FE, bitPos); + insertFuseGroup(pos & 0x7FC, bitPos); } return pos; } static inline uint16_t sparseGetFuseBit(uint16_t bitPos) { + uint8_t type; uint16_t pos = getFusePositionAndType(bitPos); - if (!(pos & 1)) { //type is 0 - the block contains all zero bits - return 0; + + type = pos & 0b11; + if (!type) { //type is 0 - the block contains all zero bits + return 0xFF00; } - pos >>= 1; //trim the type to get byte position in fuse map + if (type == 3) { // type is 3 - the block contains all 1 bits + return 0xFF01; + } + pos >>= 2; //trim the type to get byte position in fuse map return pos; } @@ -143,4 +151,4 @@ static inline void sparseDisable(void) { #define sparseSetFuseBit(X) 0 #define sparsePrintStat() #define sparseFusemapStat 0 -#endif \ No newline at end of file +#endif diff --git a/afterburner.ino b/afterburner.ino index 0733ee5..a04e528 100644 --- a/afterburner.ino +++ b/afterburner.ino @@ -1535,6 +1535,9 @@ static char getFuseBit(unsigned short bitPos) { uint16_t pos; if (sparseFusemapStat) { pos = sparseGetFuseBit(bitPos); + if (pos >= 0xFF00) { + return pos & 0x1; + } } else { pos = bitPos >> 3; }