diff --git a/drivers/parallel_flash.h b/drivers/parallel_flash.h index 7b112a6..931132b 100644 --- a/drivers/parallel_flash.h +++ b/drivers/parallel_flash.h @@ -55,6 +55,13 @@ typedef enum ParallelFlashChipType ParallelFlash_M29F160FB5AN6E2_x4, } ParallelFlashChipType; +/// Struct representing a group of identical erase sectors +typedef struct ParallelFlashEraseSectorGroup +{ + uint32_t count; + uint32_t size; +} ParallelFlashEraseSectorGroup; + // Tells which type of flash chip we are communicating with void ParallelFlash_SetChipType(ParallelFlashChipType type); ParallelFlashChipType ParallelFlash_ChipType(void); diff --git a/programmer_protocol.h b/programmer_protocol.h index 235c17a..b9333ff 100644 --- a/programmer_protocol.h +++ b/programmer_protocol.h @@ -47,7 +47,8 @@ typedef enum ProgrammerCommand ErasePortion, WriteChipsAt, ReadChipsAt, - SetChipsMask + SetChipsMask, + SetSectorLayout } ProgrammerCommand; // After a command is sent, the programmer will always respond with diff --git a/simm_programmer.c b/simm_programmer.c index 450817f..b6505c1 100644 --- a/simm_programmer.c +++ b/simm_programmer.c @@ -30,6 +30,7 @@ #include "led.h" #include "hardware.h" #include +#include /// Maximum size of an individual chip on a SIMM we read #define MAX_CHIP_SIZE (2UL * 1024UL * 1024UL) @@ -39,9 +40,19 @@ #if ((READ_WRITE_CHUNK_SIZE_BYTES % 4) != 0) #error Read/write chunk size should be a multiple of 4 bytes #endif -/// The smallest granularity for sector erase that we support +/// The smallest granularity for sector erase that we support. +/// Tehnically we could support more, but it's too complicated. #define ERASE_SECTOR_SIZE_BYTES (256UL * 1024UL) +/// The maximum number of erase groups we deal with +#define MAX_ERASE_SECTOR_GROUPS 10 + +/// The number of erase sector groups we know about currently. +/// If it's zero, we don't know, so fall back to defaults. +static uint8_t numEraseSectorGroups = 0; +/// The erase sector groups that we will pass to the programmer +static ParallelFlashEraseSectorGroup eraseSectorGroups[MAX_ERASE_SECTOR_GROUPS]; + /// Internal state so we know how to interpret the next-received byte typedef enum ProgrammerCommandState { @@ -53,6 +64,7 @@ typedef enum ProgrammerCommandState ReadingChipsReadStartPos, //!< Reading the start position for reading data from the SIMM WritingChipsReadingStartPos, //!< Reading the start position for writing data to the SIMM ReadingChipsMask, //!< Reading the bitmask of which chips should be programmed + ReadingSectorLayout, //!< Reading the erase sector layout } ProgrammerCommandState; static ProgrammerCommandState curCommandState = WaitingForCommand; @@ -85,6 +97,7 @@ static void SIMMProgrammer_HandleErasePortionReadPosLengthByte(uint8_t byte); static void SIMMProgrammer_HandleReadingChipsReadStartPosByte(uint8_t byte); static void SIMMProgrammer_HandleWritingChipsReadingStartPosByte(uint8_t byte); static void SIMMProgrammer_HandleReadingChipsMaskByte(uint8_t byte); +static void SIMMProgrammer_HandleReadingSectorLayoutByte(uint8_t byte); /** Initializes the SIMM programmer and prepares it for USB communication. * @@ -133,6 +146,9 @@ void SIMMProgrammer_Check(void) case ReadingChipsMask: SIMMProgrammer_HandleReadingChipsMaskByte(recvByte); break; + case ReadingSectorLayout: + SIMMProgrammer_HandleReadingSectorLayoutByte(recvByte); + break; } } @@ -265,6 +281,10 @@ static void SIMMProgrammer_HandleWaitingForCommandByte(uint8_t byte) curCommandState = ReadingChipsMask; USBCDC_SendByte(CommandReplyOK); break; + case SetSectorLayout: + curCommandState = ReadingSectorLayout; + USBCDC_SendByte(CommandReplyOK); + break; // We don't know what this command is, so reply that it was invalid. default: USBCDC_SendByte(CommandReplyInvalid); @@ -647,3 +667,57 @@ static void SIMMProgrammer_HandleReadingChipsMaskByte(uint8_t byte) // Done either way; now we're waiting for a command to arrive curCommandState = WaitingForCommand; } + +/** Handles a received byte when we are reading in the sector layout + * + * @param byte The received byte, which is the first sector layout byte + */ +static void SIMMProgrammer_HandleReadingSectorLayoutByte(uint8_t byte) +{ + numEraseSectorGroups = 0; + + uint32_t sectorCount = byte; + uint32_t sectorSize = 0; + int byteIndex = 1; + + while (1) + { + // Read in the sector size + for (int i = byteIndex; i < 4; i++) + { + uint32_t nextByte = (uint32_t)USBCDC_ReadByteBlocking(); + sectorCount |= nextByte << (i * 8); + } + // From now on, we loop over 4 bytes, not 3 + byteIndex = 0; + + // If we read in a count of 0, we're done! + if (sectorCount == 0) + { + break; + } + + // We have a nonzero count, so read in the size now + for (int i = 0; i < 4; i++) + { + uint32_t nextByte = (uint32_t)USBCDC_ReadByteBlocking(); + sectorSize |= nextByte << (i * 8); + } + + // If we have room to store it in the array, do it + if (numEraseSectorGroups < MAX_ERASE_SECTOR_GROUPS) + { + eraseSectorGroups[numEraseSectorGroups].count = sectorCount; + eraseSectorGroups[numEraseSectorGroups].size = sectorSize; + numEraseSectorGroups++; + } + + // Now read in the next chunk of data + sectorCount = 0; + sectorSize = 0; + } + + // We got the list. Done! + USBCDC_SendByte(CommandReplyOK); + curCommandState = WaitingForCommand; +}