18static auto getMapperConfig(
const DeviceConfig& config)
20 MSXSCCPlusCart::MapperConfig result;
22 std::string_view subtype = config.getChildData(
"subtype",
"expanded");
23 if (subtype ==
"Snatcher") {
26 result.registerMask = 0b0000'1111;
27 result.registerOffset = 0;
28 }
else if (subtype ==
"SD-Snatcher") {
31 result.registerMask = 0b0000'1111;
32 result.registerOffset = 8;
33 }
else if (subtype ==
"mirrored") {
36 result.registerMask = 0b0000'0111;
37 result.registerOffset = 0;
38 }
else if (subtype ==
"Popolon") {
40 unsigned ramSize = config.getChildDataAsInt(
"size", 2048);
41 if (!std::has_single_bit(ramSize)) {
43 "Popolon type Sound Cartridge must have a power-of-2 RAM size: ",
46 if (ramSize < 128 || ramSize > 2048) {
48 "Popolon type Sound Cartridge must have a size between 128kB and 2048kB: ",
51 result.numBlocks = ramSize / 8;
52 result.registerMask = narrow<byte>(result.numBlocks - 1);
53 result.registerOffset = 0;
57 result.numBlocks = 16;
58 result.registerMask = 0b0000'1111;
59 result.registerOffset = 0;
67 , mapperConfig(getMapperConfig(config))
68 , ram(config, getName() +
" RAM",
"SCC+ RAM", size_t(mapperConfig.numBlocks) * 0x2000)
69 , scc(getName(), config, getCurrentTime(),
SCC::Mode::Compatible)
70 , romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
72 if (
const auto* fileElem = config.
findChild(
"filename")) {
74 const auto& filename = fileElem->getData();
110 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
111 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
112 return scc.
readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
121 if (((enable == EN_SCC) && (0x9800 <= addr) && (addr < 0xA000)) ||
122 ((enable == EN_SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
125 return scc.
peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
126 }
else if ((0x4000 <= addr) && (addr < 0xC000)) {
128 return internalMemoryBank[(addr >> 13) - 2][addr & 0x1FFF];
137 if (((enable == EN_SCC) && (0x9800 <= start) && (start < 0xA000)) ||
138 ((enable == EN_SCCPLUS) && (0xB800 <= start) && (start < 0xC000))) {
142 }
else if ((0x4000 <= start) && (start < 0xC000)) {
144 return &internalMemoryBank[(start >> 13) - 2][start & 0x1FFF];
154 if ((address < 0x4000) || (0xC000 <= address)) {
160 if ((address | 0x0001) == 0xBFFF) {
161 setModeRegister(value);
166 int region = (address >> 13) - 2;
167 if (isRamSegment[region]) {
174 if (isMapped[region]) {
175 internalMemoryBank[region][address & 0x1FFF] = value;
187 if ((address & 0x1800) == 0x1000) {
188 setMapper(region, value);
198 if ((0x9800 <= address) && (address < 0xA000)) {
199 scc.
writeMem(narrow_cast<uint8_t>(address & 0xFF), value, time);
203 if ((0xB800 <= address) && (address < 0xC000)) {
204 scc.
writeMem(narrow_cast<uint8_t>(address & 0xFF), value, time);
212 if ((0x4000 <= start) && (start < 0xC000)) {
216 if (
int region = (start >> 13) - 2;
217 isRamSegment[region] && isMapped[region]) {
218 return &internalMemoryBank[region][start & 0x1FFF];
226void MSXSCCPlusCart::setMapper(
int region,
byte value)
228 mapper[region] = value;
234 isMapped[region] =
true;
235 return &ram[0x2000 * value];
237 isMapped[region] =
false;
243 internalMemoryBank[region] = block;
247void MSXSCCPlusCart::setModeRegister(
byte value)
249 modeRegister = value;
252 if (modeRegister & 0x20) {
258 if (modeRegister & 0x10) {
259 isRamSegment[0] =
true;
260 isRamSegment[1] =
true;
261 isRamSegment[2] =
true;
262 isRamSegment[3] =
true;
264 isRamSegment[0] = (modeRegister & 0x01) == 0x01;
265 isRamSegment[1] = (modeRegister & 0x02) == 0x02;
266 isRamSegment[2] = (modeRegister & 0x24) == 0x24;
267 isRamSegment[3] =
false;
272void MSXSCCPlusCart::checkEnable()
274 if ((modeRegister & 0x20) && (mapper[3] & 0x80)) {
276 }
else if ((!(modeRegister & 0x20)) && ((mapper[2] & 0x3F) == 0x3F)) {
284template<
typename Archive>
288 ar.serialize_blob(
"ram", std::span{ram.
begin(), ram.
end()});
289 ar.serialize(
"scc", scc,
291 "mode", modeRegister);
293 if constexpr (Archive::IS_LOADER) {
296 setMapper(
int(i), m);
299 setModeRegister(modeRegister);
#define REGISTER_MSXDEVICE(CLASS, NAME)
const FileContext & getFileContext() const
const XMLElement * findChild(std::string_view name) const
std::string resolve(std::string_view filename) const
void read(std::span< uint8_t > buffer)
Read from file.
size_t getSize()
Returns the size of this file.
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
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
MSXSCCPlusCart(const DeviceConfig &config)
void reset(EmuTime::param time) override
This method is called on reset.
void serialize(Archive &ar, unsigned version)
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.
byte * getWriteCacheLine(word start) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
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:
uint16_t word
16 bit unsigned integer
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)