25 : motherBoard(config.getMotherBoard())
26 , sectorInfo(
std::move(sectorInfo_))
29 , addressing(addressing_)
37 : motherBoard(config.getMotherBoard())
38 , sectorInfo(
std::move(sectorInfo_))
41 , addressing(addressing_)
46[[nodiscard]]
static bool sramEmpty(
const SRAM& ram)
49 [&](
auto i) { return ram[i] == 0xFF; });
52void AmdFlash::init(
const std::string& name,
const DeviceConfig& config, Load
load,
const Rom* rom)
54 assert(std::has_single_bit(
size()));
56 auto numSectors = sectorInfo.size();
58 size_t writableSize = 0;
59 size_t readOnlySize = 0;
60 writeAddress.
resize(numSectors);
61 for (
auto i :
xrange(numSectors)) {
62 if (sectorInfo[i].writeProtected) {
64 readOnlySize += sectorInfo[i].size;
66 writeAddress[i] = narrow<ptrdiff_t>(writableSize);
67 writableSize += sectorInfo[i].size;
70 assert((writableSize + readOnlySize) ==
size());
75 ram = std::make_unique<SRAM>(
77 writableSize, config,
nullptr, &loaded);
83 ram = std::make_unique<SRAM>(
85 writableSize, config, SRAM::DontLoadTag{});
94 const auto* romTag = config.getXML()->findChild(
"rom");
95 bool initialContentSpecified = romTag && romTag->findChild(
"sha1");
98 if (!rom && loaded && initialContentSpecified && sramEmpty(*ram)) {
99 config.getCliComm().printInfo(
100 "This flash device (", config.getHardwareConfig().getName(),
101 ") has initial content specified, but this content "
102 "was not loaded, because there was already content found "
103 "and loaded from persistent storage. However, this "
104 "content is blank (it was probably created automatically "
105 "when the specified initial content could not be loaded "
106 "when this device was used for the first time). If you "
107 "still wish to load the specified initial content, "
108 "please remove the blank persistent storage file: ",
112 std::unique_ptr<Rom> rom_;
113 if (!rom && !loaded) {
121 rom_ = std::make_unique<Rom>(
125 config.getCliComm().printInfo(
126 "Loaded initial content for flash ROM from ",
128 }
catch (MSXException&
e) {
130 assert(rom ==
nullptr);
132 if (initialContentSpecified) {
133 config.getCliComm().printWarning(
134 "Could not load specified initial content "
135 "for flash ROM: ",
e.getMessage());
140 readAddress.
resize(numSectors);
141 auto romSize = rom ? rom->size() : 0;
143 for (
auto i :
xrange(numSectors)) {
144 auto sectorSize = sectorInfo[i].size;
145 if (isSectorWritable(i)) {
146 readAddress[i] = &(*ram)[writeAddress[i]];
148 auto* ramPtr =
const_cast<uint8_t*
>(
149 &(*ram)[writeAddress[i]]);
150 if (offset >= romSize) {
153 }
else if (offset + sectorSize >= romSize) {
155 auto last = romSize - offset;
156 auto missing = sectorSize - last;
157 const uint8_t* romPtr = &(*rom)[offset];
162 const uint8_t* romPtr = &(*rom)[offset];
168 if ((offset + sectorSize) <= romSize) {
169 readAddress[i] = &(*rom)[offset];
171 readAddress[i] =
nullptr;
174 offset += sectorSize;
176 assert(offset ==
size());
183AmdFlash::GetSectorInfoResult AmdFlash::getSectorInfo(
size_t address)
const
185 address &=
size() - 1;
186 auto it = sectorInfo.begin();
188 while (address >= it->size) {
192 assert(it != sectorInfo.end());
194 auto sectorSize = it->size;
195 auto offset = address;
196 return {sector, sectorSize, offset};
205void AmdFlash::setState(State newState)
207 if (state == newState)
return;
214 auto [sector, sectorSize, offset] = getSectorInfo(address);
216 if (
const uint8_t* addr = readAddress[sector]) {
226 switch (address & 3) {
228 return narrow_cast<uint8_t>(ID >> 8);
230 return narrow_cast<uint8_t>(ID & 0xFF);
233 return isSectorWritable(sector) ? 0 : 1;
243bool AmdFlash::isSectorWritable(
size_t sector)
const
245 return vppWpPinLow && (sector ==
one_of(0u, 1u)) ?
false : (writeAddress[sector] != -1) ;
251 return peek(address);
257 auto [sector, sectorSize, offset] = getSectorInfo(address);
258 const uint8_t* addr = readAddress[sector];
267 assert(cmdIdx < MAX_CMD_SIZE);
268 cmd[cmdIdx].addr = address;
269 cmd[cmdIdx].value = value;
271 if (checkCommandManufacturer() ||
272 checkCommandEraseSector() ||
273 checkCommandProgram() ||
274 checkCommandDoubleByteProgram() ||
275 checkCommandQuadrupleByteProgram() ||
276 checkCommandEraseChip() ||
277 checkCommandReset()) {
289bool AmdFlash::checkCommandReset()
291 if (cmd[0].value == 0xf0) {
297bool AmdFlash::checkCommandEraseSector()
299 static constexpr std::array<uint8_t, 5> cmdSeq = {0xaa, 0x55, 0x80, 0xaa, 0x55};
300 if (partialMatch(cmdSeq)) {
301 if (cmdIdx < 6)
return true;
302 if (cmd[5].value == 0x30) {
303 auto addr = cmd[5].addr;
304 auto [sector, sectorSize, offset] = getSectorInfo(addr);
305 if (isSectorWritable(sector)) {
306 ram->
memset(writeAddress[sector],
314bool AmdFlash::checkCommandEraseChip()
316 static constexpr std::array<uint8_t, 5> cmdSeq = {0xaa, 0x55, 0x80, 0xaa, 0x55};
317 if (partialMatch(cmdSeq)) {
318 if (cmdIdx < 6)
return true;
319 if (cmd[5].value == 0x10) {
326bool AmdFlash::checkCommandProgramHelper(
size_t numBytes, std::span<const uint8_t> cmdSeq)
328 if (partialMatch(cmdSeq)) {
329 if (cmdIdx < (cmdSeq.size() + numBytes))
return true;
330 for (
auto i :
xrange(cmdSeq.size(), cmdSeq.size() + numBytes)) {
331 auto addr = cmd[i].addr;
332 auto [sector, sectorSize, offset] = getSectorInfo(addr);
333 if (isSectorWritable(sector)) {
334 auto ramAddr = writeAddress[sector] + offset;
335 ram->
write(ramAddr, (*ram)[ramAddr] & cmd[i].value);
342bool AmdFlash::checkCommandProgram()
344 static constexpr std::array<uint8_t, 3> cmdSeq = {0xaa, 0x55, 0xa0};
345 return checkCommandProgramHelper(1, cmdSeq);
348bool AmdFlash::checkCommandDoubleByteProgram()
350 static constexpr std::array<uint8_t, 1> cmdSeq = {0x50};
351 return checkCommandProgramHelper(2, cmdSeq);
354bool AmdFlash::checkCommandQuadrupleByteProgram()
356 static constexpr std::array<uint8_t, 1> cmdSeq = {0x56};
357 return checkCommandProgramHelper(4, cmdSeq);
360bool AmdFlash::checkCommandManufacturer()
362 static constexpr std::array<uint8_t, 3> cmdSeq = {0xaa, 0x55, 0x90};
363 if (partialMatch(cmdSeq)) {
367 if (cmdIdx < 4)
return true;
372bool AmdFlash::partialMatch(std::span<const uint8_t> dataSeq)
const
374 static constexpr std::array<unsigned, 5> addrSeq = {0, 1, 0, 0, 1};
375 static constexpr std::array<unsigned, 2> cmdAddr = {0x555, 0x2aa};
377 assert(dataSeq.size() <= 5);
378 for (
auto i :
xrange(
std::min(
unsigned(dataSeq.size()), cmdIdx))) {
381 if (((addr & 0x7FF) != cmdAddr[addrSeq[i]]) ||
382 (cmd[i].value != dataSeq[i])) {
390static constexpr std::initializer_list<enum_string<AmdFlash::State>> stateInfo = {
396template<
typename Archive>
399 ar.serialize(
"address",
addr,
403template<
typename Archive>
406 ar.serialize(
"ram", *ram,
410 if (ar.versionAtLeast(version, 2)) {
411 ar.serialize(
"vppWpPinLow", vppWpPinLow);
void write(size_t address, uint8_t value)
AmdFlash(const Rom &rom, std::span< const SectorInfo > sectorInfo, uint16_t ID, Addressing addressing, const DeviceConfig &config, Load load=Load::NORMAL)
Create AmdFlash with given configuration.
void serialize(Archive &ar, unsigned version)
const uint8_t * getReadCacheLine(size_t address) const
uint8_t peek(size_t address) const
uint8_t read(size_t 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 std::array< byte, 0x10000 > unmappedRead
void resize(size_t size)
Grow or shrink the memory block.
const std::string & getName() const
const std::string & getLoadedFilename() const
void write(size_t addr, byte value)
void memset(size_t addr, byte c, size_t size)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
SDLSurfacePtr load(const std::string &filename, bool want32bpp)
Load the given PNG file in a SDL_Surface.
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
auto copy(InputRange &&range, OutputIter out)
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
auto sum(InputRange &&range, Proj proj={})
void serialize(Archive &ar, unsigned version)
constexpr auto xrange(T e)