diff --git a/docs/specs.odt b/docs/specs.odt index bd88ac76..c62c22cc 100644 Binary files a/docs/specs.odt and b/docs/specs.odt differ diff --git a/docs/specs.pdf b/docs/specs.pdf index 3da40ad2..4fc71db2 100644 Binary files a/docs/specs.pdf and b/docs/specs.pdf differ diff --git a/firmware/usbflashprog/modules/device.cpp b/firmware/usbflashprog/modules/device.cpp index 735b7f2f..43563a09 100644 --- a/firmware/usbflashprog/modules/device.cpp +++ b/firmware/usbflashprog/modules/device.cpp @@ -22,19 +22,34 @@ // --------------------------------------------------------------------------- -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 (ST/Atmel/Xicor). */ // clang-format off -constexpr Device::TDeviceCommand kDeviceCmdUnprotect28C[] = { - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0x80}, - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0x20} + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr Device::TDeviceCommand kDeviceCmdUnprotect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} }; -// clang-format on -/* @brief Command sequence to Protect an EEPROM 28C/X28 (ST/Atmel/Xicor). */ -// clang-format off -constexpr Device::TDeviceCommand kDeviceCmdProtect28C[] = { - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0xA0} +/* @brief Command sequence to Protect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr Device::TDeviceCommand kDeviceCmdProtect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} +}; + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr Device::TDeviceCommand kDeviceCmdUnprotect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} }; + +/* @brief Command sequence to Protect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr Device::TDeviceCommand kDeviceCmdProtect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} +}; + // clang-format on // --------------------------------------------------------------------------- @@ -488,8 +503,10 @@ bool Device::erase27E_() { bool Device::unprotect(uint8_t algo) { // Unprotect entire chip switch (algo) { - case kCmdDeviceAlgorithm28C: - return protect28C_(false); + case kCmdDeviceAlgorithm28C64: + return protect28C_(false, false); + case kCmdDeviceAlgorithm28C256: + return protect28C_(false, true); default: return false; } @@ -498,28 +515,44 @@ bool Device::unprotect(uint8_t algo) { bool Device::protect(uint8_t algo) { // Protect entire chip switch (algo) { - case kCmdDeviceAlgorithm28C: - return protect28C_(true); + case kCmdDeviceAlgorithm28C64: + return protect28C_(true, false); + case kCmdDeviceAlgorithm28C256: + return protect28C_(true, true); default: return false; } } -bool Device::protect28C_(bool protect) { +bool Device::protect28C_(bool protect, bool is256) { // EEPROM 28C/X28/AT28 Algorithm bool success = true; // ~CE is LO setCE(true); // write command - if (protect) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C) { + if (protect && !is256) { + for (const TDeviceCommand& cmd : kDeviceCmdProtect28C64) { if (!writeAtAddr_(cmd.addr, cmd.data)) { success = false; break; } } - } else { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C) { + } else if (protect && is256) { + for (const TDeviceCommand& cmd : kDeviceCmdProtect28C256) { + if (!writeAtAddr_(cmd.addr, cmd.data)) { + success = false; + break; + } + } + } else if (!protect && !is256) { + for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C64) { + if (!writeAtAddr_(cmd.addr, cmd.data)) { + success = false; + break; + } + } + } else if (!protect && is256) { + for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C256) { if (!writeAtAddr_(cmd.addr, cmd.data)) { success = false; break; diff --git a/firmware/usbflashprog/modules/device.hpp b/firmware/usbflashprog/modules/device.hpp index 44ac3786..3aa206ab 100644 --- a/firmware/usbflashprog/modules/device.hpp +++ b/firmware/usbflashprog/modules/device.hpp @@ -421,9 +421,11 @@ class Device { /* * @brief Runs the device protect/unprotect (EEPROM 28C algorithm). * @param protect If true, protects device. Otherwise, unprotects device. + * @param is256 If true, uses the 28C256 algorithm. + * Otherwise, uses the 28C64 algorithm. * @return True if sucessfull. False otherwise. */ - bool protect28C_(bool protect); + bool protect28C_(bool protect, bool is256); private: /* diff --git a/firmware/usbflashprog/modules/opcodes.hpp b/firmware/usbflashprog/modules/opcodes.hpp index 4ac7b443..3f81422b 100644 --- a/firmware/usbflashprog/modules/opcodes.hpp +++ b/firmware/usbflashprog/modules/opcodes.hpp @@ -260,11 +260,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -274,11 +275,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -288,11 +290,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -328,8 +331,10 @@ enum kCmdDeviceAlgorithmEnum { kCmdDeviceAlgorithmUnknown = 0x00, /** @brief CMD / DEVICE : Defines an algorithm EPROM 27E/SF/W27. */ kCmdDeviceAlgorithm27E = 0x01, - /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C. */ - kCmdDeviceAlgorithm28C = 0x02 + /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C64. */ + kCmdDeviceAlgorithm28C64 = 0x02, + /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C256 or upper. */ + kCmdDeviceAlgorithm28C256 = 0x03 }; // --------------------------------------------------------------------------- diff --git a/reference/datasheets/eeprom/eepromAT28c/AT28C010.pdf b/reference/datasheets/eeprom/eepromAT28c/AT28C010.pdf new file mode 100644 index 00000000..31ab1d0c Binary files /dev/null and b/reference/datasheets/eeprom/eepromAT28c/AT28C010.pdf differ diff --git a/reference/datasheets/eeprom/eepromAT28c/AT28C040.pdf b/reference/datasheets/eeprom/eepromAT28c/AT28C040.pdf new file mode 100644 index 00000000..c2401136 Binary files /dev/null and b/reference/datasheets/eeprom/eepromAT28c/AT28C040.pdf differ diff --git a/reference/datasheets/eeprom/eepromAT28c/AT28C256.pdf b/reference/datasheets/eeprom/eepromAT28c/AT28C256.pdf new file mode 100644 index 00000000..368395c3 Binary files /dev/null and b/reference/datasheets/eeprom/eepromAT28c/AT28C256.pdf differ diff --git a/reference/datasheets/eeprom/eeprom28c/CAT28C256.pdf b/reference/datasheets/eeprom/eepromAT28c/CAT28C256.pdf similarity index 100% rename from reference/datasheets/eeprom/eeprom28c/CAT28C256.pdf rename to reference/datasheets/eeprom/eepromAT28c/CAT28C256.pdf diff --git a/reference/datasheets/eeprom/eepromAT28c/CAT28C512.pdf b/reference/datasheets/eeprom/eepromAT28c/CAT28C512.pdf new file mode 100644 index 00000000..80f9c2e6 Binary files /dev/null and b/reference/datasheets/eeprom/eepromAT28c/CAT28C512.pdf differ diff --git a/software/usbflashprog/CMakeLists.txt b/software/usbflashprog/CMakeLists.txt index e2f949d8..752a4bae 100644 --- a/software/usbflashprog/CMakeLists.txt +++ b/software/usbflashprog/CMakeLists.txt @@ -54,45 +54,26 @@ elseif(NORMAL_BUILD) ) set(PROJECT_SOURCES - config.hpp backend/opcodes.cpp - backend/opcodes.hpp backend/runner.cpp - backend/runner.hpp backend/epromfile/qepromfilebase.cpp - backend/epromfile/qepromfilebase.hpp backend/epromfile/qbinfile.cpp - backend/epromfile/qbinfile.hpp backend/epromfile/qsrecfile.cpp - backend/epromfile/qsrecfile.hpp backend/epromfile/qhexfile.cpp - backend/epromfile/qhexfile.hpp backend/epromfile/qatmelfile.cpp - backend/epromfile/qatmelfile.hpp backend/epromfile/qepromfile.cpp - backend/epromfile/qepromfile.hpp backend/devices/device.cpp - backend/devices/device.hpp backend/devices/parallel/pdevice.cpp - backend/devices/parallel/pdevice.hpp backend/devices/parallel/dummy.cpp - backend/devices/parallel/dummy.hpp backend/devices/parallel/sram.cpp - backend/devices/parallel/sram.hpp backend/devices/parallel/eprom.cpp - backend/devices/parallel/eprom.hpp backend/devices/parallel/eeprom.cpp - backend/devices/parallel/eeprom.hpp ui/qhexeditor.cpp - ui/qhexeditor.hpp ui/mainwindow.cpp - ui/mainwindow.hpp ui/mainwindow.ui ui/settings.cpp - ui/settings.hpp ui/settings.ui main.cpp - main.hpp ) set(PROJECT_RESOURCES diff --git a/software/usbflashprog/backend/devices/parallel/eeprom.cpp b/software/usbflashprog/backend/devices/parallel/eeprom.cpp index 5354fbc3..f612f3af 100644 --- a/software/usbflashprog/backend/devices/parallel/eeprom.cpp +++ b/software/usbflashprog/backend/devices/parallel/eeprom.cpp @@ -46,7 +46,7 @@ EEPROM::EEPROM(QObject *parent) : ParDevice(parent) { size_ = 2048; twp_ = 2; twc_ = 10000; - protectAlgo_ = kCmdDeviceAlgorithm28C; + protectAlgo_ = kCmdDeviceAlgorithm28C64; maxAttemptsProg_ = 3; DEBUG << info_.toString(); } @@ -55,6 +55,8 @@ EEPROM::~EEPROM() {} void EEPROM::setSize(uint32_t value) { ParDevice::setSize(value); + protectAlgo_ = (size_ <= 0x2000) ? kCmdDeviceAlgorithm28C64 + : kCmdDeviceAlgorithm28C256; bool oldValue = info_.capability.hasUnprotect; bool newValue = (size_ >= 0x2000); // >= 8KB if (oldValue != newValue) { @@ -96,11 +98,28 @@ EEPROM28AT::~EEPROM28AT() {} void EEPROM28AT::setSize(uint32_t value) { EEPROM::setSize(value); + switch (size_) { + case 0x02000: // 8KB + case 0x04000: // 16KB + case 0x08000: // 32KB + sectorSize_ = 64; + break; + case 0x10000: // 64KB + case 0x20000: // 128KB + sectorSize_ = 128; + break; + case 0x40000: // 256KB + sectorSize_ = 256; + break; + default: + if (size_ < 0x02000) sectorSize_ = 0; + if (size_ > 0x40000) sectorSize_ = 256; + break; + } bool oldValue = info_.capability.hasSectorSize; bool newValue = (size_ >= 0x2000); // >= 8KB if (oldValue != newValue) { info_.capability.hasSectorSize = newValue; - sectorSize_ = newValue ? 64 : 0; DEBUG << info_.toString(); } } diff --git a/software/usbflashprog/backend/opcodes.hpp b/software/usbflashprog/backend/opcodes.hpp index b12a704d..f44daff7 100644 --- a/software/usbflashprog/backend/opcodes.hpp +++ b/software/usbflashprog/backend/opcodes.hpp @@ -270,11 +270,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -284,11 +285,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -298,11 +300,12 @@ enum kCmdOpCodeEnum { * @details The parameter (one byte) represents the algorithm, and * follows the table: *
-     * +------------------------------+
-     * |Algorithm| Description        |
-     * |  0x01   | EPROM 27E/W27/27SF |
-     * |  0x02   | EEPROM 28C         |
-     * +------------------------------+
+     * +-------------------------------+
+     * |Algorithm| Description         |
+     * |  0x01   | EPROM 27E/W27/27SF  |
+     * |  0x02   | EEPROM 28C64        |
+     * |  0x03   | EEPROM 28C256/upper |
+     * +-------------------------------+
      * 
