⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flash_nvram.c

📁 GM5621原代码
💻 C
📖 第 1 页 / 共 3 页
字号:
// 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 + -