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)
212 for (
auto& regs : bankRegs) {
228MegaFlashRomSCCPlus::SCCEnable MegaFlashRomSCCPlus::getSCCEnable()
const
230 if ((sccMode & 0x20) && (sccBanks[3] & 0x80)) {
232 }
else if ((!(sccMode & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
239unsigned MegaFlashRomSCCPlus::getSubslot(
unsigned addr)
const
241 return (configReg & 0x10)
242 ? (subslotReg >> (2 * (addr >> 14))) & 0x03
246unsigned MegaFlashRomSCCPlus::getFlashAddr(
unsigned addr)
const
248 unsigned subslot = getSubslot(addr);
250 if ((configReg & 0xC0) == 0x40) {
251 unsigned bank = bankRegs[subslot][addr >> 14] + offsetReg;
252 return (bank * 0x4000) + (addr & 0x3FFF);
254 unsigned page = (addr >> 13) - 2;
261 unsigned bank = bankRegs[subslot][page] + offsetReg;
262 return (bank * 0x2000) + (addr & 0x1FFF);
265 return ((0x40000 * subslot) + tmp) & 0xFFFFF;
270 if ((configReg & 0x10) && (addr == 0xFFFF)) {
272 return subslotReg ^ 0xFF;
275 if ((configReg & 0xE0) == 0x00) {
276 SCCEnable enable = getSCCEnable();
277 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
278 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
279 return scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
283 if (((configReg & 0xC0) == 0x40) ||
284 ((0x4000 <= addr) && (addr < 0xC000))) {
286 unsigned flashAddr = getFlashAddr(addr);
287 assert(flashAddr !=
unsigned(-1));
288 return flash.
peek(flashAddr);
297 if ((configReg & 0x10) && (addr == 0xFFFF)) {
299 return subslotReg ^ 0xFF;
302 if ((configReg & 0xE0) == 0x00) {
303 SCCEnable enable = getSCCEnable();
304 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
305 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
306 return scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
310 if (((configReg & 0xC0) == 0x40) ||
311 ((0x4000 <= addr) && (addr < 0xC000))) {
313 unsigned flashAddr = getFlashAddr(addr);
314 assert(flashAddr !=
unsigned(-1));
315 return flash.
read(flashAddr);
324 if ((configReg & 0x10) &&
330 if ((configReg & 0xE0) == 0x00) {
331 SCCEnable enable = getSCCEnable();
332 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
333 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
338 if (((configReg & 0xC0) == 0x40) ||
339 ((0x4000 <= addr) && (addr < 0xC000))) {
341 unsigned flashAddr = getFlashAddr(addr);
342 assert(flashAddr !=
unsigned(-1));
353 unsigned flashAddr = getFlashAddr(addr);
359 if ((configReg & 0x10) && (addr == 0xFFFF)) {
361 byte diff = value ^ subslotReg;
363 for (
auto i :
xrange(4)) {
364 if (diff & (3 << (2 * i))) {
370 if (((configReg & 0x04) == 0x00) && ((addr & 0xFFFE) == 0x7FFE)) {
376 if ((configReg & 0xE0) == 0x00) {
378 if ((addr & 0xFFFE) == 0xBFFE) {
385 SCCEnable enable = getSCCEnable();
386 bool isRamSegment2 = ((sccMode & 0x24) == 0x24) ||
387 ((sccMode & 0x10) == 0x10);
388 bool isRamSegment3 = ((sccMode & 0x10) == 0x10);
389 if (((enable == EN_SCC) && !isRamSegment2 &&
390 (0x9800 <= addr) && (addr < 0xA000)) ||
391 ((enable == EN_SCCPLUS) && !isRamSegment3 &&
392 (0xB800 <= addr) && (addr < 0xC000))) {
393 scc.
writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
398 unsigned subslot = getSubslot(addr);
399 unsigned page8kB = (addr >> 13) - 2;
400 if (((configReg & 0x02) == 0x00) && (page8kB < 4)) {
402 switch (configReg & 0xE0) {
405 if ((addr & 0x1800) == 0x1000) {
409 sccBanks[page8kB] = value;
410 if ((value & 0x80) && (page8kB == 0)) {
411 offsetReg = value & 0x7F;
416 byte mask = (configReg & 0x01) ? 0x3F : 0x7F;
417 bankRegs[subslot][page8kB] = value & mask;
424 if (((configReg & 0x08) == 0x08) && (addr < 0x6000)) {
433 if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000)))
break;
434 byte mask = (configReg & 0x01) ? 0x1F : 0x7F;
435 bankRegs[subslot][page8kB] = value & mask;
442 bankRegs[subslot][page8kB] = value;
448 if ((0x6000 <= addr) && (addr < 0x8000)) {
449 byte bank = (addr >> 11) & 0x03;
450 bankRegs[subslot][bank] = value;
463 if ((0x6000 <= addr) && (addr < 0x6800)) {
464 bankRegs[subslot][0] = narrow_cast<uint8_t>(2 * value + 0);
465 bankRegs[subslot][1] = narrow_cast<uint8_t>(2 * value + 1);
468 if ((0x7000 <= addr) && (addr < 0x7800)) {
469 bankRegs[subslot][2] = narrow_cast<uint8_t>(2 * value + 0);
470 bankRegs[subslot][3] = narrow_cast<uint8_t>(2 * value + 1);
478 if (((configReg & 0xC0) == 0x40) ||
479 ((0x4000 <= addr) && (addr < 0xC000))) {
480 assert(flashAddr !=
unsigned(-1));
481 return flash.
write(flashAddr, value);
493 if ((port & 0xFF) == 0x10) {
494 psgLatch = value & 0x0F;
496 assert((port & 0xFF) == 0x11);
502template<
typename Archive>
506 ar.template serializeBase<MSXDevice>(*
this);
508 ar.serialize(
"scc", scc,
512 "configReg", configReg,
513 "offsetReg", offsetReg,
514 "subslotReg", subslotReg,
515 "bankRegs", bankRegs,
516 "psgLatch", psgLatch,
518 "sccBanks", sccBanks);
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:
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
AmdFlash::SectorInfo Info
uint16_t word
16 bit unsigned integer
constexpr void fill(ForwardRange &&range, const T &value)
constexpr void iota(ForwardIt first, ForwardIt last, T value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)