📄 flash_nvram.c
字号:
// INPUT : B_BlockType (block id), B_index (block index), buffer, offset, length
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
gmt_RET_STAT pp_ReadNVRAMBlock(BYTE B_BlockType, BYTE B_Index, BYTE * Bp_Buffer, WORD W_Offset, WORD W_Length )
{
BYTE far *pbAddr;
BYTE version = 0x00;
// if findBockType returns NULL_PTR (0x00), and the version number
// returned is non-zero, then it did find a valid block, but the most
// recent is corrupt, so search again but with a version number one
// less then the one returned.
do
{
if((pbAddr = findBlockType(B_BlockType,B_Index,&version)) != NULL_PTR)
{
if(!checkChecksum(pbAddr))
{
pbAddr = NULL_PTR;
msg("version bad: %d",(WORD)version);
}
}
}while(((DWORD)pbAddr == NULL_PTR) && (version-- > 0x01));
if((DWORD)pbAddr == NULL_PTR)
{
msg("entry not found",0);
return gmd_FAIL; // couldn't find block
}
if(W_Length == 0x00)
W_Length = getLength(pbAddr); // if no length supplied, use full length.
_fmemcpy(Bp_Buffer, &pbAddr[BLOCK_DATA_OFFSET + W_Offset], W_Length);
return gmd_OK;
}
//***************************************************************
// FUNCTION : pp_WriteNVRAMBlock
// DESCRIPTION : Write data block
// INPUT : B_BlockType (block id), B_index (block index), buffer, offset, length
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
gmt_RET_STAT pp_WriteNVRAMBlock(BYTE B_BlockType, BYTE B_Index, BYTE *Bp_Buffer, WORD W_Offset, WORD W_Length)
{
BYTE far *pbAddr;
BYTE version = 0x00, createHeader = gmd_TRUE;
WORD room, i;
block_hdr_type hdr;
hdr.Type = B_BlockType;
hdr.Index = B_Index;
hdr.Size = W_Length + W_Offset + sizeof(block_hdr_type);
hdr.Checksum = 0;
for(i=0;i < W_Length;i++)
{
hdr.Checksum += Bp_Buffer[i];
}
// 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.
{
msg("..prune..",0);
prune();
// 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.
}
// 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;
}
//***************************************************************
// FUNCTION : executeRamResidentCmd
// DESCRIPTION : copies RAM resident code to RAM buffer and executes code.
// FLASH_NV_WRITE -> write contents of buffer to flash WrAddr
// FLASH_NV_SECTOR_ERASE -> erases sector at addres WrAddr.
// INPUT : cmd, WrAddr, Length, buffer.
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
#define ENABLE_INT() asm{ STI } // Enable all interrupts
#if( FLASH_TYPE == SPI_FLASH )
static void executeRamResidentCmd(flash_nv_cmd cmd, BYTE far *WrAddr, WORD length, BYTE far *buff)
{
DWORD DW_WrAddr = ((DWORD) WrAddr) & 0xFF000000UL;
RamResidentEntry RamEntry = (RamResidentEntry)&DecompBuf[0];
DWORD DW_tmpAddr;
//Stop vblank ISR to avoid horizontal bar garbage during saving data to flash
StopADCCalibrationISR();
DW_tmpAddr = HUGE(WrAddr);
if( (DW_tmpAddr < HUGE(FLASHUserPrefSectorStart)) || ((DW_tmpAddr + length) > HUGE(FLASHUserPrefSectorStart + 2 * FLASHUserPrefSectorSize) ) )
{
if(cmd != FLASH_NV_AUTODETECT)
{
inp_msg("ERROR: Attempt of write to the wrong address in the flash (ignored)",0);
inp_msg("Address High = %x", (WORD)(((unsigned long)WrAddr) >> 16));
inp_msg("Address Low = %x", (WORD)WrAddr);
return;
}
}
if(FLASH_NV_AUTODETECT == cmd)
{
//msg("AUTODETECT",0);
#if(DISABLE_AUTODETECT == 0)
_fmemcpy(&DecompBuf[0],&RamResidentCode_AutoDetect[0],sizeof(RamResidentCode_AutoDetect));
#else
msg("Error - AUTODETECT is disabled !",0);
return;
#endif
}
else
{
switch(B_FlashChipID)
{
case SST25VF010_ID:
#if(DISABLE_SST == 0)
_fmemcpy(&DecompBuf[0],&RamResidentCode_SST[0],sizeof(RamResidentCode_SST));
msgx("SST",0);
break;
#else
msg("Error - SST is disabled !",0);
return;
#endif
case PM25LV010_ID:
#if(DISABLE_PMC == 0)
_fmemcpy(&DecompBuf[0],&RamResidentCode_PMC[0],sizeof(RamResidentCode_PMC));
msgx("PMC",0);
break;
#else
msg("Error - PMC is disabled !",0);
return;
#endif
case ST0000000_ID:
#if(DISABLE_ST == 0)
_fmemcpy(&DecompBuf[0],&RamResidentCode_ST[0],sizeof(RamResidentCode_ST));
msgx("ST",0);
break;
#else
msg("Error - ST is disabled !",0);
return;
#endif
default:
msg("Error - B_FlashChipID is wrong !",B_FlashChipID);
return; // added
};
}
// Put WrAddr into format that ram routine wants: unified 20-bit address
DW_WrAddr = HUGE(WrAddr);
msgx("RAM resident START",0);
gm_DisableInterrupts();
RamEntry(cmd,(BYTE far *)DW_WrAddr,length,buff);
ENABLE_INT();
msgx("RAM resident END",0);
//Resume vblank ISR for adc calibration
StartADCCalibrationISR();
}
#else
static void executeRamResidentCmd(flash_nv_cmd cmd, BYTE far *WrAddr, WORD length, BYTE far *buff)
{
RamResidentEntry RamEntry = (RamResidentEntry)&DecompBuf[0];
DWORD DW_tmpAddr;
DW_tmpAddr = HUGE(WrAddr);
if( (DW_tmpAddr < HUGE(FLASHUserPrefSectorStart)) || ((DW_tmpAddr + length) > HUGE(FLASHUserPrefSectorStart + 2 * FLASHUserPrefSectorSize) ) )
{
inp_msg("ERROR: Attempt of write to the wrong address in the flash (ignored)",0);
inp_msg("Address High = %x", (WORD)(((unsigned long)WrAddr) >> 16));
inp_msg("Address Low = %x", (WORD)WrAddr);
return;
}
_fmemcpy(&DecompBuf[0],&RamResidentCode[0],sizeof(RamResidentCode));
msgx("RAM resident START",0);
gm_DisableInterrupts();
RamEntry(cmd,WrAddr,length,buff);
ENABLE_INT();
msgx("RAM resident END",0);
}
#endif
//***************************************************************
// FUNCTION : findBlockType
// USAGE :
// DESCRIPTION : Scans through FLASH sector looking for BlockType.
// data blocks are in the following format:
// BYTE Block_Type; (i.e. NVRAM_MODEINDEP_USERPREF )
// BYTE Block_Index (i.e. 3rd MODE_DEPENDENT entry)
// WORD Block_size; size of entry (i.e. 1(Block_Type) 1(Block_Index)+ 2(Block_Size) + 1(checksum) + 36(data) + = 41 bytes
// BYTE Checksum;
// BYTE Data[];
// returns number of bytes remaining in the sector.
// INPUT : blockType (block_id), blockIndex, version.
// version is used to retrieve backup copies of data.
// OUTPUT : Address of block.
//***************************************************************
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("empty block",0);
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++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -