260static constexpr unsigned MEMORY_MAPPER_SIZE = 512;
261static constexpr uint8_t MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
265static constexpr auto sectorInfo = [] {
267 using Info = AmdFlash::SectorInfo;
268 std::array<Info, 8 + 127> result = {};
269 std::fill(result.begin(), result.begin() + 8,
Info{ 8 * 1024, false});
270 std::fill(result.begin() + 8, result.end(),
Info{64 * 1024, false});
277 , flash(
"MFR SCC+ SD flash", sectorInfo, 0x207E,
278 AmdFlash::Addressing::BITS_12, config)
279 , scc(
"MFR SCC+ SD SCC-I", config, getCurrentTime(),
SCC::SCC_Compatible)
282 , checkedRam(config.getChildDataAsBool(
"hasmemorymapper", true) ?
283 std::make_unique<
CheckedRam>(config, getName() +
" memory mapper",
"memory mapper", MEMORY_MAPPER_SIZE * 1024)
285 , mapperIO(checkedRam ?
std::make_unique<MapperIO>(*this) : nullptr)
288 for (
auto port : {0x10, 0x11}) {
300 for (
auto port : {0x10, 0x11}) {
329 for (
auto [i, mr] :
enumerate(memMapperRegs)) {
333 for (
auto [bank, reg] :
enumerate(bankRegsSubSlot3)) {
334 reg = (bank == 1) ? 1 : 0;
342byte MegaFlashRomSCCPlusSD::getSubSlot(
unsigned addr)
const
344 return isSlotExpanderEnabled() ?
345 (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
348void MegaFlashRomSCCPlusSD::writeToFlash(
unsigned addr,
byte value)
350 if (isFlashRomWriteEnabled()) {
351 flash.
write(addr, value);
360 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
362 return subslotReg ^ 0xFF;
365 switch (getSubSlot(addr)) {
366 case 0:
return peekMemSubSlot0(addr);
367 case 1:
return peekMemSubSlot1(addr, time);
368 case 2:
return isMemoryMapperEnabled() ?
369 peekMemSubSlot2(addr) : 0xFF;
370 case 3:
return peekMemSubSlot3(addr, time);
377 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
379 return subslotReg ^ 0xFF;
382 switch (getSubSlot(addr)) {
383 case 0:
return readMemSubSlot0(addr);
384 case 1:
return readMemSubSlot1(addr, time);
385 case 2:
return isMemoryMapperEnabled() ?
386 readMemSubSlot2(addr) : 0xFF;
387 case 3:
return readMemSubSlot3(addr, time);
394 if (isSlotExpanderEnabled() &&
400 switch (getSubSlot(addr)) {
401 case 0:
return getReadCacheLineSubSlot0(addr);
402 case 1:
return getReadCacheLineSubSlot1(addr);
403 case 2:
return isMemoryMapperEnabled() ?
405 case 3:
return getReadCacheLineSubSlot3(addr);
412 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
414 byte diff = value ^ subslotReg;
416 for (
auto i :
xrange(4)) {
417 if (diff & (3 << (2 * i))) {
423 switch (getSubSlot(addr)) {
424 case 0: writeMemSubSlot0(addr, value);
break;
425 case 1: writeMemSubSlot1(addr, value, time);
break;
426 case 2:
if (isMemoryMapperEnabled()) {
427 writeMemSubSlot2(addr, value);
430 case 3: writeMemSubSlot3(addr, value, time);
break;
437 if (isSlotExpanderEnabled() &&
443 switch (getSubSlot(addr)) {
444 case 0:
return getWriteCacheLineSubSlot0(addr);
445 case 1:
return getWriteCacheLineSubSlot1(addr);
446 case 2:
return isMemoryMapperEnabled() ?
448 case 3:
return getWriteCacheLineSubSlot3(addr);
455byte MegaFlashRomSCCPlusSD::readMemSubSlot0(
word addr)
const
459 return flash.
read(addr & 0x3FFF);
462byte MegaFlashRomSCCPlusSD::peekMemSubSlot0(
word addr)
const
466 return flash.
peek(addr & 0x3FFF);
469const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(
word addr)
const
474void MegaFlashRomSCCPlusSD::writeMemSubSlot0(
word addr,
byte value)
477 writeToFlash(addr & 0x3FFF, value);
480byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(
word )
const
487void MegaFlashRomSCCPlusSD::updateConfigReg(
byte value)
489 if ((value ^ configReg) & 0x08) {
491 for (
auto port : {0xa0, 0xa1}) {
495 for (
auto port : {0xa0, 0xa1}) {
505MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable()
const
507 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
509 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
516unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(
unsigned addr)
const
518 unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
519 unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
521 if (page >= 4)
return unsigned(-1);
523 unsigned bank = bankRegsSubSlot1[page];
524 if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
526 }
else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
532 unsigned tmp = (bank *
size) + (addr & (size - 1));
533 return (tmp + 0x010000) & 0x7FFFFF;
536byte MegaFlashRomSCCPlusSD::readMemSubSlot1(
word addr, EmuTime::param time)
538 if (isKonamiSCCmapperConfigured()) {
539 SCCEnable enable = getSCCEnable();
540 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
541 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
542 byte val = scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
547 unsigned flashAddr = getFlashAddrSubSlot1(addr);
548 return (flashAddr !=
unsigned(-1))
549 ? flash.
read(flashAddr)
553byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(
word addr, EmuTime::param time)
const
555 if (isKonamiSCCmapperConfigured()) {
556 SCCEnable enable = getSCCEnable();
557 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
558 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
559 byte val = scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
564 unsigned flashAddr = getFlashAddrSubSlot1(addr);
565 return (flashAddr !=
unsigned(-1))
566 ? flash.
peek(flashAddr)
570const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(
word addr)
const
572 if (isKonamiSCCmapperConfigured()) {
573 SCCEnable enable = getSCCEnable();
574 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
575 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
580 unsigned flashAddr = getFlashAddrSubSlot1(addr);
581 return (flashAddr !=
unsigned(-1))
586void MegaFlashRomSCCPlusSD::writeMemSubSlot1(
word addr,
byte value, EmuTime::param time)
589 unsigned flashAddr = getFlashAddrSubSlot1(addr);
598 if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
600 updateConfigReg(value);
603 if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
609 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
611 offsetReg = (offsetReg & 0x300) | value;
615 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
617 offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
621 if (isKonamiSCCmapperConfigured()) {
623 if ((addr & 0xFFFE) == 0xBFFE) {
626 :
SCC::SCC_Compatible);
630 SCCEnable enable = getSCCEnable();
631 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
632 ((sccMode & 0x10) == 0x10);
633 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
634 if (((enable == EN_SCC) && !isRamSegment2 &&
635 (0x9800 <= addr) && (addr < 0xA000)) ||
636 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
637 (0xB800 <= addr) && (addr < 0xC000))) {
638 scc.
writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
643 unsigned page8kB = (addr >> 13) - 2;
644 if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
646 switch (mapperReg & 0xE0) {
649 if ((addr & 0x1800) == 0x1000) {
653 sccBanks[page8kB] = value;
656 byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
657 bankRegsSubSlot1[page8kB] = value & mask;
663 if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
672 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
673 byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
674 bankRegsSubSlot1[page8kB] = value & mask;
681 bankRegsSubSlot1[page8kB] = value;
687 if ((0x6000 <= addr) && (addr < 0x8000)) {
688 byte bank = (addr >> 11) & 0x03;
689 bankRegsSubSlot1[bank] = value;
702 if ((0x6000 <= addr) && (addr < 0x6800)) {
703 bankRegsSubSlot1[0] = narrow_cast<uint8_t>(2 * value + 0);
704 bankRegsSubSlot1[1] = narrow_cast<uint8_t>(2 * value + 1);
707 if ((0x7000 <= addr) && (addr < 0x7800)) {
708 bankRegsSubSlot1[2] = narrow_cast<uint8_t>(2 * value + 0);
709 bankRegsSubSlot1[3] = narrow_cast<uint8_t>(2 * value + 1);
716 if (flashAddr !=
unsigned(-1)) {
717 writeToFlash(flashAddr, value);
721byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(
word )
const
728unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(
word address)
const
730 auto bank = memMapperRegs[address >> 14];
731 return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
734byte MegaFlashRomSCCPlusSD::readMemSubSlot2(
word addr)
737 return checkedRam->read(calcMemMapperAddress(addr));
740byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(
word addr)
const
742 return checkedRam->peek(calcMemMapperAddress(addr));
745const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(
word addr)
const
747 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
750void MegaFlashRomSCCPlusSD::writeMemSubSlot2(
word addr,
byte value)
753 checkedRam->write(calcMemMapperAddress(addr), value);
756byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(
word addr)
const
758 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
761byte MegaFlashRomSCCPlusSD::MapperIO::readIO(
word port, EmuTime::param time)
763 return peekIO(port, time);
766byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(
word port, EmuTime::param )
const
768 return getSelectedSegment(port & 3) |
byte(~MEMORY_MAPPER_MASK);
771void MegaFlashRomSCCPlusSD::MapperIO::writeIO(
word port,
byte value, EmuTime::param )
773 mega.memMapperRegs[port & 3] = value & MEMORY_MAPPER_MASK;
774 mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
777byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(
byte page)
const
779 return mega.memMapperRegs[page];
784unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(
unsigned addr)
const
786 unsigned page8kB = (addr >> 13) - 2;
787 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
790byte MegaFlashRomSCCPlusSD::readMemSubSlot3(
word addr, EmuTime::param )
792 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
794 return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
797 if ((0x4000 <= addr) && (addr < 0xC000)) {
799 unsigned flashAddr = getFlashAddrSubSlot3(addr);
800 return flash.
read(flashAddr);
807byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(
word addr, EmuTime::param )
const
809 if ((0x4000 <= addr) && (addr < 0xC000)) {
811 unsigned flashAddr = getFlashAddrSubSlot3(addr);
812 return flash.
peek(flashAddr);
819const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(
word addr)
const
821 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
825 if ((0x4000 <= addr) && (addr < 0xC000)) {
827 unsigned flashAddr = getFlashAddrSubSlot3(addr);
834void MegaFlashRomSCCPlusSD::writeMemSubSlot3(
word addr,
byte value, EmuTime::param )
837 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
838 if (addr >= 0x5800) {
839 selectedCard = value & 1;
842 sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0);
847 if ((0x4000 <= addr) && (addr < 0xC000)) {
848 unsigned flashAddr = getFlashAddrSubSlot3(addr);
849 writeToFlash(flashAddr, value);
853 if ((0x6000 <= addr) && (addr < 0x8000)) {
854 byte page8kB = (addr >> 11) & 0x03;
855 bankRegsSubSlot3[page8kB] = value;
860byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(
word )
const
869 switch (port & 0xFF) {
871 if (!isPSGalsoMappedToNormalPorts())
return;
874 psgLatch = value & 0x0F;
878 if (!isPSGalsoMappedToNormalPorts())
return;
889template<
typename Archive>
893 ar.template serializeBase<MSXDevice>(*
this);
896 ar.serialize(
"flash", flash,
897 "subslotReg", subslotReg);
903 ar.serialize(
"scc", scc,
905 "sccBanks", sccBanks,
907 "psgLatch", psgLatch,
908 "configReg", configReg,
909 "mapperReg", mapperReg,
910 "offsetReg", offsetReg,
911 "bankRegsSubSlot1", bankRegsSubSlot1);
912 if constexpr (Archive::IS_LOADER) {
914 byte tmp = configReg;
916 updateConfigReg(tmp);
921 if (checkedRam) ar.serialize(
"ram", checkedRam->getUncheckedRam());
922 ar.serialize(
"memMapperRegs", memMapperRegs);
925 ar.serialize(
"bankRegsSubSlot3", bankRegsSubSlot3,
926 "selectedCard", selectedCard,
927 "sdCard0", *sdCard[0],
928 "sdCard1", *sdCard[1]);
#define REGISTER_MSXDEVICE(CLASS, NAME)
void reset(EmuTime::param time)
void writeRegister(unsigned reg, uint8_t value, EmuTime::param time)
void write(size_t address, uint8_t value)
const uint8_t * getReadCacheLine(size_t address) const
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
uint8_t peek(size_t address) const
uint8_t read(size_t address) const
This class keeps track of which bytes in the Ram have been written to.
const XMLElement * findChild(std::string_view name) const
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void unregister_IO_Out(byte port, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
static std::array< byte, 0x10000 > unmappedRead
static std::array< byte, 0x10000 > unmappedWrite
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
EmuTime::param getCurrentTime() const
MSXCPUInterface & getCPUInterface() const
void serialize(Archive &ar, unsigned version)
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
void reset(EmuTime::param time) override
This method is called on reset.
MegaFlashRomSCCPlusSD(const DeviceConfig &config)
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
~MegaFlashRomSCCPlusSD() override
void setChipMode(ChipMode newMode)
void powerUp(EmuTime::param time)
uint8_t readMem(uint8_t address, EmuTime::param time)
void reset(EmuTime::param time)
uint8_t peekMem(uint8_t address, EmuTime::param time) const
void writeMem(uint8_t address, uint8_t value, EmuTime::param time)
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer
AmdFlash::SectorInfo Info
uint16_t word
16 bit unsigned integer
constexpr void iota(ForwardIt first, ForwardIt last, T value)
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)