openMSX
MSXDeviceSwitch.cc
Go to the documentation of this file.
1 #include "MSXDeviceSwitch.hh"
2 #include "MSXSwitchedDevice.hh"
3 #include "MSXCPUInterface.hh"
4 #include "MSXException.hh"
5 #include "ranges.hh"
6 #include "serialize.hh"
7 #include <cassert>
8 
9 namespace openmsx {
10 
12  : MSXDevice(config)
13 {
14  ranges::fill(devices, nullptr);
15  count = 0;
16  selected = 0;
17 }
18 
20 {
21  // all devices must be unregistered
22  assert(ranges::all_of(devices, [](auto* dev) { return dev == nullptr; }));
23  assert(count == 0);
24 }
25 
27 {
28  if (devices[id]) {
29  // TODO implement multiplexing
30  throw MSXException(
31  "Already have a switched device with id ", int(id));
32  }
33  devices[id] = device;
34  if (count == 0) {
35  for (byte port = 0x40; port < 0x50; ++port) {
36  getCPUInterface().register_IO_In (port, this);
37  getCPUInterface().register_IO_Out(port, this);
38  }
39  }
40  ++count;
41 }
42 
44 {
45  --count;
46  if (count == 0) {
47  for (byte port = 0x40; port < 0x50; ++port) {
48  getCPUInterface().unregister_IO_Out(port, this);
49  getCPUInterface().unregister_IO_In (port, this);
50  }
51  }
52  assert(devices[id]);
53  devices[id] = nullptr;
54 }
55 
56 void MSXDeviceSwitch::reset(EmuTime::param /*time*/)
57 {
58  selected = 0;
59 }
60 
61 byte MSXDeviceSwitch::readIO(word port, EmuTime::param time)
62 {
63  if (devices[selected]) {
64  return devices[selected]->readSwitchedIO(port, time);
65  } else {
66  return 0xFF;
67  }
68 }
69 
70 byte MSXDeviceSwitch::peekIO(word port, EmuTime::param time) const
71 {
72  if (devices[selected]) {
73  return devices[selected]->peekSwitchedIO(port, time);
74  } else {
75  return 0xFF;
76  }
77 }
78 
79 void MSXDeviceSwitch::writeIO(word port, byte value, EmuTime::param time)
80 {
81  if ((port & 0x0F) == 0x00) {
82  selected = value;
83  } else if (devices[selected]) {
84  devices[selected]->writeSwitchedIO(port, value, time);
85  } else {
86  // ignore
87  }
88 }
89 
90 
91 template<typename Archive>
92 void MSXDeviceSwitch::serialize(Archive& ar, unsigned /*version*/)
93 {
94  ar.template serializeBase<MSXDevice>(*this);
95  ar.serialize("selected", selected);
96 }
98 
99 } // namespace openmsx
virtual byte peekSwitchedIO(word port, EmuTime::param time) const =0
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void registerDevice(byte id, MSXSwitchedDevice *device)
void unregister_IO_In(byte port, MSXDevice *device)
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:191
void unregisterDevice(byte id)
void reset(EmuTime::param time) override
This method is called on reset.
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
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.
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
MSXDeviceSwitch(const DeviceConfig &config)
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
void unregister_IO_Out(byte port, MSXDevice *device)
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
virtual byte readSwitchedIO(word port, EmuTime::param time)=0
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
bool all_of(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:119
void serialize(Archive &ar, unsigned version)
MSXCPUInterface & getCPUInterface() const
Definition: MSXDevice.cc:141
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
virtual void writeSwitchedIO(word port, byte value, EmuTime::param time)=0