added support for sparse fusemap
This commit is contained in:
parent
b216b16c9a
commit
77a5d7d236
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Sparse fusemap functions for Afterburner GAL project.
|
||||
*
|
||||
* The idea of sparse fuse map is to store non-zero fuse bits only.
|
||||
* The reason is to fit big fusemaps into a size-limited SRAM.
|
||||
* The fusemap is divided into groups of 16 bits and each group
|
||||
* has a 'type' bit stored in fuseTypes array. Group type 0 has
|
||||
* all 16 fuesmap bits 0 and is not stored in fusemap array.
|
||||
* Group type 1 has at least 1 fusemap bit set and is stored in
|
||||
* fusemap array. Position of group type '1' in the fusemap array
|
||||
* may vary based on which fuses are written.
|
||||
*
|
||||
* Sparse fusemap supports:
|
||||
* - random reads and writes
|
||||
* - a simple cache to speed up index look-ups.
|
||||
*/
|
||||
|
||||
#ifdef USE_SPARSE_FUSEMAP
|
||||
|
||||
#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
|
||||
uint16_t sparseCacheBitPos = 0;
|
||||
uint16_t sparseCacheOffset = 0;
|
||||
uint16_t sparseCacheHit = 0;
|
||||
uint8_t sparseCacheIndex = 0;
|
||||
|
||||
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
|
||||
|
||||
if (bitPos <= sparseCacheBitPos) {
|
||||
sparseCacheBitPos = 0;
|
||||
sparseCacheOffset = 0;
|
||||
sparseCacheIndex = 0;
|
||||
} else {
|
||||
counter = sparseCacheBitPos;
|
||||
fuseOffset += sparseCacheOffset & 0xFFE;
|
||||
i = sparseCacheIndex;
|
||||
sparseCacheHit++;
|
||||
}
|
||||
|
||||
//calculate fusemap offset
|
||||
while (1) {
|
||||
uint8_t rec = fuseType[i];
|
||||
// speed optimised special case: all 8 bits are 0
|
||||
if (rec == 0) {
|
||||
counter += 128;
|
||||
if (counter > bitPos) {
|
||||
return (fuseOffset << 1); // 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;
|
||||
if (counter > bitPos) {
|
||||
return (fuseOffset << 1) | type;
|
||||
}
|
||||
if (type) {
|
||||
fuseOffset += 2;
|
||||
}
|
||||
rec >>= 1;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
i++; //next byte from the fuseTypes
|
||||
}
|
||||
}
|
||||
|
||||
static void insertFuseGroup(uint16_t dataPos, uint16_t bitPos) {
|
||||
int16_t i = bitPos >> 4; //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
|
||||
|
||||
//shift all data in the fuse map starting at data pos by 2 bytes (16 bits)
|
||||
if (dataPos < totalFuseBytes) {
|
||||
for (i = totalFuseBytes - 1; i >= dataPos; i--) {
|
||||
fusemap[i + 2] = fusemap[i];
|
||||
}
|
||||
}
|
||||
sparseFusemapStat = totalFuseBytes + 2; // we can ignore the sparse bit
|
||||
//clean the emptied fusemap data
|
||||
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
|
||||
if (type == 0) { //we need to write the bit into a group that has all bits 0 so far
|
||||
insertFuseGroup(pos & 0x7FE, bitPos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static inline uint16_t sparseGetFuseBit(uint16_t bitPos) {
|
||||
uint16_t pos = getFusePositionAndType(bitPos);
|
||||
if (!(pos & 1)) { //type is 0 - the block contains all zero bits
|
||||
return 0;
|
||||
}
|
||||
pos >>= 1; //trim the type to get byte position in fuse map
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void sparsePrintStat() {
|
||||
Serial.print(F("sp bytes="));
|
||||
Serial.println(sparseFusemapStat & 0x7FF, DEC);
|
||||
Serial.print("chit=");
|
||||
Serial.println(sparseCacheHit, DEC);
|
||||
}
|
||||
|
||||
static void sparseInit(char clearArray) {
|
||||
if (clearArray) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < SPFUSES; i++) {
|
||||
fuseType[i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
sparseFusemapStat = (1 << 15);
|
||||
sparseCacheBitPos = 0;
|
||||
sparseCacheOffset = 0;
|
||||
sparseCacheIndex = 0;
|
||||
}
|
||||
static inline void sparseDisable(void) {
|
||||
sparseFusemapStat = 0;
|
||||
}
|
||||
#else /* ! USE_SPARSE_FUSEMAP */
|
||||
|
||||
#define sparseDisable()
|
||||
#define sparseInit(X)
|
||||
#define sparseGetFuseBit(X) 0
|
||||
#define sparseSetFuseBit(X) 0
|
||||
#define sparsePrintStat()
|
||||
#define sparseFusemapStat 0
|
||||
#endif
|
|
@ -411,9 +411,13 @@ galinfo_t galinfo __attribute__ ((section (".noinit"))); //preserve data between
|
|||
// Boards with small RAM (< 2.5kB) do not support ATF750C
|
||||
// MAXFUSES calculated as the biggest required space to hold the fuse bitmap
|
||||
// MAXFUSES = GAL6002 8330 bits = 8330/8 = 1041.25 bytes rounded up to 1042 bytes
|
||||
#define MAXFUSES 1042
|
||||
//#define MAXFUSES 1042
|
||||
//extra space added for sparse fusemap
|
||||
#define MAXFUSES 1280
|
||||
#define USE_SPARSE_FUSEMAP
|
||||
#endif
|
||||
|
||||
|
||||
GALTYPE gal __attribute__ ((section (".noinit"))); //the gal device index pointing to galInfoList, value is preserved between resets
|
||||
|
||||
static short erasetime = 100, progtime = 100;
|
||||
|
@ -439,6 +443,7 @@ static void turnOff(void);
|
|||
static void printFormatedNumberHex2(unsigned char num) ;
|
||||
|
||||
#include "aftb_vpp.h"
|
||||
#include "aftb_sparse.h"
|
||||
|
||||
// print some help on the serial console
|
||||
void printHelp(char full) {
|
||||
|
@ -653,13 +658,19 @@ void setup() {
|
|||
pinMode(PIN_SHR_CS, OUTPUT);
|
||||
digitalWrite(PIN_SHR_CS, 1); //unselect the POT's SPI bus
|
||||
}
|
||||
|
||||
Serial.println(">");
|
||||
}
|
||||
|
||||
//copy galinfo item from the flash array into RAM backed struct
|
||||
static void copyGalInfo(void) {
|
||||
memcpy_P(&galinfo, &galInfoList[gal], sizeof(galinfo_t));
|
||||
|
||||
// Note: Sparse fuse map is ignored on MCUs with big SRAM
|
||||
if (gal == ATF750C) {
|
||||
sparseInit(0);
|
||||
} else {
|
||||
sparseDisable();
|
||||
}
|
||||
}
|
||||
|
||||
// read from serial line and discard the data
|
||||
|
@ -1510,12 +1521,24 @@ void printPes(char type) {
|
|||
// sets a fuse bit on particular position
|
||||
// expects that the fusemap was cleared (set to zero) beforehand
|
||||
static void setFuseBit(unsigned short bitPos) {
|
||||
fusemap[bitPos >> 3] |= (1 << (bitPos & 7));
|
||||
uint16_t pos;
|
||||
if (sparseFusemapStat) {
|
||||
pos = sparseSetFuseBit(bitPos);
|
||||
} else {
|
||||
pos = bitPos >> 3; //divide the bit position by 8 to get the byte position
|
||||
}
|
||||
fusemap[pos] |= (1 << (bitPos & 7));
|
||||
}
|
||||
|
||||
// gets a fuse bit from specific fuse position
|
||||
static char getFuseBit(unsigned short bitPos) {
|
||||
return (fusemap[bitPos >> 3] & (1 << (bitPos & 7))) ? 1 : 0;
|
||||
uint16_t pos;
|
||||
if (sparseFusemapStat) {
|
||||
pos = sparseGetFuseBit(bitPos);
|
||||
} else {
|
||||
pos = bitPos >> 3;
|
||||
}
|
||||
return (fusemap[pos] & (1 << (bitPos & 7))) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void setFuseBitVal(unsigned short bitPos, char val) {
|
||||
|
@ -1613,6 +1636,12 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do
|
|||
}
|
||||
setFlagBit(FLAG_BIT_APD, receiveBit());
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (sparseFusemapStat) {
|
||||
sparsePrintStat();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void readGalFuseMap600(const unsigned char* cfgArray) {
|
||||
|
@ -1895,6 +1924,7 @@ static void readOrVerifyGal(char verify)
|
|||
for (i = 0; i < MAXFUSES; i++) {
|
||||
fusemap[i] = 0;
|
||||
}
|
||||
sparseInit(1);
|
||||
}
|
||||
|
||||
turnOn(READGAL);
|
||||
|
@ -2772,6 +2802,7 @@ void loop() {
|
|||
for (i = 0; i < MAXFUSES; i++) {
|
||||
fusemap[i] = 0;
|
||||
}
|
||||
sparseInit(1);
|
||||
isUploading = 1;
|
||||
uploadError = 0;
|
||||
} break;
|
||||
|
|
Loading…
Reference in New Issue