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.
This commit is contained in:
ole00 2023-12-13 22:02:42 +00:00
parent 77a5d7d236
commit f3147397f9
2 changed files with 35 additions and 24 deletions

View File

@ -30,7 +30,7 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) {
uint16_t counter = 0; uint16_t counter = 0;
uint8_t i = 0; uint8_t i = 0;
uint8_t type; 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) { if (bitPos <= sparseCacheBitPos) {
sparseCacheBitPos = 0; sparseCacheBitPos = 0;
@ -38,7 +38,7 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) {
sparseCacheIndex = 0; sparseCacheIndex = 0;
} else { } else {
counter = sparseCacheBitPos; counter = sparseCacheBitPos;
fuseOffset += sparseCacheOffset & 0xFFE; fuseOffset += sparseCacheOffset & 0xFFC;
i = sparseCacheIndex; i = sparseCacheIndex;
sparseCacheHit++; sparseCacheHit++;
} }
@ -46,28 +46,28 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) {
//calculate fusemap offset //calculate fusemap offset
while (1) { while (1) {
uint8_t rec = fuseType[i]; 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) { if (rec == 0) {
counter += 128; counter += 128;
if (counter > bitPos) { if (counter > bitPos) {
return (fuseOffset << 1); // type is 0 return (fuseOffset << 2); // type is 0
} }
sparseCacheBitPos = counter; sparseCacheBitPos = counter;
sparseCacheOffset = fuseOffset; sparseCacheOffset = fuseOffset;
sparseCacheIndex = i + 1; sparseCacheIndex = i + 1;
} else { } else {
uint8_t j = 0; uint8_t j = 0;
//8 fuse types per byte //4 fuse types per byte
while (j < 8) { while (j < 4) {
counter += 16; counter += 32;
type = rec & 1; type = rec & 0b11;
if (counter > bitPos) { if (counter > bitPos) {
return (fuseOffset << 1) | type; return (fuseOffset << 2) | type;
} }
if (type) { if (type == 1) { // type 0 & 3 - no byte stored in fusemap
fuseOffset += 2; fuseOffset += 4;
} }
rec >>= 1; rec >>= 2;
j++; j++;
} }
} }
@ -76,39 +76,47 @@ static uint16_t getFusePositionAndType(uint16_t bitPos) {
} }
static void insertFuseGroup(uint16_t dataPos, 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 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) { if (dataPos < totalFuseBytes) {
for (i = totalFuseBytes - 1; i >= dataPos; i--) { 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 //clean the emptied fusemap data
fusemap[dataPos++] = 0; fusemap[dataPos++] = 0;
fusemap[dataPos++] = 0;
fusemap[dataPos++] = 0;
fusemap[dataPos] = 0; fusemap[dataPos] = 0;
} }
static inline uint16_t sparseSetFuseBit(uint16_t bitPos) { static inline uint16_t sparseSetFuseBit(uint16_t bitPos) {
uint8_t type; uint8_t type;
uint16_t pos = getFusePositionAndType(bitPos); uint16_t pos = getFusePositionAndType(bitPos);
type = pos & 1; type = pos & 0b11;
pos >>= 1; //trim the type to get the byte position in fuse map 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 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; return pos;
} }
static inline uint16_t sparseGetFuseBit(uint16_t bitPos) { static inline uint16_t sparseGetFuseBit(uint16_t bitPos) {
uint8_t type;
uint16_t pos = getFusePositionAndType(bitPos); 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; return pos;
} }

View File

@ -1535,6 +1535,9 @@ static char getFuseBit(unsigned short bitPos) {
uint16_t pos; uint16_t pos;
if (sparseFusemapStat) { if (sparseFusemapStat) {
pos = sparseGetFuseBit(bitPos); pos = sparseGetFuseBit(bitPos);
if (pos >= 0xFF00) {
return pos & 0x1;
}
} else { } else {
pos = bitPos >> 3; pos = bitPos >> 3;
} }