MSXDeviceSwitch.cc 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. namespace openmsx {
  9. MSXDeviceSwitch::MSXDeviceSwitch(const DeviceConfig& config)
  10. : MSXDevice(config)
  11. {
  12. ranges::fill(devices, nullptr);
  13. count = 0;
  14. selected = 0;
  15. }
  16. MSXDeviceSwitch::~MSXDeviceSwitch()
  17. {
  18. // all devices must be unregistered
  19. assert(ranges::all_of(devices, [](auto* dev) { return dev == nullptr; }));
  20. assert(count == 0);
  21. }
  22. void MSXDeviceSwitch::registerDevice(byte id, MSXSwitchedDevice* device)
  23. {
  24. if (devices[id]) {
  25. // TODO implement multiplexing
  26. throw MSXException(
  27. "Already have a switched device with id ", int(id));
  28. }
  29. devices[id] = device;
  30. if (count == 0) {
  31. for (byte port = 0x40; port < 0x50; ++port) {
  32. getCPUInterface().register_IO_In (port, this);
  33. getCPUInterface().register_IO_Out(port, this);
  34. }
  35. }
  36. ++count;
  37. }
  38. void MSXDeviceSwitch::unregisterDevice(byte id)
  39. {
  40. --count;
  41. if (count == 0) {
  42. for (byte port = 0x40; port < 0x50; ++port) {
  43. getCPUInterface().unregister_IO_Out(port, this);
  44. getCPUInterface().unregister_IO_In (port, this);
  45. }
  46. }
  47. assert(devices[id]);
  48. devices[id] = nullptr;
  49. }
  50. void MSXDeviceSwitch::reset(EmuTime::param /*time*/)
  51. {
  52. selected = 0;
  53. }
  54. byte MSXDeviceSwitch::readIO(word port, EmuTime::param time)
  55. {
  56. if (devices[selected]) {
  57. return devices[selected]->readSwitchedIO(port, time);
  58. } else {
  59. return 0xFF;
  60. }
  61. }
  62. byte MSXDeviceSwitch::peekIO(word port, EmuTime::param time) const
  63. {
  64. if (devices[selected]) {
  65. return devices[selected]->peekSwitchedIO(port, time);
  66. } else {
  67. return 0xFF;
  68. }
  69. }
  70. void MSXDeviceSwitch::writeIO(word port, byte value, EmuTime::param time)
  71. {
  72. if ((port & 0x0F) == 0x00) {
  73. selected = value;
  74. } else if (devices[selected]) {
  75. devices[selected]->writeSwitchedIO(port, value, time);
  76. } else {
  77. // ignore
  78. }
  79. }
  80. template<typename Archive>
  81. void MSXDeviceSwitch::serialize(Archive& ar, unsigned /*version*/)
  82. {
  83. ar.template serializeBase<MSXDevice>(*this);
  84. ar.serialize("selected", selected);
  85. }
  86. INSTANTIATE_SERIALIZE_METHODS(MSXDeviceSwitch);
  87. } // namespace openmsx