📄 flash_nvram56xx.c
字号:
// find an empty block
// if offset is supplied, then we assume block already exists, find the
// block if offset is not zero.
if(W_Offset == 0x00)
pbAddr = findBlockType(0xff, 0xff, &version);
else
{
createHeader = gmd_FALSE;
do
{
pbAddr = findBlockType(B_BlockType, B_Index, &version);
}while(((DWORD)pbAddr == NULL_PTR) && (version-- != 0x00));
if((DWORD)pbAddr == NULL_PTR)
{// block not found, nothing we can do, find an empty block.
createHeader = gmd_TRUE;
pbAddr = findBlockType(0xff, 0xff, &version);
}
}
msgx("B_BlockType %x",(WORD)B_BlockType);
msgx("B_Index %x",(WORD)B_Index);
msgx("pbAddr seg %x",(WORD)((DWORD)pbAddr >> 16));
msgx("pbAddr off %x",(WORD)pbAddr);
// see if there's enough room in this FLASH sector for our new block.
room = (WORD)(HUGE((DWORD)workingSector + FLASHUserPrefSectorSize) - HUGE(pbAddr));
msgx("room %d",(WORD)room);
msgx("size %d",(WORD)hdr.Size);
msgx("W_Length %d",W_Length);
msgx("W_Offset %d",W_Offset);
if( (room < hdr.Size) || (pbAddr == NULL_PTR) ) // not enough room. Time to prune the sector.
{
msgx("..prune2..",0);
msgx("room %d",(WORD)room);
msgx("size %d",(WORD)hdr.Size);
prune();
msgx("prune time: %d", (WORD)(t2-t1));
// find an empty block
pbAddr = findBlockType(0xff, 0xff, &version);
if(pbAddr == NULL_PTR)
return gmd_FAIL; // if after prune, still no room, nothing else we can do.
}
//testing
// if(B_BlockType==ModeIndependentUserPreferences_ID)
// return gmd_FAIL;
// first fill in block header.
// if offset is supplied, then we assume block already exists, don't
// create a new header if block already exists.
if(createHeader)
executeRamResidentCmd(FLASH_NV_WRITE, pbAddr, sizeof(block_hdr_type), (BYTE far *)&hdr);
// now the data...
executeRamResidentCmd(FLASH_NV_WRITE, &pbAddr[BLOCK_DATA_OFFSET + W_Offset], W_Length, Bp_Buffer);
return gmd_OK;
}
//***************************************************************
// FUNCTION : pp_ReadNVRAMAbsolute
// DESCRIPTION : Read from an Absolute address.
// INPUT : Address, buffer pointer, length.
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
gmt_RET_STAT pp_ReadNVRAMAbsolute(WORD Address, BYTE * Bp_Buffer, WORD W_Length)
{
BYTE far *pbAddr = (BYTE far *)((DWORD)workingSector + Address);
_fmemcpy(Bp_Buffer, pbAddr, W_Length);
return gmd_OK;
}
//***************************************************************
// FUNCTION : pp_WriteNVRAMAbsolute
// DESCRIPTION : Write to Absolute address.
// INPUT : Address, buffer pointer, length.
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
gmt_RET_STAT pp_WriteNVRAMAbsolute(WORD Address, BYTE * Bp_Buffer, WORD W_Length)
{
BYTE far *pbAddr = (BYTE far *)((DWORD)workingSector + Address);
executeRamResidentCmd(FLASH_NV_WRITE, pbAddr, W_Length, Bp_Buffer);
return gmd_OK;
}
static BYTE far *findBlockType(BYTE blockType, BYTE blockIndex, BYTE *version)
{
BYTE far *WrAddr, far *GoodBlock;
DWORD LastAddress;
DWORD DW_tmpAddress;
WORD length;
BYTE ver, getVer = 0;
// allow null pointer for version.
if(version == NULL_PTR)
{
ver = 0;
version = &ver;
}
// if version is non-zero, then this is the version we want to get.
if(*version)
getVer = ~*version + 1;
*version = 0;
// version is used for two purposes. If version is zero prior to entering
// this function, than it will be incremented each time a BlockType is found.
// This can be read later to see how many entries of this BlockType there
// are. When reading a block entry, and the checksum is bad, and the
// version is greater than 1, then we know there's a backup copy somewhere
// in the sector. So set the version to 1 less then the number found, and
// invert it, now when version is incremented in this function, and it hits
// zero, then it will return this entry. example: if looking for
// NVRAM_MODEDEP_USERPREF, the version is 3, and the checksum is bad.
// look for versioin 2 by inverting it and add one (0xFE) then call this
// function again. When it increments version up to 0x00, then that entry
// will be returned (the 2nd entry in this example).
WrAddr = workingSector;
GoodBlock = NULL_PTR;
LastAddress = (DWORD)workingSector + FLASHUserPrefSectorSize;
msgx("LastAddress seg %x",FP_SEG(LastAddress));
msgx("LastAddress off %x",FP_OFF(LastAddress));
msgx("findBlock %x",(WORD)blockType);
do
{
//msgx("WrAddr seg %x",FP_SEG(WrAddr));
//msgx("WrAddr off %x",FP_OFF(WrAddr));
if(WrAddr[0] == blockType)
{// look at index (first byte after Block_Type)
if(WrAddr[1] == blockIndex)
{
(*version)++; // keep track of how many matching entries we've found.
getVer++;
GoodBlock = WrAddr;
if((getVer == 0x00) || ((blockType == 0xff) && (blockIndex == 0xff)) )
{ // If getVer hit's zero, than we want this paricular entry -used
// to find backup copies of data.
msgx("GoodBlock seg %x",(WORD)((DWORD)GoodBlock >> 16));
msgx("GoodBlock off %x",(WORD)GoodBlock);
return GoodBlock;
}
}
}
// else go to next block.
length = getLength(WrAddr);
// if length > UserPrefSectorSize, than either it's 0xffff becuase the location is blank and
// we've reachd the end of our data, or it's corrupt, either case stop here.
if((length > HUGE_OFF(FLASHUserPrefSectorSize)) || (length == 0x00))
{
msgx("length out of range %d",length);
msgx("GoodBlock seg %x",FP_SEG(GoodBlock));
msgx("GoodBlock off %x",FP_OFF(GoodBlock));
msgx("WrAddr seg %x",FP_SEG(WrAddr));
msgx("WrAddr off %x",FP_OFF(WrAddr));
msgx("WrAddr[0] %x",(WORD)WrAddr[0]);
msgx("WrAddr[1] %x",(WORD)WrAddr[1]);
msgx("version %d",(WORD)*version);
msgx("blockType %x",(WORD)blockType);
msgx("blockIndex %x",(WORD)blockIndex);
return GoodBlock;
}
WrAddr += length;
DW_tmpAddress = HUGE(WrAddr);
}
while((DW_tmpAddress < HUGE(LastAddress)) && (DW_tmpAddress > HUGE(workingSector)));// make sure still in range.
msgx("end of sector",0);
msgx("version %d",(WORD)*version);
msgx("WrAddr seg %x",FP_SEG(WrAddr));
msgx("WrAddr off %x",FP_OFF(WrAddr));
msgx("GoodBlock seg %x",FP_SEG(GoodBlock));
msgx("GoodBlock off %x",FP_OFF(GoodBlock));
return GoodBlock;
}
//***************************************************************
// FUNCTION : prune
// USAGE :
// DESCRIPTION : Copy "good" data from current sector into the
// alternate sector, then erase the current sector. "good" data
// refers to the latest copy of an entry. If the user changes
// the ModeIndependent settings 100 times, only the last one is
// good, so that is the only entry that is copied to the alternate
// sector.
// INPUT : WrAddr should be pointing to the head of the
// current 'working' sector.
// OUTPUT : None
//***************************************************************
#if FAST_FLASH_PAGE_UPDATE
// The default buffer length is set to 256 bytes (= one page size of PMC flash).
// RAM resident command won't be called unless a buffer is almost full. This way can dramatically reduce
// the number of page writes and hence reduce saving time.
#define BUFFER_LENGTH 256
//***************************************************************
// FUNCTION : MakeCountTable
// DESCRIPTION : to make count table from gmc_RomDirectory[] array.
// The count table indicates how many nvram block entries exist before
// current blockType, for modeDependent block, it contains more than 1 entry.
//
// INPUT : gmc_RomDirectory[] array in nvtable.c file, generated by Workbench
//
// OUTPUT : B_CountTable
//
// RETURN : ret: gmd_TURE or gmd_FALSE;
//
// USED_REGS : None
//
// Algorithm : 1)to derive # of entries for each block type;
// 2)to accumulate # of entries before current block type;
//NOTE :
// In Workbench, all NVRAM block directory should be set in ROM, that is,
// the option "Put link in NVRAM directory" should NOT be checked.
// Otherwise, gmv_Size_RomDirectory wonn't reflect the total # of blockType.
//***************************************************************
static gmt_RET_STAT MakeCountTable(void)
{
BYTE i, end;
WORD length;
gmt_RET_STAT ret = gmd_TRUE;
//initialization
_fmemset(B_CountTable, 0, MAX_BLOCK_ENTRIES);
end = (gmv_Size_RomDirectory<MAX_BLOCK_ENTRIES?gmv_Size_RomDirectory:MAX_BLOCK_ENTRIES);
//to derive # of entries for each block type;
B_CountTable[0] = 0;
msgx("B_CountTable[i]: %d", end);
msgx("%d", B_CountTable[0]);
for(i=1; i<end; i++)
{
length = gmc_RomDirectory[i-1].length & (~CRC_FLAG);
if(gmc_RomDirectory[i-1].length & CRC_FLAG)
length += CRC_SIZE;
if(gmc_RomDirectory[i-1].length)
B_CountTable[i] = (BYTE)((gmc_RomDirectory[i].address - gmc_RomDirectory[i-1].address) / length);
else
B_CountTable[i] = 0;
msgx("addrDiff: 0x%x", gmc_RomDirectory[i].address - gmc_RomDirectory[i-1].address);
msgx("length: 0x%x", length);
msgx("%d", B_CountTable[i]);
}
//to accumulate # of entries before current block type;
for(i=1; i<end; i++)
{
B_CountTable[i] += B_CountTable[i-1];
msgx("%d", B_CountTable[i]);
}
//to check buffer/array limit
if(gmv_Size_RomDirectory > MAX_BLOCK_ENTRIES ||
B_CountTable[end-1] > MAX_TOTAL_INDICES)
ret = gmd_FALSE; //fail
else
ret = gmd_TRUE;
return ret;
}
//***************************************************************
// FUNCTION : IsValidBlockEntry
// DESCRIPTION : to check whether block is valid
//
// INPUT : blockId, index
//
// OUTPUT : none
//
// RETURN : ret: gmd_TURE or gmd_FALSE;
//
// NOTE : this function skips index check for last blockType (blockId<gmv_Size_RomDirectory-1)
//
//***************************************************************
static gmt_RET_STAT IsValidBlockEntry(BYTE blockId, BYTE index)
{
gmt_RET_STAT ret = gmd_TRUE;
if(blockId>=gmv_Size_RomDirectory || index>=MAX_TOTAL_INDICES)
return gmd_FALSE;
if(blockId<gmv_Size_RomDirectory-1)
{
if(index < (B_CountTable[blockId+1]-B_CountTable[blockId]) )
ret = gmd_TRUE;
else
ret = gmd_FALSE;
}
return ret;
}
//***************************************************************
// FUNCTION : prune
// USAGE :
// DESCRIPTION : Copy "good" data from current sector into the
// alternate sector, then erase the current sector. "good" data
// refers to the latest copy of an entry. This version search current
// sector once to build W_AddrTable, then copy data to another sector
// in page mode, the buffer size is 256 bytes by default
// INPUT : WrAddr should be pointing to the head of the
// current 'working' sector.
// OUTPUT : None
//***************************************************************
void prune(void)
{
WORD offset, length, offsetInBlock;
BYTE blockType, index, pos;
BYTE far *alternateSector, far *altPtr;
BYTE buff[BUFFER_LENGTH];
WORD freeSpace;
BYTE i;
BYTE far *WrAddr;
DWORD LastAddress;
//initialize address map table with invalid address 0xffff
_fmemset(W_AddrTable, 0xff, MAX_TOTAL_INDICES*sizeof(WORD));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -