263static constexpr unsigned MEMORY_MAPPER_SIZE = 512;
264static constexpr uint8_t MEMORY_MAPPER_MASK = (MEMORY_MAPPER_SIZE / 16) - 1;
270 , flash(
"MFR SCC+ SD flash", AmdFlashChip::M29W640GB, {}, config)
274 , checkedRam(config.getChildDataAsBool(
"hasmemorymapper",
true) ?
275 std::make_unique<CheckedRam>(config, getName() +
" memory mapper",
"memory mapper", MEMORY_MAPPER_SIZE * 1024)
277 , mapperIO(checkedRam ?
std::make_unique<MapperIO>(*this) : nullptr)
280 for (
auto port : {0x10, 0x11}) {
284 sdCard[0] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild(
"sdcard1")));
285 sdCard[1] = std::make_unique<SdCard>(DeviceConfig(config, config.findChild(
"sdcard2")));
292 for (
auto port : {0x10, 0x11}) {
321 for (
auto [i, mr] :
enumerate(memMapperRegs)) {
325 for (
auto [bank, reg] :
enumerate(bankRegsSubSlot3)) {
326 reg = (bank == 1) ? 1 : 0;
334byte MegaFlashRomSCCPlusSD::getSubSlot(
unsigned addr)
const
336 return isSlotExpanderEnabled() ?
337 (subslotReg >> (2 * (addr >> 14))) & 3 : 1;
340void MegaFlashRomSCCPlusSD::writeToFlash(
unsigned addr,
byte value)
342 if (isFlashRomWriteEnabled()) {
343 flash.
write(addr, value);
352 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
354 return subslotReg ^ 0xFF;
357 switch (getSubSlot(addr)) {
358 case 0:
return peekMemSubSlot0(addr);
359 case 1:
return peekMemSubSlot1(addr, time);
360 case 2:
return isMemoryMapperEnabled() ?
361 peekMemSubSlot2(addr) : 0xFF;
362 case 3:
return peekMemSubSlot3(addr, time);
369 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
371 return subslotReg ^ 0xFF;
374 switch (getSubSlot(addr)) {
375 case 0:
return readMemSubSlot0(addr);
376 case 1:
return readMemSubSlot1(addr, time);
377 case 2:
return isMemoryMapperEnabled() ?
378 readMemSubSlot2(addr) : 0xFF;
379 case 3:
return readMemSubSlot3(addr, time);
386 if (isSlotExpanderEnabled() &&
392 switch (getSubSlot(addr)) {
393 case 0:
return getReadCacheLineSubSlot0(addr);
394 case 1:
return getReadCacheLineSubSlot1(addr);
395 case 2:
return isMemoryMapperEnabled() ?
397 case 3:
return getReadCacheLineSubSlot3(addr);
404 if (isSlotExpanderEnabled() && (addr == 0xFFFF)) {
406 byte diff = value ^ subslotReg;
408 for (
auto i :
xrange(4)) {
409 if (diff & (3 << (2 * i))) {
415 switch (getSubSlot(addr)) {
416 case 0: writeMemSubSlot0(addr, value);
break;
417 case 1: writeMemSubSlot1(addr, value, time);
break;
418 case 2:
if (isMemoryMapperEnabled()) {
419 writeMemSubSlot2(addr, value);
422 case 3: writeMemSubSlot3(addr, value, time);
break;
429 if (isSlotExpanderEnabled() &&
435 switch (getSubSlot(addr)) {
436 case 0:
return getWriteCacheLineSubSlot0(addr);
437 case 1:
return getWriteCacheLineSubSlot1(addr);
438 case 2:
return isMemoryMapperEnabled() ?
440 case 3:
return getWriteCacheLineSubSlot3(addr);
447byte MegaFlashRomSCCPlusSD::readMemSubSlot0(
word addr)
451 return flash.
read(addr & 0x3FFF);
454byte MegaFlashRomSCCPlusSD::peekMemSubSlot0(
word addr)
const
458 return flash.
peek(addr & 0x3FFF);
461const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot0(
word addr)
const
466void MegaFlashRomSCCPlusSD::writeMemSubSlot0(
word addr,
byte value)
469 writeToFlash(addr & 0x3FFF, value);
472byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot0(
word )
479void MegaFlashRomSCCPlusSD::updateConfigReg(
byte value)
481 if ((value ^ configReg) & 0x08) {
483 for (
auto port : {0xa0, 0xa1}) {
487 for (
auto port : {0xa0, 0xa1}) {
497MegaFlashRomSCCPlusSD::SCCEnable MegaFlashRomSCCPlusSD::getSCCEnable()
const
499 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
501 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
508unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot1(
unsigned addr)
const
510 unsigned page = is64KmapperConfigured() ? (addr >> 14) : ((addr >> 13) - 2);
511 unsigned size = is64KmapperConfigured() ? 0x4000 : 0x2000;
513 if (page >= 4)
return unsigned(-1);
515 unsigned bank = bankRegsSubSlot1[page];
516 if (isDSKmodeEnabled() && (page == 0) && (bank == 0)) {
518 }
else if (isDSKmodeEnabled() && (page == 1) && (bank == 1)) {
524 unsigned tmp = (bank *
size) + (addr & (size - 1));
525 return (tmp + 0x010000) & 0x7FFFFF;
528byte MegaFlashRomSCCPlusSD::readMemSubSlot1(
word addr, EmuTime::param time)
530 if (isKonamiSCCmapperConfigured()) {
531 SCCEnable enable = getSCCEnable();
532 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
533 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
534 byte val = scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
539 unsigned flashAddr = getFlashAddrSubSlot1(addr);
540 return (flashAddr !=
unsigned(-1))
541 ? flash.
read(flashAddr)
545byte MegaFlashRomSCCPlusSD::peekMemSubSlot1(
word addr, EmuTime::param time)
const
547 if (isKonamiSCCmapperConfigured()) {
548 SCCEnable enable = getSCCEnable();
549 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
550 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
551 byte val = scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
556 unsigned flashAddr = getFlashAddrSubSlot1(addr);
557 return (flashAddr !=
unsigned(-1))
558 ? flash.
peek(flashAddr)
562const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot1(
word addr)
const
564 if (isKonamiSCCmapperConfigured()) {
565 SCCEnable enable = getSCCEnable();
566 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
567 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
572 unsigned flashAddr = getFlashAddrSubSlot1(addr);
573 return (flashAddr !=
unsigned(-1))
578void MegaFlashRomSCCPlusSD::writeMemSubSlot1(
word addr,
byte value, EmuTime::param time)
581 unsigned flashAddr = getFlashAddrSubSlot1(addr);
590 if (!isConfigRegDisabled() && (addr == 0x7FFC)) {
592 updateConfigReg(value);
595 if (!isMapperRegisterDisabled() && (addr == 0x7FFF)) {
601 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFD)) {
603 offsetReg = (offsetReg & 0x300) | value;
607 if (!areBankRegsAndOffsetRegsDisabled() && (addr == 0x7FFE)) {
609 offsetReg = (offsetReg & 0xFF) + ((value & 0x3) << 8);
613 if (isKonamiSCCmapperConfigured()) {
615 if ((addr & 0xFFFE) == 0xBFFE) {
618 :
SCC::Mode::Compatible);
622 SCCEnable enable = getSCCEnable();
623 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
624 ((sccMode & 0x10) == 0x10);
625 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
626 if (((enable == EN_SCC) && !isRamSegment2 &&
627 (0x9800 <= addr) && (addr < 0xA000)) ||
628 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
629 (0xB800 <= addr) && (addr < 0xC000))) {
630 scc.
writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
635 unsigned page8kB = (addr >> 13) - 2;
636 if (!areBankRegsAndOffsetRegsDisabled() && (page8kB < 4)) {
638 switch (mapperReg & 0xE0) {
641 if ((addr & 0x1800) == 0x1000) {
645 sccBanks[page8kB] = value;
648 byte mask = areKonamiMapperLimitsEnabled() ? 0x3F : 0xFF;
649 bankRegsSubSlot1[page8kB] = value & mask;
655 if (isWritingKonamiBankRegisterDisabled() && (addr < 0x6000)) {
664 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
665 byte mask = areKonamiMapperLimitsEnabled() ? 0x1F : 0xFF;
666 bankRegsSubSlot1[page8kB] = value & mask;
673 bankRegsSubSlot1[page8kB] = value;
679 if ((0x6000 <= addr) && (addr < 0x8000)) {
680 byte bank = (addr >> 11) & 0x03;
681 bankRegsSubSlot1[bank] = value;
694 if ((0x6000 <= addr) && (addr < 0x6800)) {
695 bankRegsSubSlot1[0] = narrow_cast<uint8_t>(2 * value + 0);
696 bankRegsSubSlot1[1] = narrow_cast<uint8_t>(2 * value + 1);
699 if ((0x7000 <= addr) && (addr < 0x7800)) {
700 bankRegsSubSlot1[2] = narrow_cast<uint8_t>(2 * value + 0);
701 bankRegsSubSlot1[3] = narrow_cast<uint8_t>(2 * value + 1);
708 if (flashAddr !=
unsigned(-1)) {
709 writeToFlash(flashAddr, value);
713byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot1(
word )
720unsigned MegaFlashRomSCCPlusSD::calcMemMapperAddress(
word address)
const
722 auto bank = memMapperRegs[address >> 14];
723 return ((bank & MEMORY_MAPPER_MASK) << 14) | (address & 0x3FFF);
726byte MegaFlashRomSCCPlusSD::readMemSubSlot2(
word addr)
729 return checkedRam->read(calcMemMapperAddress(addr));
732byte MegaFlashRomSCCPlusSD::peekMemSubSlot2(
word addr)
const
734 return checkedRam->peek(calcMemMapperAddress(addr));
737const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot2(
word addr)
const
739 return checkedRam->getReadCacheLine(calcMemMapperAddress(addr));
742void MegaFlashRomSCCPlusSD::writeMemSubSlot2(
word addr,
byte value)
745 checkedRam->write(calcMemMapperAddress(addr), value);
748byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot2(
word addr)
750 return checkedRam->getWriteCacheLine(calcMemMapperAddress(addr));
753byte MegaFlashRomSCCPlusSD::MapperIO::readIO(
word port, EmuTime::param time)
755 return peekIO(port, time);
758byte MegaFlashRomSCCPlusSD::MapperIO::peekIO(
word port, EmuTime::param )
const
760 return getSelectedSegment(port & 3) |
byte(~MEMORY_MAPPER_MASK);
763void MegaFlashRomSCCPlusSD::MapperIO::writeIO(
word port,
byte value, EmuTime::param )
765 mega.memMapperRegs[port & 3] = value & MEMORY_MAPPER_MASK;
766 mega.invalidateDeviceRWCache(0x4000 * (port & 0x03), 0x4000);
769byte MegaFlashRomSCCPlusSD::MapperIO::getSelectedSegment(
byte page)
const
771 return mega.memMapperRegs[page];
776unsigned MegaFlashRomSCCPlusSD::getFlashAddrSubSlot3(
unsigned addr)
const
778 unsigned page8kB = (addr >> 13) - 2;
779 return (bankRegsSubSlot3[page8kB] & 0x7f) * 0x2000 + (addr & 0x1fff) + 0x700000;
782byte MegaFlashRomSCCPlusSD::readMemSubSlot3(
word addr, EmuTime::param )
784 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
786 return sdCard[selectedCard]->transfer(0xFF, (addr & 0x1000) != 0);
789 if ((0x4000 <= addr) && (addr < 0xC000)) {
791 unsigned flashAddr = getFlashAddrSubSlot3(addr);
792 return flash.
read(flashAddr);
799byte MegaFlashRomSCCPlusSD::peekMemSubSlot3(
word addr, EmuTime::param )
const
801 if ((0x4000 <= addr) && (addr < 0xC000)) {
803 unsigned flashAddr = getFlashAddrSubSlot3(addr);
804 return flash.
peek(flashAddr);
811const byte* MegaFlashRomSCCPlusSD::getReadCacheLineSubSlot3(
word addr)
const
813 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
817 if ((0x4000 <= addr) && (addr < 0xC000)) {
819 unsigned flashAddr = getFlashAddrSubSlot3(addr);
826void MegaFlashRomSCCPlusSD::writeMemSubSlot3(
word addr,
byte value, EmuTime::param )
829 if (((bankRegsSubSlot3[0] & 0xC0) == 0x40) && ((0x4000 <= addr) && (addr < 0x6000))) {
830 if (addr >= 0x5800) {
831 selectedCard = value & 1;
834 sdCard[selectedCard]->transfer(value, (addr & 0x1000) != 0);
838 if ((0x4000 <= addr) && (addr < 0xC000)) {
839 unsigned flashAddr = getFlashAddrSubSlot3(addr);
840 writeToFlash(flashAddr, value);
844 if ((0x6000 <= addr) && (addr < 0x8000)) {
845 byte page8kB = (addr >> 11) & 0x03;
846 bankRegsSubSlot3[page8kB] = value;
852byte* MegaFlashRomSCCPlusSD::getWriteCacheLineSubSlot3(
word )
861 switch (port & 0xFF) {
863 if (!isPSGalsoMappedToNormalPorts())
return;
866 psgLatch = value & 0x0F;
870 if (!isPSGalsoMappedToNormalPorts())
return;
881template<
typename Archive>
885 ar.template serializeBase<MSXDevice>(*
this);
888 ar.serialize(
"flash", flash,
889 "subslotReg", subslotReg);
895 ar.serialize(
"scc", scc,
897 "sccBanks", sccBanks,
899 "psgLatch", psgLatch,
900 "configReg", configReg,
901 "mapperReg", mapperReg,
902 "offsetReg", offsetReg,
903 "bankRegsSubSlot1", bankRegsSubSlot1);
904 if constexpr (Archive::IS_LOADER) {
906 byte tmp = configReg;
908 updateConfigReg(tmp);
913 if (checkedRam) ar.serialize(
"ram", checkedRam->getUncheckedRam());
914 ar.serialize(
"memMapperRegs", memMapperRegs);
917 ar.serialize(
"bankRegsSubSlot3", bankRegsSubSlot3,
918 "selectedCard", selectedCard,
919 "sdCard0", *sdCard[0],
920 "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 read(size_t address)
uint8_t peek(size_t address) const
static DummyAY8910Periphery & instance()
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.
byte * getWriteCacheLine(word address) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
MegaFlashRomSCCPlusSD(const DeviceConfig &config)
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 setMode(Mode 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
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)