* @see kCmdDeviceAlgorithmEnum */ @@ -341,8 +344,10 @@ enum kCmdDeviceAlgorithmEnum { kCmdDeviceAlgorithmUnknown = 0x00, /** @brief CMD / DEVICE : Defines an algorithm EPROM 27E/SF/W27. */ kCmdDeviceAlgorithm27E = 0x01, - /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C. */ - kCmdDeviceAlgorithm28C = 0x02 + /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C64. */ + kCmdDeviceAlgorithm28C64 = 0x02, + /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C256 or upper. */ + kCmdDeviceAlgorithm28C256 = 0x03 }; // --------------------------------------------------------------------------- diff --git a/software/usbflashprog/test/CMakeLists.txt b/software/usbflashprog/test/CMakeLists.txt index c98afa2f..7c1e964b 100644 --- a/software/usbflashprog/test/CMakeLists.txt +++ b/software/usbflashprog/test/CMakeLists.txt @@ -27,35 +27,22 @@ FetchContent_MakeAvailable(googletest) set(PROJ_NAME ufprog_test) set(PROJECT_SOURCES - ../config.hpp ../backend/opcodes.cpp - ../backend/opcodes.hpp ../backend/runner.cpp - ../backend/runner.hpp - ../backend/devices/device.hpp ../backend/devices/device.cpp - ../backend/devices/parallel/pdevice.hpp ../backend/devices/parallel/pdevice.cpp - ../backend/devices/parallel/sram.hpp ../backend/devices/parallel/sram.cpp - ../backend/devices/parallel/eprom.hpp ../backend/devices/parallel/eprom.cpp + ../backend/devices/parallel/eeprom.cpp mock/qserialport.hpp emulator/emulator.cpp - emulator/emulator.hpp emulator/chip.cpp - emulator/chip.hpp emulator/sram.cpp - emulator/sram.hpp emulator/eprom.cpp - emulator/eprom.hpp - backend/chip_test.hpp + emulator/eeprom.cpp backend/chip_test.cpp - backend/runner_test.hpp backend/runner_test.cpp - backend/opcodes_test.hpp backend/opcodes_test.cpp - main.hpp main.cpp ) diff --git a/software/usbflashprog/test/backend/chip_test.cpp b/software/usbflashprog/test/backend/chip_test.cpp index 4f352eed..e5637d62 100644 --- a/software/usbflashprog/test/backend/chip_test.cpp +++ b/software/usbflashprog/test/backend/chip_test.cpp @@ -25,10 +25,12 @@ #include "emulator/emulator.hpp" #include "emulator/sram.hpp" #include "emulator/eprom.hpp" +#include "emulator/eeprom.hpp" #include "../../backend/devices/device.hpp" #include "../../backend/devices/parallel/sram.hpp" #include "../../backend/devices/parallel/eprom.hpp" +#include "../../backend/devices/parallel/eeprom.hpp" // --------------------------------------------------------------------------- @@ -123,6 +125,28 @@ TEST_F(ChipTest, epromW27E_test) { delete device; } +TEST_F(ChipTest, eeprom28C_test) { + ChipEEPROM *emuChip = new ChipEEPROM(); + Emulator::setChip(emuChip); + EEPROM28C *device = new EEPROM28C(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, eeprom28AT_test) { + ChipEEPROM *emuChip = new ChipEEPROM(); + Emulator::setChip(emuChip); + EEPROM28AT *device = new EEPROM28AT(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + // --------------------------------------------------------------------------- void runChipTests(BaseChip *emuChip, Device *device, uint32_t size) { @@ -230,6 +254,24 @@ void runChipTests(BaseChip *emuChip, Device *device, uint32_t size) { EXPECT_EQ(device->program(buffer), true); device->setFastProg(false); } + if (cap.hasProtect || cap.hasUnprotect) { + if (cap.hasProtect) { + GTEST_COUT << "Protect" << std::endl; + EXPECT_EQ(device->protect(), true); + } + if (cap.hasProgram) { + GTEST_COUT << "Program" << std::endl; + EXPECT_EQ(device->program(buffer), true); + } + if (cap.hasUnprotect) { + GTEST_COUT << "Unprotect" << std::endl; + EXPECT_EQ(device->unprotect(), true); + } + if (cap.hasProgram) { + GTEST_COUT << "Program" << std::endl; + EXPECT_EQ(device->program(buffer), true); + } + } if (cap.hasSectorSize && cap.hasProgram && cap.hasErase) { device->setSectorSize(64); GTEST_COUT << "Erase" << std::endl; diff --git a/software/usbflashprog/test/emulator/chip.hpp b/software/usbflashprog/test/emulator/chip.hpp index 63121b7b..aaffaee6 100644 --- a/software/usbflashprog/test/emulator/chip.hpp +++ b/software/usbflashprog/test/emulator/chip.hpp @@ -26,6 +26,32 @@ // --------------------------------------------------------------------------- +/** @ingroup UnitTests + @brief Chip Special Command Structure. */ +typedef struct TChipCommand { + /** @brief Command Address. */ + unsigned long addr; + /** @brief Command Data. */ + unsigned char data; +} TChipCommand; + +// --------------------------------------------------------------------------- + +/** @ingroup UnitTests + @brief Chip Special Command Operation. */ +enum TChipCommandOperation { + /** @brief Unknown Operation. */ + ChipOperationUnknown, + /** @brief Erase Operation. */ + ChipOperationErase, + /** @brief Unprotect Operation. */ + ChipOperationUnprotect, + /** @brief Protect Operation. */ + ChipOperationProtect +}; + +// --------------------------------------------------------------------------- + /** @ingroup UnitTests @brief Chip Emulator Base Abstract Class. @details This is a base class for Chip Emulator.
diff --git a/software/usbflashprog/test/emulator/eeprom.cpp b/software/usbflashprog/test/emulator/eeprom.cpp new file mode 100644 index 00000000..5b476e8b --- /dev/null +++ b/software/usbflashprog/test/emulator/eeprom.cpp @@ -0,0 +1,138 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup UnitTests + * @file test/emulator/eeprom.cpp + * @brief Implementation of EEPROM Chip Emulation. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#include "eeprom.hpp" + +// --------------------------------------------------------------------------- + +/* @brief Protect command sequence size. */ +constexpr int kProtectCommandSize = 3; +/* @brief Unprotect command sequence size. */ +constexpr int kUnprotectCommandSize = 6; + +// clang-format off +/* @brief Command sequence to Protect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TChipCommand kProtectCommandV1[kProtectCommandSize] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} +}; + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TChipCommand kUnprotectCommandV1[kUnprotectCommandSize] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} +}; + +/* @brief Command sequence to Protect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TChipCommand kProtectCommandV2[kProtectCommandSize] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} +}; + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TChipCommand kUnprotectCommandV2[kUnprotectCommandSize] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} +}; +// clang-format on + +// --------------------------------------------------------------------------- + +ChipEEPROM::ChipEEPROM() + : BaseParChip(), f_commandStep(-1), f_commandOp(ChipOperationUnknown) { + writeToLog("SetChip(%s)", "EEPROM"); +} + +ChipEEPROM::~ChipEEPROM() {} + +void ChipEEPROM::setSize(uint32_t size) { + if (size == f_memory_area.size()) return; + /* inherited */ + BaseParChip::setSize(size); + /* initialize with 0xFF */ + fillData(0xFFFF); +} + +void ChipEEPROM::emuChip(void) { + if (f_vdd && f_ce && !f_we && f_oe) { + /* Read : VDD = 1; VPP = X; CE = 1; WE = 0; OE = 1; */ + read(); + } else if (f_vdd && f_ce && f_we) { + /* Write: VDD = 1; VPP = X; CE = 1; WE = 1; OE = X; */ + // execute if special command or write + if (!specialCommand()) write(); + } else if (!f_vdd || !f_ce) { + /* VDD = 0 OR CE = 0 */ + // reset special command state + if (f_commandStep != -1) { + writeToLog("End of Special Command"); + f_commandStep = -1; + f_commandOp = ChipOperationUnknown; + } + } +} + +bool ChipEEPROM::specialCommand(void) { + bool isCommand = false; + int i = ((f_commandStep == 0xFF) ? -1 : f_commandStep) + 1; + + bool isUnprotect = (f_addr_bus == kUnprotectCommandV1[i].addr && + f_data_bus == kUnprotectCommandV1[i].data) || + (f_addr_bus == kUnprotectCommandV2[i].addr && + f_data_bus == kUnprotectCommandV2[i].data); + + bool isProtect = (f_addr_bus == kProtectCommandV1[i].addr && + f_data_bus == kProtectCommandV1[i].data) || + (f_addr_bus == kProtectCommandV2[i].addr && + f_data_bus == kProtectCommandV2[i].data); + + if (isUnprotect) { + f_commandOp = ChipOperationUnprotect; + isCommand = true; + } else if (isProtect) { + f_commandOp = ChipOperationProtect; + isCommand = true; + } + if (isCommand) { + if (f_commandStep != 0xFF) f_commandStep++; + writeToLog("Special Command (addr %06X, data %02X)", f_addr_bus, + f_data_bus); + } + switch (f_commandOp) { + case ChipOperationUnprotect: + if (f_commandStep == (kUnprotectCommandSize - 1)) { + // unprotect + writeToLog("Special Command: Unprotect"); + f_commandStep = 0xFF; + f_commandOp = ChipOperationUnknown; + } + break; + case ChipOperationProtect: + if (f_commandStep == (kProtectCommandSize - 1)) { + // protect + writeToLog("Special Command: Protect"); + f_commandStep = 0xFF; + f_commandOp = ChipOperationUnknown; + } + break; + default: + break; + } + return isCommand; +} diff --git a/software/usbflashprog/test/emulator/eeprom.hpp b/software/usbflashprog/test/emulator/eeprom.hpp new file mode 100644 index 00000000..7f281166 --- /dev/null +++ b/software/usbflashprog/test/emulator/eeprom.hpp @@ -0,0 +1,52 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup UnitTests + * @file test/emulator/eeprom.hpp + * @brief Header of EEPROM Chip Emulation. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#ifndef TEST_EMULATOR_EEPROM_HPP_ +#define TEST_EMULATOR_EEPROM_HPP_ + +// --------------------------------------------------------------------------- + +#include "chip.hpp" + +// --------------------------------------------------------------------------- + +/** @ingroup UnitTests + @brief EEPROM Chip Emulator Class. + @details Emulates a EEPROM Chip. + @nosubgrouping +*/ +class ChipEEPROM : public BaseParChip { + public: + /** Default Constructor. */ + ChipEEPROM(); + /** Destructor. */ + virtual ~ChipEEPROM(); + /* reimplemented */ + virtual void setSize(uint32_t size); + + protected: + /* stores the step of current special command */ + int f_commandStep; + /* stores what is the special command */ + TChipCommandOperation f_commandOp; + /* emulates the chip */ + virtual void emuChip(void); + /* check if received special command */ + virtual bool specialCommand(void); +}; + +#endif // TEST_EMULATOR_EEPROM_HPP_ diff --git a/software/usbflashprog/test/emulator/emulator.cpp b/software/usbflashprog/test/emulator/emulator.cpp index db7cc184..262a31a1 100644 --- a/software/usbflashprog/test/emulator/emulator.cpp +++ b/software/usbflashprog/test/emulator/emulator.cpp @@ -38,19 +38,34 @@ typedef struct TDeviceCommand { // --------------------------------------------------------------------------- -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 (ST/Atmel/Xicor). */ // clang-format off -constexpr TDeviceCommand kDeviceCmdUnprotect28C[] = { - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0x80}, - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0x20} + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} }; -// clang-format on -/* @brief Command sequence to Protect an EEPROM 28C/X28 (ST/Atmel/Xicor). */ -// clang-format off -constexpr TDeviceCommand kDeviceCmdProtect28C[] = { - {0x1555, 0xAA}, {0xAAA, 0x55}, {0x1555, 0xA0} +/* @brief Command sequence to Protect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} +}; + +/* @brief Command sequence to Unprotect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} }; + +/* @brief Command sequence to Protect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} +}; + // clang-format on // --------------------------------------------------------------------------- @@ -1022,28 +1037,44 @@ bool Emulator::deviceErase27E_() { bool Emulator::deviceProtect_(kCmdDeviceAlgorithmEnum algo, bool protect) { switch (algo) { - case kCmdDeviceAlgorithm28C: - return deviceProtect28C_(protect); + case kCmdDeviceAlgorithm28C64: + return deviceProtect28C_(protect, false); + case kCmdDeviceAlgorithm28C256: + return deviceProtect28C_(protect, true); default: return false; } } -bool Emulator::deviceProtect28C_(bool protect) { +bool Emulator::deviceProtect28C_(bool protect, bool is256) { // EEPROM 28C/X28/AT28 Algorithm bool success = true; // ~CE is LO setCE(true); // write command - if (protect) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C) { + if (protect && !is256) { + for (const TDeviceCommand& cmd : kDeviceCmdProtect28C64) { if (!writeAtAddr_(cmd.addr, cmd.data)) { success = false; break; } } - } else { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C) { + } else if (protect && is256) { + for (const TDeviceCommand& cmd : kDeviceCmdProtect28C256) { + if (!writeAtAddr_(cmd.addr, cmd.data)) { + success = false; + break; + } + } + } else if (!protect && !is256) { + for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C64) { + if (!writeAtAddr_(cmd.addr, cmd.data)) { + success = false; + break; + } + } + } else if (!protect && is256) { + for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C256) { if (!writeAtAddr_(cmd.addr, cmd.data)) { success = false; break; diff --git a/software/usbflashprog/test/emulator/emulator.hpp b/software/usbflashprog/test/emulator/emulator.hpp index c0a9bedf..7b57cf99 100644 --- a/software/usbflashprog/test/emulator/emulator.hpp +++ b/software/usbflashprog/test/emulator/emulator.hpp @@ -282,8 +282,10 @@ class Emulator : public QObject { bool deviceErase27E_(); /* @brief Device Protect/Unprotect 28C Algorithm. * @param protect Protect/Unprotect device. + * @param is256 If true, uses the 28C256 algorithm. + * Otherwise, uses the 28C64 algorithm. * @return True if success, false otherwise. */ - bool deviceProtect28C_(bool protect); + bool deviceProtect28C_(bool protect, bool is256); }; #endif // TEST_EMULATOR_EMULATOR_HPP_