mac-rom-simm-programmer/programmer_protocol.h

189 lines
7.1 KiB
C
Raw Normal View History

/*
* programmer_protocol.h
*
* Created on: Dec 26, 2011
* Author: Doug
*
* Copyright (C) 2011-2020 Doug Brown
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef PROGRAMMER_PROTOCOL_H_
#define PROGRAMMER_PROTOCOL_H_
Break out code into a HAL, optimize flash operations This makes the code pretty easily portable to other architectures if someone wants to make a more modern SIMM programmer. I also was pretty careful to split responsibilities of the different components and give the existing components better names. I'm pretty happy with the organization of the code now. As part of this change I have also heavily optimized the code. In particular, the read and write cycle routines are very important to the overall performance of the programmer. In these routines I had to make some tradeoffs of code performance versus prettiness, but the overall result is much faster programming. Some of these performance changes are the result of what I discovered when I upgraded my AVR compiler. I discovered that it is smarter at looking at 32-bit variables when I use a union instead of bitwise operations. I also shaved off more CPU cycles by carefully making a few small tweaks. I added a bypass for the "program only some chips" mask, because it was adding unnecessary CPU cycles for a feature that is rarely used. I removed the verification feature from the write routine, because we can always verify the data after the write chunk is complete, which is more efficient. I also added assumptions about the initial/final state of the CS/OE/WE pins, which allowed me to remove more valuable CPU cycles from the read/write cycle routines. There are also a few enormous performance optimizations I should have done a long time ago: 1) The code was only handling one received byte per main loop iteration. Reading every byte available cut nearly a minute off of the 8 MB programming time. 2) The code wasn't taking advantage of the faster programming command available in the chips used on the 8 MB SIMM. The end result of all of these optimizations is I have programming time of the 8 MB SIMM down to 3:31 (it used to be 8:43). Another minor issue I fixed: the Micron SIMM chip identification wasn't working properly. It was outputting the manufacturer ID again instead of the device ID.
2020-11-18 05:03:32 +00:00
/// When the programmer is in "waiting for command" mode,
/// you send it one of the bytes below to do something (or begin to do something)
typedef enum ProgrammerCommand
{
EnterWaitingMode = 0,
DoElectricalTest,
IdentifyChips,
ReadByte,
ReadChips,
EraseChips,
WriteChips,
GetBootloaderState,
EnterBootloader,
EnterProgrammer,
BootloaderEraseAndWriteProgram,
SetSIMMTypePLCC32_2MB,
SetSIMMTypeLarger,
SetVerifyWhileWriting,
SetNoVerifyWhileWriting,
ErasePortion,
WriteChipsAt,
ReadChipsAt,
SetChipsMask
} ProgrammerCommand;
// After a command is sent, the programmer will always respond with
// one of the replies below. (Depending on the command, it may reply with other
// stuff after that, too)
typedef enum ProgrammerReply
{
CommandReplyOK = 0,
CommandReplyError,
CommandReplyInvalid
} ProgrammerReply;
// ------------------------- ELECTRICAL TEST PROTOCOL -------------------------
// After CommandReplyOK, any failures are reported by the programmer.
// It will send ProgrammerElectricalTestFail followed by two more bytes -- each
// representing an index of the failure location. Any more electrical test failures
// will result in another 3-byte sequence as described above.
// When it's totally finished, it will send ProgrammerElectricalTestDone.
// So a pass would be indicated by no ProgrammerElectricalTestFail sequences being
// sent.
typedef enum ProgrammerElectricalTestReply
{
ProgrammerElectricalTestFail = 0,
ProgrammerElectricalTestDone
} ProgrammerElectricalTestReply;
// ------------------------- IDENTIFY CHIPS PROTOCOL -------------------------
// After CommandReplyOK, it will send the manufacturer ID and device ID of each
// of the 4 chips:
// M1, D1, M2, D2, M3, D3, M4, D4
// followed by ProgrammerIdentifyDone.
typedef enum ProgrammerIdentifyReply
{
ProgrammerIdentifyDone = 0
} ProgrammerIdentifyReply;
// ------------------------- READ PROTOCOL -------------------------
// After CommandReplyOK, the requester will send a 4-byte value containing
// the number of bytes requested to read (should be a multiple of the read
// chunk size of 1024 bytes, though). The programmer will reply with OK or
// error, and if OK, also send a chunk of data.
// The computer will send a reply (see the enum below this one)
// The programmer will then reply to *that* reply (see this enum)
typedef enum ProgrammerReadReply
{
ProgrammerReadOK = 0,
ProgrammerReadError,
ProgrammerReadMoreData,
ProgrammerReadFinished,
ProgrammerReadConfirmCancel
} ProgrammerReadReply;
// When the computer is confirming reception of a block of data from the device,
// it should reply with either OK that it received the data OK, or cancel
// to tell the device that the user canceled the read.
typedef enum ComputerReadReply
{
ComputerReadOK = 0,
ComputerReadCancel
} ComputerReadReply;
// ------------------------- ERASE PROTOCOL -------------------------
// There is none -- a reply of CommandReplyOK will indicate that the erase
// completed successfully.
// ------------------------- WRITE PROTOCOL -------------------------
// After CommandReplyOK, the computer should send one of the commands below.
// The programmer will reply with one of the replies seen in the enum below
// this one, and then the computer can send a 1024-byte chunk of data.
// The programmer will reply with ProgrammerWriteOK, and then the cycle can
// continue (the computer sends another request in this enum)
//
// If the programmer was asked to verify while writing and a verification error
// occurs, it will respond with ProgrammerWriteVerificationError ORed with a bit
// mask of chips that are acting up (so it could be 0x81 if IC1 is acting up,
// for example)
typedef enum ComputerWriteRequest
{
ComputerWriteMore = 0,
ComputerWriteFinish,
ComputerWriteCancel
} ComputerWriteRequest;
typedef enum ProgrammerWriteReply
{
ProgrammerWriteOK = 0,
ProgrammerWriteError,
ProgrammerWriteConfirmCancel,
ProgrammerWriteVerificationError = 0x80 /* high bit signifies verify error, low bits signify which chips are bad */
} ProgrammerWriteReply;
// ------------------------- BOOTLOADER STATE PROTOCOL -------------------------
// If the command is GetBootloaderState, it will reply with CommandReplyOK followed
// by one of the two replies below to tell the control program which mode
// the device is currently in.
typedef enum BootloaderStateReply
{
BootloaderStateInBootloader = 0,
BootloaderStateInProgrammer
} BootloaderStateReply;
// ------------------------- BOOTLOADER ERASE/WRITE PROTOCOL -------------------------
// If the command is BootloaderEraseAndWriteProgram, it will reply with CommandReplyOK
// followed by either BootloaderEraseOK or BootloaderEraseError. At this point
// the program can ask to write more data or finish or cancel, and then the appropriate
// reply will be sent back to it. Works very similar to the write protocol.
typedef enum ProgrammerBootloaderEraseWriteReply
{
BootloaderWriteOK,
BootloaderWriteError,
BootloaderWriteConfirmCancel
} ProgrammerBootloaderEraseWriteReply;
typedef enum ComputerBootloaderEraseWriteRequest
{
ComputerBootloaderWriteMore = 0,
ComputerBootloaderFinish,
ComputerBootloaderCancel
} 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_ */