169static constexpr auto sectorInfo = [] {
171 using Info = AmdFlash::SectorInfo;
172 std::array<Info, 1 + 2 + 1 + 15> result = {};
173 std::fill(result.begin() + 0, result.begin() + 1,
Info{16 * 1024, false});
174 std::fill(result.begin() + 1, result.begin() + 3,
Info{ 8 * 1024, false});
175 std::fill(result.begin() + 3, result.begin() + 4,
Info{32 * 1024, false});
176 std::fill(result.begin() + 4, result.end(),
Info{64 * 1024, false});
183 , scc(
"MFR SCC+ SCC-I", config, getCurrentTime(),
SCC::SCC_Compatible)
186 , flash(rom, sectorInfo, 0x205B,
187 AmdFlash::Addressing::BITS_11, config)
190 for (
auto port : {0x10, 0x11}) {
197 for (
auto port : {0x10, 0x11}) {
213 for (
auto& regs : bankRegs) {
229MegaFlashRomSCCPlus::SCCEnable MegaFlashRomSCCPlus::getSCCEnable()
const
231 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
233 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
240unsigned MegaFlashRomSCCPlus::getSubslot(
unsigned addr)
const
242 return (configReg & 0x10)
243 ? (subslotReg >> (2 * (addr >> 14))) & 0x03
247unsigned MegaFlashRomSCCPlus::getFlashAddr(
unsigned addr)
const
249 unsigned subslot = getSubslot(addr);
251 if ((configReg & 0xC0) == 0x40) {
252 unsigned bank = bankRegs[subslot][addr >> 14] + offsetReg;
253 return (bank * 0x4000) + (addr & 0x3FFF);
255 unsigned page = (addr >> 13) - 2;
262 unsigned bank = bankRegs[subslot][page] + offsetReg;
263 return (bank * 0x2000) + (addr & 0x1FFF);
266 return ((0x40000 * subslot) + tmp) & 0xFFFFF;
271 if ((configReg & 0x10) && (addr == 0xFFFF)) {
273 return subslotReg ^ 0xFF;
276 if ((configReg & 0xE0) == 0x00) {
277 SCCEnable enable = getSCCEnable();
278 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
279 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
280 return scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
284 if (((configReg & 0xC0) == 0x40) ||
285 ((0x4000 <= addr) && (addr < 0xC000))) {
287 unsigned flashAddr = getFlashAddr(addr);
288 assert(flashAddr !=
unsigned(-1));
289 return flash.
peek(flashAddr);
298 if ((configReg & 0x10) && (addr == 0xFFFF)) {
300 return subslotReg ^ 0xFF;
303 if ((configReg & 0xE0) == 0x00) {
304 SCCEnable enable = getSCCEnable();
305 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
306 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
307 return scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
311 if (((configReg & 0xC0) == 0x40) ||
312 ((0x4000 <= addr) && (addr < 0xC000))) {
314 unsigned flashAddr = getFlashAddr(addr);
315 assert(flashAddr !=
unsigned(-1));
316 return flash.
read(flashAddr);
325 if ((configReg & 0x10) &&
331 if ((configReg & 0xE0) == 0x00) {
332 SCCEnable enable = getSCCEnable();
333 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
334 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
339 if (((configReg & 0xC0) == 0x40) ||
340 ((0x4000 <= addr) && (addr < 0xC000))) {
342 unsigned flashAddr = getFlashAddr(addr);
343 assert(flashAddr !=
unsigned(-1));
354 unsigned flashAddr = getFlashAddr(addr);
360 if ((configReg & 0x10) && (addr == 0xFFFF)) {
362 byte diff = value ^ subslotReg;
364 for (
auto i :
xrange(4)) {
365 if (diff & (3 << (2 * i))) {
371 if (((configReg & 0x04) == 0x00) && ((addr & 0xFFFE) == 0x7FFE)) {
377 if ((configReg & 0xE0) == 0x00) {
379 if ((addr & 0xFFFE) == 0xBFFE) {
386 SCCEnable enable = getSCCEnable();
387 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
388 ((sccMode & 0x10) == 0x10);
389 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
390 if (((enable == EN_SCC) && !isRamSegment2 &&
391 (0x9800 <= addr) && (addr < 0xA000)) ||
392 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
393 (0xB800 <= addr) && (addr < 0xC000))) {
394 scc.
writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
399 unsigned subslot = getSubslot(addr);
400 unsigned page8kB = (addr >> 13) - 2;
401 if (((configReg & 0x02) == 0x00) && (page8kB < 4)) {
403 switch (configReg & 0xE0) {
406 if ((addr & 0x1800) == 0x1000) {
410 sccBanks[page8kB] = value;
411 if ((value & 0x80) && (page8kB == 0)) {
412 offsetReg = value & 0x7F;
417 byte mask = (configReg & 0x01) ? 0x3F : 0x7F;
418 bankRegs[subslot][page8kB] = value & mask;
425 if (((configReg & 0x08) == 0x08) && (addr < 0x6000)) {
434 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
435 byte mask = (configReg & 0x01) ? 0x1F : 0x7F;
436 bankRegs[subslot][page8kB] = value & mask;
443 bankRegs[subslot][page8kB] = value;
449 if ((0x6000 <= addr) && (addr < 0x8000)) {
450 byte bank = (addr >> 11) & 0x03;
451 bankRegs[subslot][bank] = value;
464 if ((0x6000 <= addr) && (addr < 0x6800)) {
465 bankRegs[subslot][0] = narrow_cast<uint8_t>(2 * value + 0);
466 bankRegs[subslot][1] = narrow_cast<uint8_t>(2 * value + 1);
469 if ((0x7000 <= addr) && (addr < 0x7800)) {
470 bankRegs[subslot][2] = narrow_cast<uint8_t>(2 * value + 0);
471 bankRegs[subslot][3] = narrow_cast<uint8_t>(2 * value + 1);
479 if (((configReg & 0xC0) == 0x40) ||
480 ((0x4000 <= addr) && (addr < 0xC000))) {
481 assert(flashAddr !=
unsigned(-1));
482 return flash.
write(flashAddr, value);
494 if ((port & 0xFF) == 0x10) {
495 psgLatch = value & 0x0F;
497 assert((port & 0xFF) == 0x11);
503template<
typename Archive>
507 ar.template serializeBase<MSXDevice>(*
this);
509 ar.serialize(
"scc", scc,
513 "configReg", configReg,
514 "offsetReg", offsetReg,
515 "subslotReg", subslotReg,
516 "bankRegs", bankRegs,
517 "psgLatch", psgLatch,
519 "sccBanks", sccBanks);
#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
uint8_t peek(size_t address) const
uint8_t read(size_t address) const
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void unregister_IO_Out(byte port, MSXDevice *device)
void invalidateDeviceRCache()
static std::array< byte, 0x10000 > unmappedRead
EmuTime::param getCurrentTime() const
MSXCPUInterface & getCPUInterface() const
void reset(EmuTime::param time) override
This method is called on reset.
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
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.
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
MegaFlashRomSCCPlus(const DeviceConfig &config, Rom &&rom)
void serialize(Archive &ar, unsigned version)
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 peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
~MegaFlashRomSCCPlus() 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)
This file implemented 3 utility functions:
AmdFlash::SectorInfo Info
uint16_t word
16 bit unsigned integer
constexpr void iota(ForwardIt first, ForwardIt last, T value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)