11static constexpr byte REG_BANK_SEGMENT_MASK = (1 << 5) - 1;
14static constexpr byte DISABLE = 1 << 7;
15static constexpr byte REG_FRAME_SEGMENT_MASK = (1 << 3) - 1;
18static constexpr byte ENA_S0 = 1 << 5;
19static constexpr byte ENA_FW = 1 << 4;
20static constexpr byte ENA_C4 = 1 << 1;
21static constexpr byte ENA_C0 = 1 << 0;
28 [this](bool mode0,
std::span<const uint8_t> rom,
std::span<const uint8_t> ram,
29 std::span<
YMF278::Block128, 32> memPtrs) {
30 setupMemPtrs(mode0, rom, ram, memPtrs);
32 , sram(config, getName() +
" RAM",
"DalSoRi R2 RAM", 0x8000)
33 , flash(getName() +
" flash", AmdFlashChip::SST39SF010, {}, config,
"flash")
34 , dipSwitchBDIS(getCommandController(),
35 getName() +
" DIP switch BDIS",
36 "Controls the BDIS DIP switch position. ON = Disable BIOS (flash memory access)",
false)
37 , dipSwitchMCFG(getCommandController(),
38 getName() +
" DIP switch MCFG",
39 "Controls the MCFG DIP switch position. ON = Enable sample RAM instead of sample ROM on reset.",
false)
40 , dipSwitchIO_C0(getCommandController(),
41 getName() +
" DIP switch IO/C0",
42 "Controls the IO/C0 DIP switch position. ON = Enable I/O addres C0H~C3H on reset. This is the MSX-AUDIO compatible I/O port range.",
true)
43 , dipSwitchIO_C4(getCommandController(),
44 getName() +
" DIP switch IO/C4",
45 "Controls the IO/C4 DIP switch position. ON = Enable I/O addres C4H~C7H on reset. This is the MoonSound compatible I/O port range",
true)
46 , biosDisable(dipSwitchBDIS.getBoolean())
48 dipSwitchBDIS.attach(*
this);
49 powerUp(getCurrentTime());
55 dipSwitchBDIS.
detach(*
this);
58void DalSoRiR2::setupMemPtrs(
60 std::span<const uint8_t> rom,
61 std::span<const uint8_t> ram,
62 std::span<YMF278::Block128, 32> memPtrs)
71 bool enableRam = regCfg & ENA_S0;
72 auto mem0 = enableRam ? std::span<const uint8_t>{ram} : std::span<const uint8_t>{rom};
73 for (
auto i :
xrange(16)) {
74 memPtrs[i] = subspan<k128>(mem0, i * k128);
77 if (mode0) [[likely]] {
79 for (
auto i :
xrange(16, 32)) {
80 memPtrs[i] = subspan<k128>(ram, i * k128);
88 for (
auto i :
xrange(16, 32)) {
108 setRegCfg((dipSwitchMCFG. getBoolean() ? ENA_S0 : 0) |
113void DalSoRiR2::setRegCfg(
byte value)
115 auto registerHelper = [
this](
bool enable,
byte base) {
122 if ((value ^ regCfg) & ENA_C0) {
123 registerHelper((value & ENA_C0) != 0, 0xC0);
125 if ((value ^ regCfg) & ENA_C4) {
126 registerHelper((value & ENA_C4) != 0, 0xC4);
129 if ((value ^ regCfg) & ENA_FW) {
140 return ymf278b.
readIO(port, time);
145 return ymf278b.
peekIO(port, time);
150 ymf278b.
writeIO(port, value, time);
153byte* DalSoRiR2::getSramAddr(
word addr)
155 auto get = [&](
byte frame) {
156 return &sram[(addr & 0x0FFF) + (frame & REG_FRAME_SEGMENT_MASK) * 0x1000];
159 if ((0x3000 <= addr) && (addr < 0x4000)) {
162 }
else if ((0x7000 <= addr) && (addr < 0x8000) && ((regFrame[0] & DISABLE) == 0)) {
164 return get(regFrame[0]);
165 }
else if ((0xB000 <= addr) && (addr < 0xC000) && ((regFrame[1] & DISABLE) == 0)) {
167 return get(regFrame[1]);
173unsigned DalSoRiR2::getFlashAddr(
word addr)
const
175 auto page = addr >> 14;
176 auto bank = regBank[page] & REG_BANK_SEGMENT_MASK;
177 auto offset = addr & 0x3FFF;
178 return 0x4000 * bank + offset;
183 if (
const auto* r = getSramAddr(addr)) {
185 }
else if (!biosDisable) {
186 return flash.
read(getFlashAddr(addr));
193 if (
const auto* r =
const_cast<DalSoRiR2*
>(
this)->getSramAddr(addr)) {
195 }
else if (!biosDisable) {
196 return flash.
peek(getFlashAddr(addr));
203 if (
const auto* r =
const_cast<DalSoRiR2*
>(
this)->getSramAddr(start)) {
205 }
else if (!biosDisable) {
213 if (
auto* r = getSramAddr(addr)) {
215 }
else if ((0x6000 <= addr) && (addr < 0x6400)) {
216 auto bank = (addr >> 8) & 3;
217 regBank[bank] = value;
219 }
else if ((0x6500 <= addr) && (addr < 0x6700)) {
220 auto frame = (addr >> 9) & 1;
221 regFrame[frame] = value;
223 }
else if ((0x6700 <= addr) && (addr < 0x6800)) {
225 }
else if (!biosDisable && ((regCfg & ENA_FW) != 0)) {
226 flash.
write(getFlashAddr(addr), value);
232 if (
auto* r = getSramAddr(start)) {
242 assert(&
setting == &dipSwitchBDIS);
243 auto newBiosDisable = dipSwitchBDIS.getBoolean();
244 if (biosDisable != newBiosDisable) {
245 biosDisable = newBiosDisable;
246 invalidateDeviceRWCache();
251template<
typename Archive>
254 ar.template serializeBase<MSXDevice>(*
this);
255 auto backupRegCfg = regCfg;
256 ar.serialize(
"ymf278b", ymf278b,
259 "regFrame", regFrame,
260 "regCfg", backupRegCfg);
261 if constexpr (Archive::IS_LOADER) {
262 setRegCfg(backupRegCfg);
#define REGISTER_MSXDEVICE(CLASS, NAME)
void write(size_t address, uint8_t value)
const uint8_t * getReadCacheLine(size_t address) const
uint8_t read(size_t address)
uint8_t peek(size_t address) const
bool getBoolean() const noexcept
DalSoRiR2(const DeviceConfig &config)
void writeMem(word addr, 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 peekMem(word addr, EmuTime::param time) const override
Read a byte from a given memory location.
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
byte readMem(word addr, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
void reset(EmuTime::param time) override
This method is called on reset.
byte * getWriteCacheLine(word start) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
void serialize(Archive &ar, unsigned version)
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
void unregister_IO_InOut_range(byte port, unsigned num, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
static std::array< byte, 0x10000 > unmappedRead
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
MSXCPUInterface & getCPUInterface() const
void detach(Observer< T > &observer)
void setupMemoryPointers()
void writeIO(word port, byte value, EmuTime::param time)
void powerUp(EmuTime::param time)
byte readIO(word port, EmuTime::param time)
byte peekIO(word port, EmuTime::param time) const
void reset(EmuTime::param time)
static constexpr auto k128
optional_fixed_span< const uint8_t, k128 > Block128
This file implemented 3 utility functions:
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)