28 : motherBoard(config.getMotherBoard())
29 , sectorInfo(std::move(sectorInfo_))
32 , addressing(addressing_)
34 init(rom.getName() +
"_flash", config,
load, &rom);
40 : motherBoard(config.getMotherBoard())
41 , sectorInfo(std::move(sectorInfo_))
44 , addressing(addressing_)
46 init(name, config, Load::NORMAL,
nullptr);
49 [[nodiscard]]
static bool sramEmpty(
const SRAM& ram)
52 [&](
auto i) { return ram[i] == 0xFF; });
55 void AmdFlash::init(
const string& name,
const DeviceConfig& config, Load
load,
const Rom* rom)
59 auto numSectors = sectorInfo.size();
61 unsigned writableSize = 0;
62 unsigned readOnlySize = 0;
63 writeAddress.
resize(numSectors);
64 for (
auto i :
xrange(numSectors)) {
65 if (sectorInfo[i].writeProtected) {
67 readOnlySize += sectorInfo[i].size;
69 writeAddress[i] = writableSize;
70 writableSize += sectorInfo[i].size;
73 assert((writableSize + readOnlySize) ==
getSize());
78 ram = std::make_unique<SRAM>(
80 writableSize, config,
nullptr, &loaded);
86 ram = std::make_unique<SRAM>(
88 writableSize, config, SRAM::DontLoadTag{});
97 const auto* romTag = config.getXML()->findChild(
"rom");
98 bool initialContentSpecified = romTag && romTag->findChild(
"sha1");
101 if (!rom && loaded && initialContentSpecified && sramEmpty(*ram)) {
102 config.getCliComm().printInfo(
103 "This flash device (", config.getHardwareConfig().getName(),
104 ") has initial content specified, but this content "
105 "was not loaded, because there was already content found "
106 "and loaded from persistent storage. However, this "
107 "content is blank (it was probably created automatically "
108 "when the specified initial content could not be loaded "
109 "when this device was used for the first time). If you "
110 "still wish to load the specified initial content, "
111 "please remove the blank persistent storage file: ",
112 ram->getLoadedFilename());
115 std::unique_ptr<Rom> rom_;
116 if (!rom && !loaded) {
124 rom_ = std::make_unique<Rom>(
128 config.getCliComm().printInfo(
129 "Loaded initial content for flash ROM from ",
131 }
catch (MSXException& e) {
133 assert(rom ==
nullptr);
135 if (initialContentSpecified) {
136 config.getCliComm().printWarning(
137 "Could not load specified initial content "
138 "for flash ROM: ", e.getMessage());
143 readAddress.
resize(numSectors);
144 unsigned romSize = rom ? rom->getSize() : 0;
146 for (
auto i :
xrange(numSectors)) {
147 unsigned sectorSize = sectorInfo[i].size;
148 if (isSectorWritable(
unsigned(i))) {
149 readAddress[i] = &(*ram)[writeAddress[i]];
151 auto* ramPtr =
const_cast<byte*
>(
152 &(*ram)[writeAddress[i]]);
153 if (offset >= romSize) {
155 memset(ramPtr, 0xFF, sectorSize);
156 }
else if (offset + sectorSize >= romSize) {
158 unsigned last = romSize - offset;
159 unsigned missing = sectorSize - last;
160 const byte* romPtr = &(*rom)[offset];
161 memcpy(ramPtr, romPtr, last);
162 memset(ramPtr + last, 0xFF, missing);
165 const byte* romPtr = &(*rom)[offset];
166 memcpy(ramPtr, romPtr, sectorSize);
171 if ((offset + sectorSize) <= romSize) {
172 readAddress[i] = &(*rom)[offset];
174 readAddress[i] =
nullptr;
177 offset += sectorSize;
186 AmdFlash::GetSectorInfoResult AmdFlash::getSectorInfo(
unsigned address)
const
189 auto it = sectorInfo.begin();
191 while (address >= it->size) {
195 assert(it != sectorInfo.end());
197 unsigned sectorSize = it->size;
198 unsigned offset = address;
199 return {sector, sectorSize, offset};
208 void AmdFlash::setState(State newState)
210 if (state == newState)
return;
217 auto [sector, sectorSize, offset] = getSectorInfo(address);
219 if (
const byte* addr = readAddress[sector]) {
229 switch (address & 3) {
236 return isSectorWritable(sector) ? 0 : 1;
246 bool AmdFlash::isSectorWritable(
unsigned sector)
const
248 return vppWpPinLow && (sector ==
one_of(0u, 1u)) ?
false : (writeAddress[sector] != -1) ;
254 return peek(address);
260 auto [sector, sectorSize, offset] = getSectorInfo(address);
261 const byte* addr = readAddress[sector];
270 assert(cmdIdx < MAX_CMD_SIZE);
271 cmd[cmdIdx].
addr = address;
272 cmd[cmdIdx].
value = value;
274 if (checkCommandManufacturer() ||
275 checkCommandEraseSector() ||
276 checkCommandProgram() ||
277 checkCommandDoubleByteProgram() ||
278 checkCommandQuadrupleByteProgram() ||
279 checkCommandEraseChip() ||
280 checkCommandReset()) {
292 bool AmdFlash::checkCommandReset()
294 if (cmd[0].value == 0xf0) {
300 bool AmdFlash::checkCommandEraseSector()
302 static constexpr
byte cmdSeq[] = { 0xaa, 0x55, 0x80, 0xaa, 0x55 };
303 if (partialMatch(5, cmdSeq)) {
304 if (cmdIdx < 6)
return true;
305 if (cmd[5].value == 0x30) {
306 unsigned addr = cmd[5].
addr;
307 auto [sector, sectorSize, offset] = getSectorInfo(addr);
308 if (isSectorWritable(sector)) {
309 ram->memset(writeAddress[sector],
317 bool AmdFlash::checkCommandEraseChip()
319 static constexpr
byte cmdSeq[] = { 0xaa, 0x55, 0x80, 0xaa, 0x55 };
320 if (partialMatch(5, cmdSeq)) {
321 if (cmdIdx < 6)
return true;
322 if (cmd[5].value == 0x10) {
323 if (ram) ram->memset(0, 0xff, ram->getSize());
329 bool AmdFlash::checkCommandProgramHelper(
unsigned numBytes,
const byte* cmdSeq,
size_t cmdLen)
331 if (partialMatch(cmdLen, cmdSeq)) {
332 if (cmdIdx < (cmdLen + numBytes))
return true;
333 for (
auto i :
xrange(cmdLen, cmdLen + numBytes)) {
334 unsigned addr = cmd[i].
addr;
335 auto [sector, sectorSize, offset] = getSectorInfo(addr);
336 if (isSectorWritable(sector)) {
337 unsigned ramAddr = writeAddress[sector] + offset;
338 ram->write(ramAddr, (*ram)[ramAddr] & cmd[i].value);
345 bool AmdFlash::checkCommandProgram()
347 static constexpr
byte cmdSeq[] = { 0xaa, 0x55, 0xa0 };
348 return checkCommandProgramHelper(1, cmdSeq,
std::size(cmdSeq));
351 bool AmdFlash::checkCommandDoubleByteProgram()
353 static constexpr
byte cmdSeq[] = { 0x50 };
354 return checkCommandProgramHelper(2, cmdSeq,
std::size(cmdSeq));
357 bool AmdFlash::checkCommandQuadrupleByteProgram()
359 static constexpr
byte cmdSeq[] = { 0x56 };
360 return checkCommandProgramHelper(4, cmdSeq,
std::size(cmdSeq));
363 bool AmdFlash::checkCommandManufacturer()
365 static constexpr
byte cmdSeq[] = { 0xaa, 0x55, 0x90 };
366 if (partialMatch(3, cmdSeq)) {
370 if (cmdIdx < 4)
return true;
375 bool AmdFlash::partialMatch(
size_t len,
const byte* dataSeq)
const
377 static constexpr
unsigned addrSeq[] = { 0, 1, 0, 0, 1 };
378 unsigned cmdAddr[2] = { 0x555, 0x2aa };
384 if (((addr & 0x7FF) != cmdAddr[addrSeq[i]]) ||
385 (cmd[i].
value != dataSeq[i])) {
393 static constexpr std::initializer_list<enum_string<AmdFlash::State>> stateInfo = {
399 template<
typename Archive>
402 ar.serialize(
"address",
addr,
406 template<
typename Archive>
409 ar.serialize(
"ram", *ram,
413 if (ar.versionAtLeast(version, 2)) {
414 ar.serialize(
"vppWpPinLow", vppWpPinLow);
void write(unsigned address, byte value)
void serialize(Archive &ar, unsigned version)
byte peek(unsigned address) const
byte read(unsigned address) const
AmdFlash(const Rom &rom, span< const SectorInfo > sectorInfo, word ID, Addressing addressing, const DeviceConfig &config, Load load=Load::NORMAL)
Create AmdFlash with given configuration.
const byte * getReadCacheLine(unsigned address) const
void invalidateAllSlotsRWCache(word start, unsigned size)
Invalidate the CPU its cache for the interval [start, start + size) For example MSXMemoryMapper and M...
static byte unmappedRead[0x10000]
void resize(size_t size)
Grow or shrink the memory block.
constexpr bool ispow2(T x) noexcept
Is the given number an integral power of two? That is, does it have exactly one 1-bit in binary repre...
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
XMLElement load(const string &filename, string_view systemID)
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
uint16_t word
16 bit unsigned integer
bool all_of(InputRange &&range, UnaryPredicate pred)
auto transform(InputRange &&range, OutputIter out, UnaryOperation op)
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
auto sum(InputRange &&range)
void serialize(Archive &ar, unsigned version)
constexpr auto xrange(T e)