//--------------------------------------------------------- // 28FxxxC Boot Block Flash Memory: XJEase device file // 28FxxxC.xje Revision: 1.12 // (c)2001-2008 XJTAG Limited // // Disclaimer: XJTAG makes no guarantees whatsoever // about this code. You use it at your own risk ... // This code requires XJTAG version 1.4 or later. // // This file tests Non-JTAG Flash using TestNonDestructive()(INT result) // TestDestructive()(INT result) //--------------------------------------------------------- DEVICE NAME := "28FxxxC - Boot Block Flash Memory" PINS // TSOP 48 ADDR := 9 /*64M*/, 10 /*32M*/, 15 /*16M*/, 16, 17, 48, 1, 2, 3, 4, 5, 6, 7, 8, 18, 19, 20, 21, 22, 23, 24, 25; DATA := 45, 43, 41, 39, 36, 34, 32, 30, 44, 42, 40, 38, 35, 33, 31, 29; nWE := 11; nOE := 28; nCE := 26; nRP := 12; /* //Easy BGA 64 ADDR := C6, B6, B3, A3, B2, G8, A8, B8, C8, C7, B7, A7, D8, D7, C2, A2, D2, D1, C1, B1, A1, G1; DATA := G6, F6, G5, E5, F4, F3, E3, E1, H6, E6, F5, G4, E4, G3, E2, F2; nWE := C4; nOE := H2; nCE := F1; nRP := B4; */ END; DISABLE DEVICE nOE := 1; nCE := 1; END; TEST COVERAGE ADDR := SHORTS OPEN HI LO; DATA := SHORTS OPEN HI LO; nWE := OPEN HI LO; nCE := OPEN HI LO; nOE := OPEN HI LO; nRP := OPEN LO; END; FILES "memtestFlash.xje"; //"DataReader.xje"; END; END; //----------------------------------------------------------------------------- // Constants //----------------------------------------------------------------------------- CONST INT READ_ARRAY := 0x00FF; CONST INT READ_ID := 0x0090; CONST INT READ_QUERY := 0x0098; CONST INT READ_STATUS := 0x0070; CONST INT CLEAR_STATUS := 0x0050; CONST INT WRITE_BUFFER := 0x00E8; CONST INT WORD_PROGRAM := 0x0040; CONST INT BLOCK_ERASE := 0x0020; CONST INT BLOCK_E_SUSP := 0x00B0; CONST INT BLOCK_E_RESM := 0x00D0; CONST INT CONFIG := 0x00B8; CONST INT SET_LOCK := 0x0060; CONST INT CLEAR_LOCK := 0x0060; CONST INT CONFIRM := 0x00D0; CONST INT PROTECT := 0x00C0; CONST INT MANUFACTURER_ADDR := 0x0000; CONST INT DEVICE_ADDR := 0x0001; CONST INT MANUFACTURER_ID := 0x0089; //CONST INT DEVICE_ID := 0x88C0;// 8 MBit Top boot block //CONST INT DEVICE_ID := 0x88C1;// 8 MBit Bottom boot block //CONST INT DEVICE_ID := 0x88C2;// 16 MBit Top boot block //CONST INT DEVICE_ID := 0x88C3;// 16 MBit Bottom boot block //CONST INT DEVICE_ID := 0x88C4;// 32 MBit Top boot block //CONST INT DEVICE_ID := 0x88C5;// 32 MBit Bottom boot block CONST INT DEVICE_ID := 0x88CC;// 64 MBit Top boot block //CONST INT DEVICE_ID := 0x88CD;// 64 MBit Bottom boot block CONST INT BLOCK_LENGTH := 0x00008000; CONST INT BUFFER_LENGTH := 0x10; CONST INT DATA_BUS_WIDTH := WIDTHOF(DATA); CONST INT ADDR_BUS_WIDTH := WIDTHOF(ADDR); CONST INT FLASH_SIZE := (1<<ADDR_BUS_WIDTH)*DATA_BUS_WIDTH; CONST INT RESULT_PASS := FALSE; CONST INT RESULT_FAIL := TRUE; CONST INT FLASH_PROG_LEVEL_NONE := 0; // Flash erased everywhere CONST INT FLASH_PROG_LEVEL_SOME := 1; // Flash programmed enough to verify data/addr bus for opens/stucks and data bus // for shorts. Ie. Data written to a single block, or small number of blocks. CONST INT FLASH_PROG_LEVEL_LOTS := 2; // Flash programmed enough to data/addr bus for opens/stucks and shorts. // Ie. Data written to a large number of blocks. //------------------------------------------------------------------------ // The higher this level is set, the more test coverage will be attained. // The aim is to set the highest level possible with the test still passing. // If the flash is totally erased, the test will only pass if this variable // is set to FLASH_PROG_LEVEL_NONE. //------------------------------------------------------------------------ CONST INT FLASH_PROG_LEVEL := FLASH_PROG_LEVEL_NONE; CONST INT DEBUG := FALSE; // Globals INT ALL_ONES WIDTH FLASH_SIZE := ~0[(FLASH_SIZE-1)..0]; INT dataSet WIDTH FLASH_SIZE; //------------------------------------------------------------------------ // Includes Read ID test and optional Readonly Data and Address bus tests. // The optional test only be used if the flash has been sufficiently // programmed (by setting FlASH_PROGRAMMED to TRUE). // Much quicker alternative to Destructive test. //------------------------------------------------------------------------ TestNonDestructive()(INT result) INT tempResult; result := RESULT_PASS; PRINT("\n\nStarting Read ID test...\n"); ReadIDtest()(result); IF (FLASH_PROG_LEVEL > FLASH_PROG_LEVEL_NONE) THEN PRINT("\nStarting Non-Destructive memory test\n"); MemTestNonDestructive()(tempResult); IF tempResult = RESULT_FAIL THEN result := RESULT_FAIL; END; ELSE PRINT("FLASH_PROG_LEVEL currently set to FLASH_PROG_LEVEL_NONE\nAlthough the ReadID test excersises the data/addr bus and control lines,\na more comprehensive test can be done by changing FLASH_PROG_LEVEL\nThis can only be done if the flash is progammed (see device file for more information).\n\n"); END; IF result = RESULT_FAIL THEN PRINT("Non Destructive Memory Test FAILED...\n\n"); ELSE PRINT("Non Destructive Memory Test PASSED...\n\n"); END; END; //------------------------------------------------------------------------ // Includes Read ID test, and optimised destructive memory test. // Slower than non destructive test, but more reliable. //------------------------------------------------------------------------ TestDestructive()(INT result) INT tempResult; result := RESULT_PASS; PRINT("\n\nStarting Read ID test...\n"); ReadIDtest()(result); PRINT("\nStarting Destructive memory test\n"); IF (result = RESULT_PASS) THEN MemTestDestructive()(tempResult); IF tempResult = RESULT_FAIL THEN result := RESULT_FAIL; END; ELSE TestDetail(TRUE)(); END; IF ((result = RESULT_PASS) && WRITEABLE(nCE)) THEN PRINT("\nTesting Chip Enable\n"); TestChipEnable()(result); IF result = RESULT_FAIL THEN PRINT("Chip Enable - pin: ",PINNUM(nCE)," stuck low\n"); END; END; IF result = RESULT_FAIL THEN PRINT("Destructive Memory Test FAILED...\n"); ELSE PRINT("Destructive Memory Test PASSED...\n"); END; END; //------------------------------------------------------ // ReadIDTest //------------------------------------------------------ ReadIDtest()(INT result) INT manufacturer; INT device; INT status; PRINT ("Checking Flash ", DEVICE_REF, " ID codes... "); Init()(); result := RESULT_FAIL; // Read Flash IDs. ReadID()(manufacturer, device); ReadStatus()(status); ResetFlash()(); IF DEBUG THEN PRINT("Manufacturer ID = 0x", HEX(manufacturer), ", "); PRINT("Device ID = 0x", HEX(device), ", "); PRINT("Status = 0x", HEX(status), ", "); END; // Check the IDs. IF DEBUG THEN PRINT("Check Flash ID...\n"); END; IF ((manufacturer != MANUFACTURER_ID) || (device != DEVICE_ID)) THEN PRINT("Read Manufacturer ID : 0x", HEX(manufacturer), ", expected to read 0x",HEX(MANUFACTURER_ID),"\n"); PRINT("Read Device ID = 0x", HEX(device), ", expected to read 0x", HEX(DEVICE_ID),"\n"); PRINT("failed.\nStatus=0x",HEX(status), "\n"); result := RESULT_FAIL; RETURN; END; PRINT("IDs verified\n"); result := RESULT_PASS; END; //----------------------------------------------------------------------------- Erase(INT startAddress, INT endAddress)(INT result) //----------------------------------------------------------------------------- INT i; INT address; result := RESULT_PASS; Init()(); IF (DEBUG) THEN PRINT("Erasing blocks from 0x", HEX(startAddress), " to 0x", HEX(endAddress), "\n"); END; address := startAddress; WriteCycle(address, CLEAR_LOCK); // Clear block locks. WriteCycle(address, CONFIRM); // Confirm. DO WHILE (address < endAddress) EraseBlock(address)(result); IF result = RESULT_FAIL THEN PRINT("Erase flash failed\n"); RETURN; END; address := address + BLOCK_LENGTH; END; PRINT("Erased.\n"); Init()(); END; //------------------------------------------------------ // EraseBlock //------------------------------------------------------ EraseBlock(INT address)(INT result) IF (DEBUG) THEN PRINT ("Erase Block at 0x", HEX(address), "\n"); ELSE PRINT("."); END; WriteCycle(address, CLEAR_LOCK); // Clear block locks. WriteCycle(address, CONFIRM); // Confirm. WaitReady(5000)(result); WriteCycle(address, BLOCK_ERASE); // Erase block. WriteCycle(address, CONFIRM); // Confirm. WaitReady(5000)(result); END; //------------------------------------------------------ // Checks chip enable isnt stuck low //------------------------------------------------------ TestChipEnable()(INT result) INT data; INT temp; result := RESULT_PASS; EraseBlock(0)(temp); WriteCycle(0, WORD_PROGRAM); // try programming with nCEO held high SET ADDR := 0, nWE := 0, nCE := 1, nOE := 1, DATA := 0; SET nCE := 1, nOE := 1, DATA := I, nWE := 1; WaitReady(100)(temp); ReadWord(0)(data); IF data = 0 THEN result := RESULT_FAIL; END; END; //----------------------------------------------------------------------------- ProgramWord(INT address, INT data)(INT result) //----------------------------------------------------------------------------- IF (DEBUG) THEN PRINT ("Program 0x", HEX(data), " to 0x", HEX(address), "\n"); END; WriteCycle(address, WORD_PROGRAM); WriteCycle(address, data); WaitReady(100)(result); END; //------------------------------------------------------ // ReadWord // Read a word from the flash //------------------------------------------------------ ReadWord(INT address)(INT data) ResetFlash()(); ReadCycle(address)(data); IF DEBUG THEN PRINT ("Read addr 0x", HEX(address), " = 0x", HEX(data), "\n"); END; END; //----------------------------------------------------- // ResetFlash //----------------------------------------------------- ResetFlash()() WriteCycle(0, READ_ARRAY); // Reset and switch to read array mode. END; //------------------------------------------------------ // Init //------------------------------------------------------ Init()() INT temp; IF DEBUG THEN PRINT("Initialising flash...\n")(); END; IF WRITEABLE(nRP) THEN SET nRP := 1; END; ClearStatus(); WaitReady(100)(temp); WriteCycle(0, READ_ARRAY); // Read array command. WriteCycle(0, READ_ARRAY); // Read array command. IF DEBUG THEN PRINT("Initialised\n"); END; END; //----------------------------------------------------------------------------- ReadID()(INT manufacturer, INT device) //----------------------------------------------------------------------------- WriteCycle(0, READ_ARRAY); // Read array command. WriteCycle(0x0, READ_ID); ReadCycle(MANUFACTURER_ADDR)(manufacturer); ReadCycle(DEVICE_ADDR)(device); END; //------------------------------------------------------ WaitReady (INT delay)(INT result) //------------------------------------------------------ INT status; INT timeout := NOW() + delay; result := RESULT_PASS; DO ReadStatus()(status); WHILE (status[7] = 0) IF NOW() > timeout THEN result := RESULT_FAIL; PRINT("\n*** Timeout waiting for flash ready ***\n"); RETURN; END; END; END; //----------------------------------------------------------------------------- ReadStatus()(INT status) //----------------------------------------------------------------------------- INT i; WriteCycle(0x0, READ_STATUS); // Read status command. ReadCycle(0x0)(status); IF DEBUG THEN IF !status[7] THEN ELSE // Full status check. IF status[6] THEN PRINT("Block erase suspended.\n"); END; IF status[5] THEN PRINT("Block erase/Clear locks error.\n"); END; IF status[4] THEN PRINT("Program/Set lock bit error.\n"); END; IF status[3] THEN PRINT("Program Voltage Range Error.\n"); END; IF status[2] THEN PRINT("Program suspended.\n"); END; IF status[1] THEN PRINT("Block lock detected.\n"); END; IF (status[6..1] != 0) THEN ClearStatus(); END; END; END; END; //----------------------------------------------------------------------------- ClearStatus()() //----------------------------------------------------------------------------- WriteCycle(0x0, CLEAR_STATUS)(); END; // ASSUME nCEO is writeable to rather than the other 2 pins //----------------------------------------------------------------------------- WriteCycle(INT address WIDTH ADDR_BUS_WIDTH, INT code WIDTH DATA_BUS_WIDTH)() //----------------------------------------------------------------------------- SET ADDR := address[(ADDR_BUS_WIDTH-1)..0], nWE := 0, nCE := 0, nOE := 1, DATA := code; SET nCE := 1, nOE := 1, DATA := I, nWE := 1; END; //------------------------------------------------------ ReadCycle(INT address WIDTH ADDR_BUS_WIDTH)(INT result WIDTH DATA_BUS_WIDTH) //------------------------------------------------------ SET ADDR := address[(ADDR_BUS_WIDTH-1)..0], nWE := 1, nCE := 0, nOE := 0, DATA := I; SET nCE := 1, nOE := 1, nWE := 1, result := DATA; END; //---------------------------------------------------------------------------------- // Functions required for use of device file with memtestFlash.xje //---------------------------------------------------------------------------------- PrintData(INT i)() PRINT(PINNUM(DATA[i])); END; PrintAddr(INT i)() PRINT(PINNUM(ADDR[i])); END; /*********************FLASH PROGRAMMING*********************************** //------------------------------------------------------ // ProgramFromSRecordFile // Program the flash from an S Record file //------------------------------------------------------ ProgramFromSRecordFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; PRINT("\n\nStarting flash programming from file ",fileName,"\n"); dataSet := ALL_ONES; ReadSRecordFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ProgramFromHexFile // Program the flash from a HEX file //------------------------------------------------------ ProgramFromHexFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; dataSet := ALL_ONES; ReadHEXFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ProgramFromBinFile // Program the flash from a BIN file //------------------------------------------------------ ProgramFromBINFile(STRING fileName)(INT result) INT addrLow; INT addrHigh; INT address; dataSet := ALL_ONES; ReadBINFile(fileName, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); ProgramFlash(addrLow, addrHigh - addrLow, dataSet)(result); // optional verification of memory written to flash VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //----------------------------------------------------------------------------- // Program Flash using "dataSet" variable. Optimised Programming //----------------------------------------------------------------------------- ProgramFlash (INT addrLow, INT numAddresses, INT dataSet)(INT result) //----------------------------------------------------------------------------- INT address := addrLow; INT endAddress := addrLow + numAddresses; INT byteNum; INT value; INT count := 0; INT tempCount :=0; result := RESULT_PASS; // Initialise the flash. Init(); IF DEBUG THEN PRINT("Programming from address 0x", HEX(addrLow), " for length 0x", HEX(numAddresses), "\n"); END; DO WHILE (address < endAddress) // Notify flash that we are going to write to buffer. WriteCycle(address, WRITE_BUFFER); // Write to buffer command value := (BUFFER_LENGTH-1)[DATA_BUS_WIDTH-1..0]; WriteCycle(address, value); // Length of buffer FOR byteNum := 0 FOR BUFFER_LENGTH WriteCycle(address, dataSet[(address+1)*DATA_BUS_WIDTH -1..address*DATA_BUS_WIDTH]); // Write data address := address + 1; END; WriteCycle(address, CONFIRM); // Confirm write buffer. WaitReady(500)(result); IF (result = RESULT_FAIL) THEN PRINT("Write to buffer failed\n"); RETURN; END; tempCount := ((address - addrLow)*100)/numAddresses; IF (tempCount != count && tempCount%5 = 0) THEN PRINT(tempCount, " percent programming complete\r"); count := tempCount; END; END; Init(); PRINT("Programming complete. \n"); END; //----------------------------------------------------------------- // VerifyFlash with a given dataSet //----------------------------------------------------------------- VerifyFlash(INT dataSet, INT addrLow, INT numAddresses)(INT result) //----------------------------------------------------------------- INT data WIDTH DATA_BUS_WIDTH; INT expectedData WIDTH DATA_BUS_WIDTH; INT address; INT count := 0; INT tempCount :=0; result := RESULT_FAIL; PRINT("Attempting to verify programmed data\n"); ResetFlash()(); FOR address := addrLow FOR numAddresses ReadCycle(address)(data); expectedData := dataSet[(address+1)*DATA_BUS_WIDTH-1..address*DATA_BUS_WIDTH]; IF (expectedData != data) THEN result := RESULT_FAIL; PRINT("\n*** Verify error at address 0x", HEX(address), ", data=0x", HEX(data), ", expected data=0x", HEX(expectedData), " ***\n"); RETURN; END; tempCount := ((address - addrLow)*100)/numAddresses; IF (tempCount != count && tempCount%5 = 0) THEN PRINT(tempCount, " percent verifying complete\r"); count := tempCount; END; END; PRINT("Verified OK. \n"); result := RESULT_PASS; END; //------------------------------------------------------ // Verify flash from a BIN file //------------------------------------------------------ VerifyFlashFromBINFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadBINFile(fileName, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("BIN file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // Verify flash from a HEX file //------------------------------------------------------ VerifyFlashFromHEXFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadHEXFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("HEX file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // Verify flash from an S Record file //------------------------------------------------------ VerifyFlashFromSRecordFile(STRING fileName)(INT result) //------------------------------------------------------ INT addrLow; INT addrHigh; result := RESULT_FAIL; dataSet := ALL_ONES; ReadSRecordFile(fileName, 0, 0, 16, DATA_BUS_WIDTH)(dataSet, addrLow, addrHigh, result); IF (result = RESULT_FAIL) THEN PRINT("S-Record file failed to be read\n"); END; VerifyFlash(dataSet, addrLow, addrHigh - addrLow)(result); END; //------------------------------------------------------ // ReadFlash // Read the flash and write contents in binary // format to an open file //------------------------------------------------------ ReadFlash(FILE fp, INT address, INT length)(INT result) INT endAddress := address + length; INT data; IF DEBUG THEN PRINT("Reading Flash\n"); END; ResetFlash()(); result := RESULT_FAIL; DO WHILE address <= endAddress ReadCycle(address)(data); FWRITE(fp, data[0..(DATA_BUS_WIDTH-1)])(); address := address + 1; END; result := RESULT_PASS; IF DEBUG THEN PRINT("Read completed OK\n"); END; END; //----------------------------------------------------------------------------- QueryFlash()() //----------------------------------------------------------------------------- INT data; INT i; INT byteAddress; INT wordAddress; WriteCycle(0, READ_QUERY); // Switch to read query command. PRINT("Query data :\n"); byteAddress := 0; wordAddress := 0; FOR i := 0 TO 0x2f ReadCycle(byteAddress)(data); PRINT("0x", HEX(byteAddress), "(0x", HEX(wordAddress), ")=0x", HEX(data), "\n"); byteAddress := byteAddress + 2; // 16-bit-wide flash devices wordAddress := wordAddress + 1; END; PRINT("\n"); WriteCycle(0, READ_ARRAY); // Switch to read array command. PRINT("Array data :\n"); byteAddress := 0; wordAddress := 0; FOR i := 0 TO 0x2f ReadCycle(byteAddress)(data); PRINT("0x", HEX(byteAddress), "(0x", HEX(wordAddress), ")=0x", HEX(data), "\n"); byteAddress := byteAddress + 2; // 16-bit wide flash devices wordAddress := wordAddress + 1; END; PRINT("\n"); Init()(); END; *************************************************************************/