openMSX
MSXPSG.cc
Go to the documentation of this file.
1 #include "MSXPSG.hh"
2 #include "AY8910.hh"
3 #include "LedStatus.hh"
4 #include "CassettePort.hh"
5 #include "MSXMotherBoard.hh"
6 #include "JoystickPort.hh"
7 #include "RenShaTurbo.hh"
8 #include "StringOp.hh"
9 #include "serialize.hh"
10 #include "checked_cast.hh"
11 #include <memory>
12 
13 namespace openmsx {
14 
15 static byte getKeyboardLayout(const MSXPSG& psg)
16 {
17  // As many (mostly European) configs do not specify the layout
18  // in the PSG config, assume 50on for these cases.
19  auto value = psg.getDeviceConfig().getChildData("keyboardlayout", "50on");
20  StringOp::casecmp cmp; // case-insensitive
21  if (cmp(value, "50on")) {
22  return 0x00;
23  } else if (cmp(value, "jis")) {
24  return 0x40;
25  }
26  throw MSXException(
27  "Illegal keyboard layout configuration in '", psg.getName(),
28  "' device configuration: '", value,
29  "', expected 'jis' or '50on'.");
30 }
31 
32 // MSXDevice
34  : MSXDevice(config)
35  , cassette(getMotherBoard().getCassettePort())
36  , renShaTurbo(getMotherBoard().getRenShaTurbo())
37  , selectedPort(0)
38  , prev(255)
39  , keyLayout(getKeyboardLayout(*this))
40  , addressMask(config.getChildDataAsBool("mirrored_registers", true) ? 0x0f : 0xff)
41 {
42  ports[0] = &getMotherBoard().getJoystickPort(0);
43  ports[1] = &getMotherBoard().getJoystickPort(1);
44  ay8910 = std::make_unique<AY8910>("PSG", *this, config, getCurrentTime());
45 
47 }
48 
50 {
51  powerDown(EmuTime::dummy());
52 }
53 
54 void MSXPSG::reset(EmuTime::param time)
55 {
56  registerLatch = 0;
57  ay8910->reset(time);
58 }
59 
60 void MSXPSG::powerDown(EmuTime::param /*time*/)
61 {
63 }
64 
65 byte MSXPSG::readIO(word /*port*/, EmuTime::param time)
66 {
67  return ay8910->readRegister(registerLatch, time);
68 }
69 
70 byte MSXPSG::peekIO(word /*port*/, EmuTime::param time) const
71 {
72  return ay8910->peekRegister(registerLatch, time);
73 }
74 
75 void MSXPSG::writeIO(word port, byte value, EmuTime::param time)
76 {
77  switch (port & 0x03) {
78  case 0:
79  registerLatch = value & addressMask;
80  break;
81  case 1:
82  ay8910->writeRegister(registerLatch, value, time);
83  break;
84  }
85 }
86 
87 
88 // AY8910Periphery
89 byte MSXPSG::readA(EmuTime::param time)
90 {
91  byte joystick = ports[selectedPort]->read(time) |
92  ((renShaTurbo.getSignal(time)) ? 0x10 : 0x00);
93 
94  // pin 6,7 input is ANDed with pin 6,7 output
95  byte pin67 = prev << (4 - 2 * selectedPort);
96  joystick &= (pin67| 0xCF);
97 
98  byte cassetteInput = cassette.cassetteIn(time) ? 0x80 : 0x00;
99  return joystick | keyLayout | cassetteInput;
100 }
101 
102 void MSXPSG::writeB(byte value, EmuTime::param time)
103 {
104  byte val0 = (value & 0x03) | ((value & 0x10) >> 2);
105  byte val1 = ((value & 0x0C) >> 2) | ((value & 0x20) >> 3);
106  ports[0]->write(val0, time);
107  ports[1]->write(val1, time);
108  selectedPort = (value & 0x40) >> 6;
109 
110  if ((prev ^ value) & 0x80) {
111  getLedStatus().setLed(LedStatus::KANA, !(value & 0x80));
112  }
113  prev = value;
114 }
115 
116 // version 1: initial version
117 // version 2: joystickportA/B moved from here to MSXMotherBoard
118 template<typename Archive>
119 void MSXPSG::serialize(Archive& ar, unsigned version)
120 {
121  ar.template serializeBase<MSXDevice>(*this);
122  ar.serialize("ay8910", *ay8910);
123  if (ar.versionBelow(version, 2)) {
124  assert(ar.isLoader());
125  // in older versions there were always 2 real joystick ports
126  ar.serialize("joystickportA", *checked_cast<JoystickPort*>(ports[0]),
127  "joystickportB", *checked_cast<JoystickPort*>(ports[1]));
128  }
129  ar.serialize("registerLatch", registerLatch);
130  byte portB = prev;
131  ar.serialize("portB", portB);
132  if (ar.isLoader()) {
133  writeB(portB, getCurrentTime());
134  }
135  // selectedPort is derived from portB
136 }
139 
140 } // namespace openmsx
virtual bool cassetteIn(EmuTime::param time)=0
Reads one bit from the cassette port.
virtual void write(byte value, EmuTime::param time)=0
virtual byte read(EmuTime::param time)=0
void setLed(Led led, bool status)
Definition: LedStatus.cc:40
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:76
LedStatus & getLedStatus() const
Definition: MSXDevice.cc:160
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:132
JoystickPortIf & getJoystickPort(unsigned port)
MSXPSG(const DeviceConfig &config)
Definition: MSXPSG.cc:33
void powerDown(EmuTime::param time) override
This method is called when MSX is powered down.
Definition: MSXPSG.cc:60
~MSXPSG() override
Definition: MSXPSG.cc:49
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.
Definition: MSXPSG.cc:75
void serialize(Archive &ar, unsigned version)
Definition: MSXPSG.cc:119
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MSXPSG.cc:54
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: MSXPSG.cc:65
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: MSXPSG.cc:70
bool getSignal(EmuTime::param time)
Get the output signal in negative logic.
Definition: RenShaTurbo.cc:27
This file implemented 3 utility functions:
Definition: Autofire.cc:5
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983