mirror of
https://github.com/dougg3/mac-rom-simm-programmer.git
synced 2024-11-26 02:49:16 +00:00
Added untested support for erasing a specific portion of the SIMM
(in 256 KB increments). Won't be able to test it until I implement it in the control software as well, but I think it should work.
This commit is contained in:
parent
d484d126e5
commit
3252f66749
@ -256,6 +256,91 @@ void ExternalMem_EraseChips(uint8_t chipsMask)
|
|||||||
ExternalMem_WaitCompletion(chipsMask);
|
ExternalMem_WaitCompletion(chipsMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExternalMem_EraseSectors(uint32_t address, uint32_t length, uint8_t chipsMask)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
// Make sure the area requested to be erased is on 64 KB boundaries.
|
||||||
|
// True, the 2 MB SIMM doesn't require 64 KB boundaries, but I'm going to
|
||||||
|
// keep it to 2 MB boundaries to simplify everything.
|
||||||
|
#define ERASABLE_SECTOR_SIZE (64*1024UL*1024UL)
|
||||||
|
if ((address & ERASABLE_SECTOR_SIZE) ||
|
||||||
|
(length & ERASABLE_SECTOR_SIZE))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're good to go. Let's do it.
|
||||||
|
|
||||||
|
if (curChipType == ChipType8BitData_4MBitSize)
|
||||||
|
{
|
||||||
|
#define SECTOR_SIZE_4MBIT (128)
|
||||||
|
// This chip sucks because you have to erase each sector with its own
|
||||||
|
// complete erase unlock command, which can take a while. At least
|
||||||
|
// individual erase operations are much faster on this chip...
|
||||||
|
while (length)
|
||||||
|
{
|
||||||
|
// Start the erase command
|
||||||
|
ExternalMem_UnlockChips(chipsMask);
|
||||||
|
ExternalMem_WriteCycle(0x55555555UL, 0x80808080UL);
|
||||||
|
ExternalMem_UnlockChips(chipsMask);
|
||||||
|
|
||||||
|
// Now provide a sector address, but only one. Then the whole
|
||||||
|
// unlock sequence has to be done again after this sector is done.
|
||||||
|
ExternalMem_WriteCycle(address, 0x20202020UL);
|
||||||
|
|
||||||
|
address += SECTOR_SIZE_4MBIT;
|
||||||
|
length -= SECTOR_SIZE_4MBIT;
|
||||||
|
|
||||||
|
// Wait for completion of this individual erase operation before
|
||||||
|
// we can start a new erase operation.
|
||||||
|
ExternalMem_WaitCompletion(chipsMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else if (curChipType == ChipType8Bit16BitData_16MBitSize)
|
||||||
|
{
|
||||||
|
#define SECTOR_SIZE_16MBIT (64*1024UL*1024UL)
|
||||||
|
// This chip is nicer because it can take all the sector addresses at
|
||||||
|
// once and then do the final erase operation in one fell swoop.
|
||||||
|
|
||||||
|
// Start the erase command
|
||||||
|
ExternalMem_UnlockChips(chipsMask);
|
||||||
|
ExternalMem_WriteCycle(0xAAAAAAAAUL, 0x80808080UL);
|
||||||
|
ExternalMem_UnlockChips(chipsMask);
|
||||||
|
|
||||||
|
// Now provide as many sector addresses as needed to erase.
|
||||||
|
|
||||||
|
// The first address is a bit of a special case because the boot sector
|
||||||
|
// actually has finer granularity for sector sizes.
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
ExternalMem_WriteCycle(0x00000000UL, 0x30303030UL);
|
||||||
|
ExternalMem_WriteCycle(0x00004000UL, 0x30303030UL);
|
||||||
|
ExternalMem_WriteCycle(0x00006000UL, 0x30303030UL);
|
||||||
|
ExternalMem_WriteCycle(0x00008000UL, 0x30303030UL);
|
||||||
|
address += SECTOR_SIZE_16MBIT;
|
||||||
|
length -= SECTOR_SIZE_16MBIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining sectors can use a more generic algorithm
|
||||||
|
while (length)
|
||||||
|
{
|
||||||
|
ExternalMem_WriteCycle(address, 0x30303030UL);
|
||||||
|
address += SECTOR_SIZE_16MBIT;
|
||||||
|
length -= SECTOR_SIZE_16MBIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for completion of the entire erase operation
|
||||||
|
ExternalMem_WaitCompletion(chipsMask);
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void ExternalMem_WaitCompletion(uint8_t chipsMask)
|
void ExternalMem_WaitCompletion(uint8_t chipsMask)
|
||||||
{
|
{
|
||||||
// Mark the chips not requested as already completed,
|
// Mark the chips not requested as already completed,
|
||||||
@ -408,3 +493,8 @@ void ExternalMem_SetChipType(ChipType type)
|
|||||||
{
|
{
|
||||||
curChipType = type;
|
curChipType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChipType ExternalMem_GetChipType(void)
|
||||||
|
{
|
||||||
|
return curChipType;
|
||||||
|
}
|
||||||
|
@ -94,6 +94,7 @@ void ExternalMem_IdentifyChips(struct ChipID *chips);
|
|||||||
|
|
||||||
// Erases the chips requested
|
// Erases the chips requested
|
||||||
void ExternalMem_EraseChips(uint8_t chipsMask);
|
void ExternalMem_EraseChips(uint8_t chipsMask);
|
||||||
|
bool ExternalMem_EraseSectors(uint32_t address, uint32_t length, uint8_t chipsMask);
|
||||||
|
|
||||||
// Writes a byte to the chips requested at the specified address
|
// Writes a byte to the chips requested at the specified address
|
||||||
void ExternalMem_WriteByteToChips(uint32_t address, uint32_t data, uint8_t chipsMask);
|
void ExternalMem_WriteByteToChips(uint32_t address, uint32_t data, uint8_t chipsMask);
|
||||||
@ -107,5 +108,6 @@ uint8_t ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, ui
|
|||||||
|
|
||||||
// Tells which flash command protocol to use
|
// Tells which flash command protocol to use
|
||||||
void ExternalMem_SetChipType(ChipType type);
|
void ExternalMem_SetChipType(ChipType type);
|
||||||
|
ChipType ExternalMem_GetChipType(void);
|
||||||
|
|
||||||
#endif /* EXTERNAL_MEM_H_ */
|
#endif /* EXTERNAL_MEM_H_ */
|
||||||
|
@ -45,7 +45,8 @@ typedef enum ProgrammerCommand
|
|||||||
SetSIMMTypePLCC32_2MB,
|
SetSIMMTypePLCC32_2MB,
|
||||||
SetSIMMTypeLarger,
|
SetSIMMTypeLarger,
|
||||||
SetVerifyWhileWriting,
|
SetVerifyWhileWriting,
|
||||||
SetNoVerifyWhileWriting
|
SetNoVerifyWhileWriting,
|
||||||
|
ErasePortion
|
||||||
} ProgrammerCommand;
|
} ProgrammerCommand;
|
||||||
|
|
||||||
// After a command is sent, the programmer will always respond with
|
// After a command is sent, the programmer will always respond with
|
||||||
@ -166,4 +167,21 @@ typedef enum ComputerBootloaderEraseWriteRequest
|
|||||||
ComputerBootloaderCancel
|
ComputerBootloaderCancel
|
||||||
} ComputerBootloaderEraseWriteRequest;
|
} ComputerBootloaderEraseWriteRequest;
|
||||||
|
|
||||||
|
// ------------------------- ERASE PORTION OF CHIP PROTOCOL -------------------------
|
||||||
|
// If the command is ErasePortion, the programmer will reply CommandReplyOK.
|
||||||
|
// Next, the program will send the beginning position to erase as a 4-byte little
|
||||||
|
// endian integer, followed by the length to erase as a 4-byte little endian
|
||||||
|
// integer. The programmer will reply with ProgrammerErasePortionOK to signify
|
||||||
|
// that the erase is beginning, followed by ProgrammerErasePortionFinished when
|
||||||
|
// everything is done.
|
||||||
|
// The length and position to erase must be on 256 KB boundaries and shouldn't
|
||||||
|
// go past the end of the selected type of chip. If any error occurs, it will
|
||||||
|
// reply with ProgrammerErasePortionError instead.
|
||||||
|
typedef enum ProgrammerErasePortionOfChipReply
|
||||||
|
{
|
||||||
|
ProgrammerErasePortionOK = 0,
|
||||||
|
ProgrammerErasePortionError,
|
||||||
|
ProgrammerErasePortionFinished
|
||||||
|
} ProgrammerErasePortionOfChipReply;
|
||||||
|
|
||||||
#endif /* PROGRAMMER_PROTOCOL_H_ */
|
#endif /* PROGRAMMER_PROTOCOL_H_ */
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#define MAX_CHIP_SIZE (2UL * 1024UL * 1024UL)
|
#define MAX_CHIP_SIZE (2UL * 1024UL * 1024UL)
|
||||||
#define READ_CHUNK_SIZE_BYTES 1024UL
|
#define READ_CHUNK_SIZE_BYTES 1024UL
|
||||||
#define WRITE_CHUNK_SIZE_BYTES 1024UL
|
#define WRITE_CHUNK_SIZE_BYTES 1024UL
|
||||||
|
#define ERASE_SECTOR_SIZE_BYTES (256UL * 1024UL)
|
||||||
#if ((READ_CHUNK_SIZE_BYTES % 4) != 0)
|
#if ((READ_CHUNK_SIZE_BYTES % 4) != 0)
|
||||||
#error Read chunk size should be a multiple of 4 bytes
|
#error Read chunk size should be a multiple of 4 bytes
|
||||||
#endif
|
#endif
|
||||||
@ -54,7 +55,8 @@ typedef enum ProgrammerCommandState
|
|||||||
ReadingChipsReadLength,
|
ReadingChipsReadLength,
|
||||||
ReadingChips,
|
ReadingChips,
|
||||||
ReadingChipsUnableSendError,
|
ReadingChipsUnableSendError,
|
||||||
WritingChips
|
WritingChips,
|
||||||
|
ErasePortionReadingPosLength
|
||||||
} ProgrammerCommandState;
|
} ProgrammerCommandState;
|
||||||
static ProgrammerCommandState curCommandState = WaitingForCommand;
|
static ProgrammerCommandState curCommandState = WaitingForCommand;
|
||||||
|
|
||||||
@ -66,6 +68,8 @@ static uint8_t readLengthByteIndex;
|
|||||||
static int16_t writePosInChunk = -1;
|
static int16_t writePosInChunk = -1;
|
||||||
static uint16_t curWriteIndex = 0;
|
static uint16_t curWriteIndex = 0;
|
||||||
static bool verifyDuringWrite = false;
|
static bool verifyDuringWrite = false;
|
||||||
|
static uint32_t erasePosition;
|
||||||
|
static uint32_t eraseLength;
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
void USBSerial_HandleWaitingForCommandByte(uint8_t byte);
|
void USBSerial_HandleWaitingForCommandByte(uint8_t byte);
|
||||||
@ -74,6 +78,7 @@ void USBSerial_HandleReadingChipsReadLengthByte(uint8_t byte);
|
|||||||
void USBSerial_SendReadDataChunk(void);
|
void USBSerial_SendReadDataChunk(void);
|
||||||
void USBSerial_HandleWritingChipsByte(uint8_t byte);
|
void USBSerial_HandleWritingChipsByte(uint8_t byte);
|
||||||
void USBSerial_ElectricalTest_Fail_Handler(uint8_t index1, uint8_t index2);
|
void USBSerial_ElectricalTest_Fail_Handler(uint8_t index1, uint8_t index2);
|
||||||
|
void USBSerial_HandleErasePortionReadPosLengthByte(uint8_t byte);
|
||||||
|
|
||||||
// Read/write to USB serial macros -- easier than retyping
|
// Read/write to USB serial macros -- easier than retyping
|
||||||
// CDC_Device_XXX(&VirtualSerial_CDC_Interface...) every time
|
// CDC_Device_XXX(&VirtualSerial_CDC_Interface...) every time
|
||||||
@ -107,6 +112,9 @@ void USBSerial_Check(void)
|
|||||||
case WritingChips:
|
case WritingChips:
|
||||||
USBSerial_HandleWritingChipsByte((uint8_t)recvByte);
|
USBSerial_HandleWritingChipsByte((uint8_t)recvByte);
|
||||||
break;
|
break;
|
||||||
|
case ErasePortionReadingPosLength:
|
||||||
|
USBSerial_HandleErasePortionReadPosLengthByte((uint8_t)recvByte);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,6 +235,13 @@ void USBSerial_HandleWaitingForCommandByte(uint8_t byte)
|
|||||||
verifyDuringWrite = false;
|
verifyDuringWrite = false;
|
||||||
SendByte(CommandReplyOK);
|
SendByte(CommandReplyOK);
|
||||||
break;
|
break;
|
||||||
|
case ErasePortion:
|
||||||
|
readLengthByteIndex = 0;
|
||||||
|
eraseLength = 0;
|
||||||
|
erasePosition = 0;
|
||||||
|
curCommandState = ErasePortionReadingPosLength;
|
||||||
|
SendByte(CommandReplyOK);
|
||||||
|
break;
|
||||||
// We don't know what this command is, so reply that it was invalid.
|
// We don't know what this command is, so reply that it was invalid.
|
||||||
default:
|
default:
|
||||||
SendByte(CommandReplyInvalid);
|
SendByte(CommandReplyInvalid);
|
||||||
@ -416,6 +431,76 @@ void USBSerial_ElectricalTest_Fail_Handler(uint8_t index1, uint8_t index2)
|
|||||||
SendByte(index2);
|
SendByte(index2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're figuring out the position/length to erase, parse it here.
|
||||||
|
void USBSerial_HandleErasePortionReadPosLengthByte(uint8_t byte)
|
||||||
|
{
|
||||||
|
// Read in the position and length to erase
|
||||||
|
if (readLengthByteIndex < 4)
|
||||||
|
{
|
||||||
|
erasePosition |= (((uint32_t)byte) << (8*readLengthByteIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eraseLength |= (((uint32_t)byte) << (8*(readLengthByteIndex - 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++readLengthByteIndex >= 8)
|
||||||
|
{
|
||||||
|
ChipType chipType = ExternalMem_GetChipType();
|
||||||
|
bool eraseSuccess = false;
|
||||||
|
|
||||||
|
// Ensure they are both within limits of sector size erasure
|
||||||
|
if (((erasePosition & ERASE_SECTOR_SIZE_BYTES) == 0) &&
|
||||||
|
((eraseLength & ERASE_SECTOR_SIZE_BYTES) == 0))
|
||||||
|
{
|
||||||
|
uint32_t boundary = eraseLength + erasePosition;
|
||||||
|
|
||||||
|
// Ensure they are within the limits of the chip size too
|
||||||
|
if (chipType == ChipType8BitData_4MBitSize)
|
||||||
|
{
|
||||||
|
if (boundary <= (2 * 1024UL * 1024UL))
|
||||||
|
{
|
||||||
|
// OK! We're erasing certain sectors of a 2 MB SIMM.
|
||||||
|
SendByte(ProgrammerErasePortionOK);
|
||||||
|
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
|
||||||
|
if (ExternalMem_EraseSectors(erasePosition/NUM_CHIPS,
|
||||||
|
eraseLength/NUM_CHIPS, ALL_CHIPS))
|
||||||
|
{
|
||||||
|
eraseSuccess = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chipType == ChipType8Bit16BitData_16MBitSize)
|
||||||
|
{
|
||||||
|
if (boundary <= (8 * 1024UL * 1024UL))
|
||||||
|
{
|
||||||
|
// OK! We're erasing certain sectors of an 8 MB SIMM.
|
||||||
|
SendByte(ProgrammerErasePortionOK);
|
||||||
|
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
|
||||||
|
if (ExternalMem_EraseSectors(erasePosition/NUM_CHIPS,
|
||||||
|
eraseLength/NUM_CHIPS, ALL_CHIPS))
|
||||||
|
{
|
||||||
|
eraseSuccess = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eraseSuccess)
|
||||||
|
{
|
||||||
|
// Not on a sector boundary for erase position and/or length
|
||||||
|
SendByte(ProgrammerErasePortionFinished);
|
||||||
|
curCommandState = WaitingForCommand;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not on a sector boundary for erase position and/or length
|
||||||
|
SendByte(ProgrammerErasePortionError);
|
||||||
|
curCommandState = WaitingForCommand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LUFA event handler for when the USB configuration changes.
|
// LUFA event handler for when the USB configuration changes.
|
||||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user