| 1 |
#ifndef AMDFLASH_HH |
| 2 |
#define AMDFLASH_HH |
| 3 |
|
| 4 |
#include "serialize_meta.hh" |
| 5 |
|
| 6 |
#include "BitField.hh" |
| 7 |
#include "EmuDuration.hh" |
| 8 |
#include "EmuTime.hh" |
| 9 |
#include "Schedulable.hh" |
| 10 |
#include "cstd.hh" |
| 11 |
#include "narrow.hh" |
| 12 |
#include "outer.hh" |
| 13 |
#include "power_of_two.hh" |
| 14 |
#include "static_vector.hh" |
| 15 |
|
| 16 |
#include <algorithm> |
| 17 |
#include <cstddef> |
| 18 |
#include <cstdint> |
| 19 |
#include <memory> |
| 20 |
#include <span> |
| 21 |
#include <string> |
| 22 |
#include <utility> |
| 23 |
#include <vector> |
| 24 |
|
| 25 |
namespace openmsx { |
| 26 |
|
| 27 |
class MSXMotherBoard; |
| 28 |
class Rom; |
| 29 |
class SRAM; |
| 30 |
class DeviceConfig; |
| 31 |
|
| 32 |
class AmdFlash |
| 33 |
{ |
| 34 |
public: |
| 35 |
|
| 36 |
enum class ManufacturerID : uint8_t { |
| 37 |
AMD = 0x01, |
| 38 |
STM = 0x20, |
| 39 |
SST = 0xBF, |
| 40 |
}; |
| 41 |
|
| 42 |
struct AutoSelect { |
| 43 |
ManufacturerID manufacturer; |
| 44 |
static_vector<uint8_t, 2> device; |
| 45 |
uint16_t extraCode = 0x0000; |
| 46 |
uint16_t undefined = 0xFFFF; |
| 47 |
bool oddZero : 1 = false; |
| 48 |
size_t readMask = 0x03; |
| 49 |
|
| 50 |
constexpr void validate() const { |
| 51 |
|
| 52 |
assert(std::popcount(std::to_underlying(manufacturer)) & 1); |
| 53 |
|
| 54 |
assert(!device.empty() && device[0] != 0x7E); |
| 55 |
} |
| 56 |
}; |
| 57 |
|
| 58 |
enum class DeviceInterface : uint16_t { |
| 59 |
x8 = 0x0000, |
| 60 |
x8x16 = 0x0002, |
| 61 |
}; |
| 62 |
|
| 63 |
struct Region { |
| 64 |
size_t count = 0; |
| 65 |
power_of_two<size_t> size = 1; |
| 66 |
}; |
| 67 |
|
| 68 |
struct Geometry { |
| 69 |
constexpr Geometry(DeviceInterface deviceInterface_, std::initializer_list<Region> regions_, |
| 70 |
int writeProtectPinRange_ = 0) |
| 71 |
: deviceInterface(deviceInterface_) |
| 72 |
, regions(regions_) |
| 73 |
, writeProtectPinRange(writeProtectPinRange_) |
| 74 |
, size(sum(regions, [](Region r) { return r.count * r.size; })) |
| 75 |
|
| 76 |
|
| 77 |
|
| 78 |
, sectorCount(sum(regions, [](Region r) { return r.count; })) {} |
| 79 |
DeviceInterface deviceInterface; |
| 80 |
static_vector<Region, 4> regions; |
| 81 |
int writeProtectPinRange; |
| 82 |
power_of_two<size_t> size; |
| 83 |
size_t sectorCount; |
| 84 |
|
| 85 |
constexpr void validate() const { |
| 86 |
assert(std::ranges::all_of(regions, [](const auto& region) { return region.count > 0; })); |
| 87 |
assert(narrow_cast<unsigned>(cstd::abs(writeProtectPinRange)) <= sectorCount); |
| 88 |
} |
| 89 |
}; |
| 90 |
|
| 91 |
struct Erase { |
| 92 |
bool suspend : 1 = false; |
| 93 |
EmuDuration duration = EmuDuration::zero(); |
| 94 |
EmuDuration timerDuration = EmuDuration::usec(50); |
| 95 |
EmuDuration minimumDuration = EmuDuration::usec(100); |
| 96 |
EmuDuration suspendDuration = EmuDuration::zero(); |
| 97 |
|
| 98 |
constexpr void validate() const { |
| 99 |
assert(duration > EmuDuration::zero()); |
| 100 |
assert(!suspend || suspendDuration > EmuDuration::zero()); |
| 101 |
} |
| 102 |
}; |
| 103 |
|
| 104 |
struct Program { |
| 105 |
bool shortAbortReset : 1 = false; |
| 106 |
bool bitRaiseError : 1 = true; |
| 107 |
bool suspend : 1 = false; |
| 108 |
bool enhancedSuspend : 1 = false; |
| 109 |
power_of_two<size_t> fastPageSize = 1; |
| 110 |
power_of_two<size_t> bufferPageSize = 1; |
| 111 |
EmuDuration duration = EmuDuration::zero(); |
| 112 |
EmuDuration additionalDuration = EmuDuration::zero(); |
| 113 |
EmuDuration suspendDuration = EmuDuration::zero(); |
| 114 |
|
| 115 |
constexpr void validate() const { |
| 116 |
assert(fastPageSize <= bufferPageSize); |
| 117 |
assert(duration > EmuDuration::zero()); |
| 118 |
assert(bufferPageSize == 1 || additionalDuration > EmuDuration::zero()); |
| 119 |
assert(!enhancedSuspend || suspend); |
| 120 |
assert(!suspend || suspendDuration > EmuDuration::zero()); |
| 121 |
} |
| 122 |
}; |
| 123 |
|
| 124 |
struct CFI { |
| 125 |
bool command : 1 = false; |
| 126 |
bool withManufacturerDevice : 1 = false; |
| 127 |
bool withAutoSelect : 1 = false; |
| 128 |
bool exitCommand : 1 = false; |
| 129 |
size_t commandMask = 0xFF; |
| 130 |
size_t readMask = 0x7F; |
| 131 |
struct SystemInterface { |
| 132 |
struct Supply { |
| 133 |
uint8_t minVcc = 0; |
| 134 |
uint8_t maxVcc = 0; |
| 135 |
uint8_t minVpp = 0; |
| 136 |
uint8_t maxVpp = 0; |
| 137 |
} supply = {}; |
| 138 |
struct TypicalTimeout { |
| 139 |
power_of_two<unsigned> singleProgram = 1; |
| 140 |
power_of_two<unsigned> multiProgram = 1; |
| 141 |
power_of_two<unsigned> sectorErase = 1; |
| 142 |
power_of_two<unsigned> chipErase = 1; |
| 143 |
} typTimeout = {}; |
| 144 |
struct MaxTimeoutMultiplier { |
| 145 |
power_of_two<unsigned> singleProgram = 1; |
| 146 |
power_of_two<unsigned> multiProgram = 1; |
| 147 |
power_of_two<unsigned> sectorErase = 1; |
| 148 |
power_of_two<unsigned> chipErase = 1; |
| 149 |
} maxTimeoutMult = {}; |
| 150 |
} systemInterface = {}; |
| 151 |
struct PrimaryAlgorithm { |
| 152 |
struct Version { |
| 153 |
uint8_t major = 0; |
| 154 |
uint8_t minor = 0; |
| 155 |
} version = {}; |
| 156 |
uint8_t addressSensitiveUnlock : 2 = 0; |
| 157 |
uint8_t siliconRevision : 6 = 0; |
| 158 |
uint8_t eraseSuspend = 0; |
| 159 |
uint8_t sectorProtect = 0; |
| 160 |
uint8_t sectorTemporaryUnprotect = 0; |
| 161 |
uint8_t sectorProtectScheme = 0; |
| 162 |
uint8_t simultaneousOperation = 0; |
| 163 |
uint8_t burstMode = 0; |
| 164 |
uint8_t pageMode = 0; |
| 165 |
struct Supply { |
| 166 |
uint8_t minAcc = 0; |
| 167 |
uint8_t maxAcc = 0; |
| 168 |
} supply = {}; |
| 169 |
uint8_t bootBlockFlag = 0; |
| 170 |
uint8_t programSuspend = 0; |
| 171 |
} primaryAlgorithm = {}; |
| 172 |
|
| 173 |
constexpr void validate(const Erase& erase_, const Program& program_) const { |
| 174 |
(void)erase_, (void)program_; |
| 175 |
assert(!command || primaryAlgorithm.version.major == 1); |
| 176 |
assert(!command || erase_.suspend == (primaryAlgorithm.eraseSuspend > 0)); |
| 177 |
assert(!command || program_.suspend == (primaryAlgorithm.programSuspend > 0)); |
| 178 |
} |
| 179 |
}; |
| 180 |
|
| 181 |
struct Misc { |
| 182 |
bool statusCommand : 1 = false; |
| 183 |
bool continuityCommand : 1 = false; |
| 184 |
bool readyPin : 1 = false; |
| 185 |
|
| 186 |
constexpr void validate() const { |
| 187 |
assert(!continuityCommand || statusCommand); |
| 188 |
} |
| 189 |
}; |
| 190 |
|
| 191 |
struct Chip { |
| 192 |
AutoSelect autoSelect; |
| 193 |
Geometry geometry; |
| 194 |
Erase erase = {}; |
| 195 |
Program program = {}; |
| 196 |
CFI cfi = {}; |
| 197 |
Misc misc = {}; |
| 198 |
|
| 199 |
constexpr void validate() const { |
| 200 |
autoSelect.validate(); |
| 201 |
geometry.validate(); |
| 202 |
erase.validate(); |
| 203 |
program.validate(); |
| 204 |
cfi.validate(erase, program); |
| 205 |
misc.validate(); |
| 206 |
} |
| 207 |
}; |
| 208 |
|
| 209 |
struct ValidatedChip { |
| 210 |
constexpr ValidatedChip(const Chip& chip_) : chip(chip_) { |
| 211 |
chip.validate(); |
| 212 |
} |
| 213 |
const Chip chip; |
| 214 |
}; |
| 215 |
|
| 216 |
|
| 217 |
|
| 218 |
|
| 219 |
|
| 220 |
|
| 221 |
|
| 222 |
|
| 223 |
|
| 224 |
|
| 225 |
|
| 226 |
|
| 227 |
|
| 228 |
|
| 229 |
|
| 230 |
|
| 231 |
AmdFlash(const Rom& rom, const ValidatedChip& chip, |
| 232 |
std::span<const bool> writeProtectSectors, |
| 233 |
DeviceConfig& config); |
| 234 |
AmdFlash(const std::string& name, const ValidatedChip& chip, |
| 235 |
std::span<const bool> writeProtectSectors, |
| 236 |
DeviceConfig& config, std::string_view id = {}); |
| 237 |
~AmdFlash(); |
| 238 |
|
| 239 |
void reset(); |
| 240 |
|
| 241 |
|
| 242 |
|
| 243 |
|
| 244 |
|
| 245 |
|
| 246 |
void setVppWpPinLow(bool value) { vppWpPinLow = value; } |
| 247 |
bool getReadyPin() const; |
| 248 |
|
| 249 |
[[nodiscard]] power_of_two<size_t> size() const { return chip.geometry.size; } |
| 250 |
[[nodiscard]] uint8_t read(size_t address, EmuTime time); |
| 251 |
[[nodiscard]] uint8_t peek(size_t address, EmuTime time) const; |
| 252 |
void write(size_t address, uint8_t value, EmuTime time); |
| 253 |
[[nodiscard]] const uint8_t* getReadCacheLine(size_t address) const; |
| 254 |
|
| 255 |
template<typename Archive> |
| 256 |
void serialize(Archive& ar, unsigned version); |
| 257 |
|
| 258 |
|
| 259 |
struct AddressValue { |
| 260 |
size_t addr; |
| 261 |
uint8_t value; |
| 262 |
|
| 263 |
auto operator<=>(const AddressValue&) const = default; |
| 264 |
|
| 265 |
template<typename Archive> |
| 266 |
void serialize(Archive& ar, unsigned version); |
| 267 |
}; |
| 268 |
|
| 269 |
enum class State : uint8_t { READ, AUTOSELECT, CFI, STATUS, ERROR, ERASE_SECTOR, ERASE_CHIP, PROGRAM }; |
| 270 |
|
| 271 |
struct Sector { |
| 272 |
size_t index = 0; |
| 273 |
size_t address = 0; |
| 274 |
power_of_two<size_t> size = 1; |
| 275 |
bool writeProtect = false; |
| 276 |
ptrdiff_t writeAddress = -1; |
| 277 |
const uint8_t* readAddress = nullptr; |
| 278 |
|
| 279 |
std::weak_ordering operator<=>(const Sector& sector) const { return address <=> sector.address; } |
| 280 |
bool operator==(const Sector& sector) const { return address == sector.address; } |
| 281 |
}; |
| 282 |
|
| 283 |
private: |
| 284 |
AmdFlash(const std::string& name, const ValidatedChip& chip, |
| 285 |
const Rom* rom, std::span<const bool> writeProtectSectors, |
| 286 |
DeviceConfig& config, std::string_view id); |
| 287 |
|
| 288 |
[[nodiscard]] size_t getSectorIndex(size_t address) const; |
| 289 |
[[nodiscard]] Sector& getSector(size_t address) { return sectors[getSectorIndex(address)]; }; |
| 290 |
[[nodiscard]] const Sector& getSector(size_t address) const { return sectors[getSectorIndex(address)]; }; |
| 291 |
[[nodiscard]] bool isWritable(const Sector& sector) const; |
| 292 |
|
| 293 |
void softReset(); |
| 294 |
void clearStatus(); |
| 295 |
void setState(State newState); |
| 296 |
|
| 297 |
[[nodiscard]] uint16_t peekAutoSelect(size_t address, uint16_t undefined = 0xFFFF) const; |
| 298 |
[[nodiscard]] uint16_t peekCFI(size_t address) const; |
| 299 |
|
| 300 |
[[nodiscard]] bool checkCommandReset(); |
| 301 |
[[nodiscard]] bool checkCommandLongReset(); |
| 302 |
[[nodiscard]] bool checkCommandAutoSelect(); |
| 303 |
[[nodiscard]] bool checkCommandCFIQuery(); |
| 304 |
[[nodiscard]] bool checkCommandCFIExit(); |
| 305 |
[[nodiscard]] bool checkCommandStatusRead(); |
| 306 |
[[nodiscard]] bool checkCommandStatusClear(); |
| 307 |
[[nodiscard]] bool checkCommandContinuityCheck(); |
| 308 |
[[nodiscard]] bool checkCommandEraseSector(EmuTime time); |
| 309 |
[[nodiscard]] bool checkCommandEraseAdditionalSector(EmuTime time); |
| 310 |
[[nodiscard]] bool checkCommandEraseChip(EmuTime time); |
| 311 |
[[nodiscard]] bool checkCommandSuspend(EmuTime time); |
| 312 |
[[nodiscard]] bool checkCommandResume(EmuTime time); |
| 313 |
[[nodiscard]] bool checkCommandProgram(EmuTime time); |
| 314 |
[[nodiscard]] bool checkCommandDoubleByteProgram(EmuTime time); |
| 315 |
[[nodiscard]] bool checkCommandQuadrupleByteProgram(EmuTime time); |
| 316 |
[[nodiscard]] bool checkCommandProgramHelper(size_t numBytes, std::span<const uint8_t> cmdSeq, EmuTime time); |
| 317 |
[[nodiscard]] bool checkCommandBufferProgram(EmuTime time); |
| 318 |
[[nodiscard]] bool partialMatch(std::span<const uint8_t> dataSeq) const; |
| 319 |
|
| 320 |
void scheduleEraseOperation(EmuTime time); |
| 321 |
void scheduleProgramOperation(EmuTime time); |
| 322 |
void execOperation(EmuTime time); |
| 323 |
void execEraseOperation(EmuTime time); |
| 324 |
void execProgramOperation(EmuTime time); |
| 325 |
void execSuspend(EmuTime time); |
| 326 |
|
| 327 |
MSXMotherBoard& motherBoard; |
| 328 |
std::unique_ptr<SRAM> ram; |
| 329 |
const Chip& chip; |
| 330 |
std::vector<Sector> sectors; |
| 331 |
std::vector<AddressValue> cmd; |
| 332 |
State state = State::READ; |
| 333 |
bool vppWpPinLow = false; |
| 334 |
|
| 335 |
template<size_t POS, size_t WIDTH = 1, typename T2 = bool> |
| 336 |
using BF8 = BitField<uint8_t, POS, WIDTH, T2>; |
| 337 |
|
| 338 |
union OperationStatus { |
| 339 |
uint8_t raw = 0x00; |
| 340 |
BF8<7> dataPolling; |
| 341 |
BF8<6> busyToggle; |
| 342 |
BF8<5> error; |
| 343 |
BF8<4> dq4; |
| 344 |
BF8<3> eraseTimer; |
| 345 |
BF8<2> eraseToggle; |
| 346 |
BF8<1> abort; |
| 347 |
BF8<0> dq0; |
| 348 |
} status; |
| 349 |
|
| 350 |
union StatusRegister { |
| 351 |
uint8_t raw = 0x80; |
| 352 |
BF8<7> ready; |
| 353 |
BF8<6> eraseSuspend; |
| 354 |
BF8<5> eraseStatus; |
| 355 |
BF8<4> programStatus; |
| 356 |
BF8<3> bufferAbort; |
| 357 |
BF8<2> programSuspend; |
| 358 |
BF8<1> sectorLock; |
| 359 |
BF8<0> continuity; |
| 360 |
} statusRegister; |
| 361 |
|
| 362 |
struct EraseOperation { |
| 363 |
size_t index = 0; |
| 364 |
std::vector<uint8_t> buffer; |
| 365 |
|
| 366 |
bool isPending(const Sector& sector) const; |
| 367 |
void markPending(const Sector& sector); |
| 368 |
void reset(); |
| 369 |
template<typename Archive> |
| 370 |
void serialize(Archive& ar, unsigned version); |
| 371 |
} erase; |
| 372 |
|
| 373 |
struct ProgramOperation { |
| 374 |
size_t address = 0; |
| 375 |
size_t index = 0; |
| 376 |
std::vector<uint16_t> buffer; |
| 377 |
|
| 378 |
void reset(); |
| 379 |
template<typename Archive> |
| 380 |
void serialize(Archive& ar, unsigned version); |
| 381 |
} program; |
| 382 |
|
| 383 |
struct SyncOperation : Schedulable { |
| 384 |
friend class AmdFlash; |
| 385 |
explicit SyncOperation(Scheduler& s) : Schedulable(s) {} |
| 386 |
void executeUntil(EmuTime time) override { |
| 387 |
auto& outer = OUTER(AmdFlash, syncOperation); |
| 388 |
outer.execOperation(time); |
| 389 |
} |
| 390 |
} syncOperation; |
| 391 |
|
| 392 |
struct SyncSuspend : Schedulable { |
| 393 |
friend class AmdFlash; |
| 394 |
explicit SyncSuspend(Scheduler& s) : Schedulable(s) {} |
| 395 |
void executeUntil(EmuTime time) override { |
| 396 |
auto& outer = OUTER(AmdFlash, syncSuspend); |
| 397 |
outer.execSuspend(time); |
| 398 |
} |
| 399 |
} syncSuspend; |
| 400 |
}; |
| 401 |
SERIALIZE_CLASS_VERSION(AmdFlash, 4); |
| 402 |
|
| 403 |
namespace AmdFlashChip |
| 404 |
{ |
| 405 |
using ValidatedChip = AmdFlash::ValidatedChip; |
| 406 |
using enum AmdFlash::ManufacturerID; |
| 407 |
using DeviceInterface = AmdFlash::DeviceInterface; |
| 408 |
|
| 409 |
|
| 410 |
static constexpr ValidatedChip AM29F040B = {{ |
| 411 |
.autoSelect{.manufacturer = AMD, .device{0xA4}, .extraCode = 0x01}, |
| 412 |
.geometry{ |
| 413 |
DeviceInterface::x8, { |
| 414 |
{.count = 8, .size = 0x10000}, |
| 415 |
}, |
| 416 |
}, |
| 417 |
.erase{.suspend = true, .duration = EmuDuration::msec(1000), .suspendDuration = EmuDuration::usec(20)}, |
| 418 |
.program{.duration = EmuDuration::usec(7)}, |
| 419 |
}}; |
| 420 |
|
| 421 |
|
| 422 |
static constexpr ValidatedChip AM29F016D = {{ |
| 423 |
.autoSelect{.manufacturer = AMD, .device{0xAD}}, |
| 424 |
.geometry{ |
| 425 |
DeviceInterface::x8, { |
| 426 |
{.count = 32, .size = 0x10000}, |
| 427 |
}, |
| 428 |
}, |
| 429 |
.erase{.suspend = true, .duration = EmuDuration::msec(1000), .suspendDuration = EmuDuration::usec(20)}, |
| 430 |
.program{.duration = EmuDuration::usec(7)}, |
| 431 |
.cfi{ |
| 432 |
.command = true, |
| 433 |
.systemInterface{ |
| 434 |
.supply = {.minVcc = 0x45, .maxVcc = 0x55, .minVpp = 0x00, .maxVpp = 0x00}, |
| 435 |
.typTimeout = {.singleProgram = 8, .multiProgram = 1, .sectorErase = 1024, .chipErase = 1}, |
| 436 |
.maxTimeoutMult = {.singleProgram = 32, .multiProgram = 1, .sectorErase = 16, .chipErase = 1}, |
| 437 |
}, |
| 438 |
.primaryAlgorithm{ |
| 439 |
.version = {.major = 1, .minor = 1}, |
| 440 |
.addressSensitiveUnlock = 0, |
| 441 |
.siliconRevision = 0, |
| 442 |
.eraseSuspend = 2, |
| 443 |
.sectorProtect = 4, |
| 444 |
.sectorTemporaryUnprotect = 1, |
| 445 |
.sectorProtectScheme = 4, |
| 446 |
.simultaneousOperation = 0, |
| 447 |
.burstMode = 0, |
| 448 |
.pageMode = 0, |
| 449 |
.supply = {.minAcc = 0, .maxAcc = 0}, |
| 450 |
.bootBlockFlag = 0 |
| 451 |
}, |
| 452 |
}, |
| 453 |
.misc{.readyPin = true}, |
| 454 |
}}; |
| 455 |
|
| 456 |
|
| 457 |
static constexpr ValidatedChip SST39SF010 = {{ |
| 458 |
.autoSelect{.manufacturer = SST, .device{0xB5}}, |
| 459 |
.geometry{ |
| 460 |
DeviceInterface::x8, { |
| 461 |
{.count = 32, .size = 0x1000}, |
| 462 |
}, |
| 463 |
}, |
| 464 |
.erase{.duration = EmuDuration::msec(25)}, |
| 465 |
.program{.duration = EmuDuration::usec(20)}, |
| 466 |
}}; |
| 467 |
|
| 468 |
|
| 469 |
static constexpr ValidatedChip M29W800DB = {{ |
| 470 |
.autoSelect{.manufacturer = STM, .device{0x5B}}, |
| 471 |
.geometry{ |
| 472 |
DeviceInterface::x8x16, { |
| 473 |
{.count = 1, .size = 0x4000}, |
| 474 |
{.count = 2, .size = 0x2000}, |
| 475 |
{.count = 1, .size = 0x8000}, |
| 476 |
{.count = 15, .size = 0x10000}, |
| 477 |
}, |
| 478 |
}, |
| 479 |
.erase{.suspend = true, .duration = EmuDuration::msec(800), .suspendDuration = EmuDuration::usec(25)}, |
| 480 |
.program{.duration = EmuDuration::usec(10)}, |
| 481 |
.cfi{ |
| 482 |
.command = true, |
| 483 |
.systemInterface{ |
| 484 |
.supply = {.minVcc = 0x27, .maxVcc = 0x36, .minVpp = 0x00, .maxVpp = 0x00}, |
| 485 |
.typTimeout = {.singleProgram = 16, .multiProgram = 1, .sectorErase = 1024, .chipErase = 1}, |
| 486 |
.maxTimeoutMult = {.singleProgram = 16, .multiProgram = 1, .sectorErase = 8, .chipErase = 1}, |
| 487 |
}, |
| 488 |
.primaryAlgorithm{ |
| 489 |
.version = {.major = 1, .minor = 0}, |
| 490 |
.addressSensitiveUnlock = 0, |
| 491 |
.siliconRevision = 0, |
| 492 |
.eraseSuspend = 2, |
| 493 |
.sectorProtect = 1, |
| 494 |
.sectorTemporaryUnprotect = 1, |
| 495 |
.sectorProtectScheme = 4, |
| 496 |
.simultaneousOperation = 0, |
| 497 |
.burstMode = 0, |
| 498 |
.pageMode = 0, |
| 499 |
}, |
| 500 |
}, |
| 501 |
.misc{.readyPin = true}, |
| 502 |
}}; |
| 503 |
|
| 504 |
|
| 505 |
static constexpr ValidatedChip M29W640GB = {{ |
| 506 |
.autoSelect{.manufacturer = STM, .device{0x10, 0x00}, .extraCode = 0x0008, .undefined = 0, .oddZero = true, .readMask = 0x7F}, |
| 507 |
.geometry{ |
| 508 |
DeviceInterface::x8x16, { |
| 509 |
{.count = 8, .size = 0x2000}, |
| 510 |
{.count = 127, .size = 0x10000}, |
| 511 |
}, 2 |
| 512 |
}, |
| 513 |
.erase{.suspend = true, .duration = EmuDuration::msec(500), .suspendDuration = EmuDuration::usec(4)}, |
| 514 |
.program{ |
| 515 |
.shortAbortReset = true, .bitRaiseError = true, .suspend = true, .fastPageSize = 8, .bufferPageSize = 32, |
| 516 |
.duration = EmuDuration::usec(10), .additionalDuration = EmuDuration::usec(5.5), .suspendDuration = EmuDuration::usec(4) |
| 517 |
}, |
| 518 |
.cfi{ |
| 519 |
.command = true, .withManufacturerDevice = true, .commandMask = 0x7FF, .readMask = 0xFF, |
| 520 |
.systemInterface{ |
| 521 |
.supply = {.minVcc = 0x27, .maxVcc = 0x36, .minVpp = 0xB5, .maxVpp = 0xC5}, |
| 522 |
.typTimeout = {.singleProgram = 16, .multiProgram = 1, .sectorErase = 1024, .chipErase = 1}, |
| 523 |
.maxTimeoutMult = {.singleProgram = 16, .multiProgram = 1, .sectorErase = 8, .chipErase = 1}, |
| 524 |
}, |
| 525 |
.primaryAlgorithm{ |
| 526 |
.version = {.major = 1, .minor = 3}, |
| 527 |
.addressSensitiveUnlock = 0, |
| 528 |
.siliconRevision = 0, |
| 529 |
.eraseSuspend = 2, |
| 530 |
.sectorProtect = 4, |
| 531 |
.sectorTemporaryUnprotect = 1, |
| 532 |
.sectorProtectScheme = 4, |
| 533 |
.simultaneousOperation = 0, |
| 534 |
.burstMode = 0, |
| 535 |
.pageMode = 1, |
| 536 |
.supply = {.minAcc = 0xB5, .maxAcc = 0xC5}, |
| 537 |
.bootBlockFlag = 0x02, |
| 538 |
.programSuspend = 1, |
| 539 |
}, |
| 540 |
}, |
| 541 |
.misc{.readyPin = true}, |
| 542 |
}}; |
| 543 |
|
| 544 |
|
| 545 |
static constexpr ValidatedChip S29GL064N90TFI04 = {{ |
| 546 |
.autoSelect{.manufacturer = AMD, .device{0x10, 0x00}, .extraCode = 0xFF0A, .readMask = 0x0F}, |
| 547 |
.geometry{ |
| 548 |
DeviceInterface::x8x16, { |
| 549 |
{.count = 8, .size = 0x2000}, |
| 550 |
{.count = 127, .size = 0x10000}, |
| 551 |
}, 1 |
| 552 |
}, |
| 553 |
.erase{.suspend = true, .duration = EmuDuration::msec(500), .suspendDuration = EmuDuration::usec(20)}, |
| 554 |
.program{ |
| 555 |
.suspend = true, .bufferPageSize = 32, |
| 556 |
.duration = EmuDuration::usec(60), .additionalDuration = EmuDuration::usec(5.8), .suspendDuration = EmuDuration::usec(20) |
| 557 |
}, |
| 558 |
.cfi{ |
| 559 |
.command = true, |
| 560 |
.systemInterface{ |
| 561 |
.supply = {.minVcc = 0x27, .maxVcc = 0x36, .minVpp = 0x00, .maxVpp = 0x00}, |
| 562 |
.typTimeout = {.singleProgram = 128, .multiProgram = 128, .sectorErase = 1024, .chipErase = 1}, |
| 563 |
.maxTimeoutMult = {.singleProgram = 8, .multiProgram = 32, .sectorErase = 16, .chipErase = 1}, |
| 564 |
}, |
| 565 |
.primaryAlgorithm{ |
| 566 |
.version = {.major = 1, .minor = 3}, |
| 567 |
.addressSensitiveUnlock = 0, |
| 568 |
.siliconRevision = 8, |
| 569 |
.eraseSuspend = 2, |
| 570 |
.sectorProtect = 1, |
| 571 |
.sectorTemporaryUnprotect = 0, |
| 572 |
.sectorProtectScheme = 8, |
| 573 |
.simultaneousOperation = 0, |
| 574 |
.burstMode = 0, |
| 575 |
.pageMode = 2, |
| 576 |
.supply = {.minAcc = 0xB5, .maxAcc = 0xC5}, |
| 577 |
.bootBlockFlag = 0x02, |
| 578 |
.programSuspend = 1, |
| 579 |
}, |
| 580 |
}, |
| 581 |
.misc{.readyPin = true}, |
| 582 |
}}; |
| 583 |
|
| 584 |
|
| 585 |
static constexpr ValidatedChip S29GL064S70TFI040 = {{ |
| 586 |
.autoSelect{.manufacturer = AMD, .device{0x10, 0x00}, .extraCode = 0xFF0A, .readMask = 0x0F}, |
| 587 |
.geometry{ |
| 588 |
DeviceInterface::x8x16, { |
| 589 |
{.count = 8, .size = 0x2000}, |
| 590 |
{.count = 127, .size = 0x10000}, |
| 591 |
}, 2 |
| 592 |
}, |
| 593 |
.erase{.suspend = true, .duration = EmuDuration::msec(300), .suspendDuration = EmuDuration::usec(30)}, |
| 594 |
.program{ |
| 595 |
.shortAbortReset = false, .bitRaiseError = false, .suspend = true, .enhancedSuspend = true, .bufferPageSize = 256, |
| 596 |
.duration = EmuDuration::usec(150), .additionalDuration = EmuDuration::usec(1.0), .suspendDuration = EmuDuration::usec(23.5) |
| 597 |
}, |
| 598 |
.cfi{ |
| 599 |
.command = true, .withAutoSelect = true, .exitCommand = true, .commandMask = 0xFF, .readMask = 0x7F, |
| 600 |
.systemInterface{ |
| 601 |
.supply = {.minVcc = 0x27, .maxVcc = 0x36, .minVpp = 0x00, .maxVpp = 0x00}, |
| 602 |
.typTimeout = {.singleProgram = 256, .multiProgram = 256, .sectorErase = 512, .chipErase = 65536}, |
| 603 |
.maxTimeoutMult = {.singleProgram = 8, .multiProgram = 8, .sectorErase = 2, .chipErase = 1}}, |
| 604 |
.primaryAlgorithm{ |
| 605 |
.version = {.major = 1, .minor = 3}, |
| 606 |
.addressSensitiveUnlock = 0, |
| 607 |
.siliconRevision = 8, |
| 608 |
.eraseSuspend = 2, |
| 609 |
.sectorProtect = 1, |
| 610 |
.sectorTemporaryUnprotect = 0, |
| 611 |
.sectorProtectScheme = 8, |
| 612 |
.simultaneousOperation = 0, |
| 613 |
.burstMode = 0, |
| 614 |
.pageMode = 2, |
| 615 |
.supply = {.minAcc = 0xB5, .maxAcc = 0xC5}, |
| 616 |
.bootBlockFlag = 0x02, |
| 617 |
.programSuspend = 1, |
| 618 |
}, |
| 619 |
}, |
| 620 |
.misc{.statusCommand = true, .continuityCommand = true, .readyPin = true}, |
| 621 |
}}; |
| 622 |
} |
| 623 |
|
| 624 |
} |
| 625 |
|
| 626 |
#endif |