24 std::span<const bool> writeProtectSectors,
26 :
AmdFlash(rom.getName() +
"_flash", validatedChip, &rom, writeProtectSectors, config)
31 std::span<const bool> writeProtectSectors,
33 :
AmdFlash(name, validatedChip, nullptr, writeProtectSectors, config)
38 const Rom* rom, std::span<const bool> writeProtectSectors,
40 : motherBoard(config.getMotherBoard())
41 , chip(validatedChip.chip)
46 for (
size_t address = 0;
const Region& region : chip.
geometry.
regions) {
47 for (
size_t regionSector = 0; regionSector < region.count; ++regionSector, address += region.size) {
51 .writeProtect = sectors.size() < writeProtectSectors.size() && writeProtectSectors[sectors.size()]
56 size_t writableSize = 0;
57 size_t readOnlySize = 0;
58 for (Sector& sector : sectors) {
59 if (sector.writeProtect) {
60 sector.writeAddress = -1;
61 readOnlySize += sector.size;
63 sector.writeAddress = narrow<ptrdiff_t>(writableSize);
64 writableSize += sector.size;
67 assert((writableSize + readOnlySize) ==
size());
71 ram = std::make_unique<SRAM>(
73 writableSize, config,
nullptr, &loaded);
81 std::unique_ptr<Rom> rom_;
82 if (!rom && !loaded) {
90 rom_ = std::make_unique<Rom>(
95 "Loaded initial content for flash ROM from ",
97 }
catch (MSXException& e) {
99 assert(rom ==
nullptr);
102 const bool initialContentSpecified = romTag && romTag->
findChild(
"sha1");
103 if (initialContentSpecified) {
105 "Could not load specified initial content "
106 "for flash ROM: ",
e.getMessage());
111 auto romSize = rom ? rom->
size() : 0;
113 for (Sector& sector : sectors) {
114 if (sector.writeAddress != -1) {
115 sector.readAddress = &(*ram)[sector.writeAddress];
117 auto* ramPtr =
const_cast<uint8_t*
>(
118 &(*ram)[sector.writeAddress]);
119 if (offset >= romSize) {
122 }
else if (offset + sector.size >= romSize) {
124 auto last = romSize - offset;
125 auto missing = sector.size - last;
126 const uint8_t* romPtr = &(*rom)[offset];
131 const uint8_t* romPtr = &(*rom)[offset];
137 if ((offset + sector.size) <= romSize) {
138 sector.readAddress = &(*rom)[offset];
140 sector.readAddress =
nullptr;
143 offset += sector.size;
145 assert(offset ==
size());
152size_t AmdFlash::getSectorIndex(
size_t address)
const
154 size_t sectorIndex = 0;
155 for (
const Region& region : chip.geometry.regions) {
156 if (address < region.count * region.size) {
157 return sectorIndex + address / region.size;
159 address -= region.count * region.size;
160 sectorIndex += region.count;
172void AmdFlash::softReset()
179void AmdFlash::setState(State newState)
181 if (state == newState)
return;
190 const Sector& sector = getSector(address);
192 return addr[address - sector.
address];
209 const uint16_t result = peekCFI(address >> 1);
210 return narrow_cast<uint8_t>(address & 1 ? result >> 8 : result);
212 return narrow_cast<uint8_t>(peekCFI(address));
221uint16_t AmdFlash::peekAutoSelect(
size_t address, uint16_t undefined)
const
233 return isWritable(getSector(address)) ? 0 : 1;
266uint16_t AmdFlash::peekCFI(
size_t address)
const
268 const size_t maskedAddress = address & chip.
cfi.
readMask;
270 if (maskedAddress < 0x10) {
273 switch (maskedAddress) {
287 return peekAutoSelect(address);
291 switch (maskedAddress) {
350 if (
const size_t index = (maskedAddress - 0x2D) >> 2; index < chip.
geometry.
regions.size()) {
351 return narrow<uint8_t>((chip.
geometry.
regions[index].count - 1) & 0xFF);
358 if (
const size_t index = (maskedAddress - 0x2E) >> 2; index < chip.
geometry.
regions.size()) {
366 if (
const size_t index = (maskedAddress - 0x2F) >> 2; index < chip.
geometry.
regions.size()) {
367 return narrow<uint8_t>((chip.
geometry.
regions[index].size >> 8) & 0xFF);
374 if (
const size_t index = (maskedAddress - 0x30) >> 2; index < chip.
geometry.
regions.size()) {
420bool AmdFlash::isWritable(
const Sector& sector)
const
424 if ((range > 0 && sector <= sectors[range -
size_t(1)]) ||
429 return !sector.writeProtect;
435 const uint8_t value =
peek(address);
448 const Sector& sector = getSector(address);
459 cmd.push_back({address, value});
462 if (checkCommandAutoSelect() ||
463 checkCommandEraseSector() ||
464 checkCommandProgram() ||
465 checkCommandDoubleByteProgram() ||
466 checkCommandQuadrupleByteProgram() ||
467 checkCommandBufferProgram() ||
468 checkCommandEraseChip() ||
469 checkCommandCFIQuery() ||
470 checkCommandContinuityCheck() ||
471 checkCommandStatusRead() ||
472 checkCommandStatusClear() ||
473 checkCommandLongReset() ||
474 checkCommandReset()) {
480 if (checkCommandCFIQuery() ||
481 checkCommandLongReset() ||
482 checkCommandReset()) {
488 if (checkCommandLongReset() ||
489 checkCommandCFIExit() ||
490 checkCommandReset()) {
497 if (checkCommandLongReset() ||
498 checkCommandReset()) {
504 if (checkCommandLongReset() ||
520bool AmdFlash::checkCommandReset()
522 if (cmd[0].value == 0xf0) {
528bool AmdFlash::checkCommandLongReset()
530 static constexpr std::array<uint8_t, 3> cmdSeq = {0xaa, 0x55, 0xf0};
531 if (partialMatch(cmdSeq)) {
532 if (cmd.size() < 3)
return true;
538bool AmdFlash::checkCommandStatusRead()
540 static constexpr std::array<uint8_t, 1> cmdSeq = {0x70};
547bool AmdFlash::checkCommandStatusClear()
549 static constexpr std::array<uint8_t, 1> cmdSeq = {0x71};
556bool AmdFlash::checkCommandContinuityCheck()
559 if (cmd.size() < 2)
return true;
560 if (cmd.size() == 2 && cmd[1] == AddressValue{0x2AAB54, 0x00}) {
567bool AmdFlash::checkCommandCFIQuery()
577bool AmdFlash::checkCommandCFIExit()
585bool AmdFlash::checkCommandEraseSector()
587 static constexpr std::array<uint8_t, 5> cmdSeq = {0xaa, 0x55, 0x80, 0xaa, 0x55};
588 if (partialMatch(cmdSeq)) {
589 if (cmd.size() < 6)
return true;
590 if (cmd[5].value == 0x30) {
591 if (
const Sector& sector = getSector(cmd[5].addr);
592 isWritable(sector)) {
593 ram->memset(sector.writeAddress, 0xff, sector.size);
602bool AmdFlash::checkCommandEraseChip()
604 static constexpr std::array<uint8_t, 5> cmdSeq = {0xaa, 0x55, 0x80, 0xaa, 0x55};
605 if (partialMatch(cmdSeq)) {
606 if (cmd.size() < 6)
return true;
607 if (cmd[5].value == 0x10) {
608 for (
const Sector& sector : sectors) {
609 if (isWritable(sector)) {
610 ram->memset(sector.writeAddress, 0xff, sector.size);
620bool AmdFlash::checkCommandProgramHelper(
size_t numBytes, std::span<const uint8_t> cmdSeq)
623 if (cmd.size() < (cmdSeq.size() + numBytes))
return true;
625 const Sector& sector = getSector(cmd[i].addr);
626 if (isWritable(sector)) {
627 auto ramAddr = sector.writeAddress + cmd[i].addr - sector.address;
628 uint8_t ramValue = (*ram)[ramAddr] & cmd[i].value;
629 ram->write(ramAddr, ramValue);
631 status = (status & 0x7F) | (ramValue & 0x80);
638bool AmdFlash::checkCommandProgram()
640 static constexpr std::array<uint8_t, 3> cmdSeq = {0xaa, 0x55, 0xa0};
641 return checkCommandProgramHelper(1, cmdSeq);
644bool AmdFlash::checkCommandDoubleByteProgram()
646 static constexpr std::array<uint8_t, 1> cmdSeq = {0x50};
650bool AmdFlash::checkCommandQuadrupleByteProgram()
652 static constexpr std::array<uint8_t, 1> cmdSeq = {0x56};
656bool AmdFlash::checkCommandBufferProgram()
658 static constexpr std::array<uint8_t, 2> cmdSeq = {0xaa, 0x55};
659 if (chip.
program.
bufferCommand && partialMatch(cmdSeq) && (cmd.size() <= 2 || cmd[2].value == 0x25)) {
660 if (cmd.size() <= 3) {
662 }
else if (cmd.size() <= 4) {
663 if (cmd[3].value < chip.
program.
pageSize && getSector(cmd[3].addr) == getSector(cmd[2].addr)) {
666 }
else if (cmd.size() <=
size_t(5 + cmd[3].value)) {
668 if ((cmd.back().addr & pageMask) == (cmd[4].addr & pageMask)) {
669 status = (status & 0x7F) | (~cmd.back().value & 0x80);
673 const Sector& sector = getSector(cmd[2].addr);
674 if (cmd.back().value == 0x29 && getSector(cmd.back().addr) == sector) {
675 if (isWritable(sector)) {
677 for (
auto i :
xrange<size_t>(4, cmd.
size() - 1)) {
678 auto ramAddr = sector.writeAddress + cmd[i].addr - sector.address;
679 uint8_t ramValue = (*ram)[ramAddr] & cmd[i].value;
680 ram->write(ramAddr, ramValue);
682 status = (status & 0x7F) | (ramValue & 0x80);
688 status = (status & 0xDF) | 0x02;
694bool AmdFlash::checkCommandAutoSelect()
696 static constexpr std::array<uint8_t, 3> cmdSeq = {0xaa, 0x55, 0x90};
697 if (partialMatch(cmdSeq)) {
698 if (cmd.size() < 3)
return true;
704bool AmdFlash::partialMatch(std::span<const uint8_t> dataSeq)
const
706 static constexpr std::array<unsigned, 5> addrSeq = {0, 1, 0, 0, 1};
707 static constexpr std::array<unsigned, 2> cmdAddr = {0x555, 0x2aa};
708 (void)addrSeq; (void)cmdAddr;
710 assert(dataSeq.size() <= 5);
713 auto addr = (chip.geometry.deviceInterface == DeviceInterface::x8x16) ? cmd[i].addr >> 1 : cmd[i].addr;
714 return ((addr & 0x7FF) == cmdAddr[addrSeq[i]]) &&
715 (cmd[i].value == dataSeq[i]);
720static constexpr std::initializer_list<enum_string<AmdFlash::State>> stateInfo = {
729template<
typename Archive>
732 ar.serialize(
"address",
addr,
739template<
typename Archive>
742 ar.serialize(
"ram", *ram);
743 if (ar.versionAtLeast(version, 3)) {
744 ar.serialize(
"cmd", cmd,
747 std::array<AddressValue, 8> cmdArray;
748 unsigned cmdSize = 0;
749 ar.serialize(
"cmd", cmdArray,
753 ar.serialize(
"state", state);
754 if (ar.versionAtLeast(version, 2)) {
755 ar.serialize(
"vppWpPinLow", vppWpPinLow);
AmdFlash(const Rom &rom, const ValidatedChip &chip, std::span< const bool > writeProtectSectors, const DeviceConfig &config)
Create AmdFlash with given configuration.
void write(size_t address, uint8_t value)
void serialize(Archive &ar, unsigned version)
const uint8_t * getReadCacheLine(size_t address) const
uint8_t read(size_t address)
power_of_two< size_t > size() const
uint8_t peek(size_t address) const
void printInfo(std::string_view message)
void printWarning(std::string_view message)
MSXCliComm & getCliComm() const
const XMLElement * getXML() const
void invalidateAllSlotsRWCache(word start, unsigned size)
Invalidate the CPU its cache for the interval [start, start + size) For example MSXMemoryMapper and M...
static std::array< byte, 0x10000 > unmappedRead
std::string_view getFilename() const
const XMLElement * findChild(std::string_view childName) const
constexpr size_t size() const noexcept
This file implemented 3 utility functions:
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
constexpr from_range_t from_range
constexpr auto to_underlying(E e) noexcept
void serialize(Archive &ar, unsigned version)
ManufacturerID manufacturer
static_vector< uint8_t, 2 > device
uint8_t simultaneousOperation
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm::Supply supply
uint8_t addressSensitiveUnlock
uint8_t sectorTemporaryUnprotect
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm::Version version
uint8_t sectorProtectScheme
power_of_two< unsigned > singleProgram
power_of_two< unsigned > chipErase
power_of_two< unsigned > sectorErase
power_of_two< unsigned > multiProgram
power_of_two< unsigned > chipErase
power_of_two< unsigned > sectorErase
power_of_two< unsigned > multiProgram
power_of_two< unsigned > singleProgram
struct openmsx::AmdFlash::CFI::SystemInterface::Supply supply
struct openmsx::AmdFlash::CFI::SystemInterface::MaxTimeoutMultiplier maxTimeoutMult
struct openmsx::AmdFlash::CFI::SystemInterface::TypicalTimeout typTimeout
struct openmsx::AmdFlash::CFI::SystemInterface systemInterface
bool withManufacturerDevice
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm primaryAlgorithm
static_vector< Region, 4 > regions
DeviceInterface deviceInterface
power_of_two< size_t > size
power_of_two< size_t > pageSize
const uint8_t * readAddress
constexpr auto xrange(T e)