openMSX
SVIPSG.cc
Go to the documentation of this file.
1 #include "SVIPSG.hh"
2 #include "AY8910.hh"
3 #include "LedStatus.hh"
4 #include "MSXCPUInterface.hh"
5 #include "MSXMotherBoard.hh"
6 #include "JoystickPort.hh"
7 #include "serialize.hh"
8 #include <memory>
9 
10 // Slot 0 Slot 1 Slot 2 Slot 3
11 // FFFF +---------+---------+---------+---------+
12 // | Bank 2 | Bank 12 | Bank 22 | Bank 32 | Page 3
13 // | RAM |ROM Cart | RAM | RAM |
14 // 8000 |00000000 |01010000 |10100000 |11110000 | Page 2
15 // +---------+---------+---------+---------+
16 // 7FFF | Bank 1 | Bank 11 | Bank 21 | Bank 31 | Page 1
17 // |ROM BASIC|ROM Cart | RAM | RAM |
18 // |00000000 |00000101 |00001010 |00001111 | Page 0
19 // 0000 +---------+---------+---------+---------+
20 //
21 // PSG Port A Input
22 // Bit Name Description
23 // 0 FWD1 Joystick 1, Forward
24 // 1 BACK1 Joystick 1, Back
25 // 2 LEFT1 Joystick 1, Left
26 // 3 RIGHT1 Joystick 1, Right
27 // 4 FWD2 Joystick 2, Forward
28 // 5 BACK2 Joystick 2, Back
29 // 6 LEFT2 Joystick 2, Left
30 // 7 RIGHT2 Joystick 2, Right
31 //
32 // PSG Port B Output
33 // Bit Name Description
34 // 0 /CART Memory bank 11, ROM 0000-7FFF (cartridge /CCS1, /CCS2)
35 // 1 /BK21 Memory bank 21, RAM 0000-7FFF
36 // 2 /BK22 Memory bank 22, RAM 8000-FFFF
37 // 3 /BK31 Memory bank 31, RAM 0000-7FFF
38 // 4 /BK32 Memory bank 32, RAM 8000-7FFF
39 // 5 CAPS Caps-Lock diod
40 // 6 /ROMEN0 Memory bank 12, ROM 8000-BFFF* (cartridge /CCS3)
41 // 7 /ROMEN1 Memory bank 12, ROM C000-FFFF* (cartridge /CCS4)
42 //
43 // * The /CART signal must be active for any effect,
44 // then all banks of RAM are disabled.
45 
46 namespace openmsx {
47 
48 // MSXDevice
49 
51  : MSXDevice(config)
52  , prev(255)
53 {
54  ports[0] = &getMotherBoard().getJoystickPort(0);
55  ports[1] = &getMotherBoard().getJoystickPort(1);
56 
57  // must come after initialisation of ports
58  EmuTime::param time = getCurrentTime();
59  ay8910 = std::make_unique<AY8910>("PSG", *this, config, time);
60  reset(time);
61 }
62 
64 {
65  powerDown(EmuTime::dummy());
66 }
67 
68 void SVIPSG::reset(EmuTime::param time)
69 {
70  registerLatch = 0;
71  ay8910->reset(time);
72 }
73 
74 void SVIPSG::powerDown(EmuTime::param /*time*/)
75 {
77 }
78 
79 byte SVIPSG::readIO(word /*port*/, EmuTime::param time)
80 {
81  return ay8910->readRegister(registerLatch, time);
82 }
83 
84 byte SVIPSG::peekIO(word /*port*/, EmuTime::param time) const
85 {
86  return ay8910->peekRegister(registerLatch, time);
87 }
88 
89 void SVIPSG::writeIO(word port, byte value, EmuTime::param time)
90 {
91  switch (port & 0x07) {
92  case 0:
93  registerLatch = value & 0x0F;
94  break;
95  case 4:
96  ay8910->writeRegister(registerLatch, value, time);
97  break;
98  }
99 }
100 
101 // AY8910Periphery
102 
103 byte SVIPSG::readA(EmuTime::param time)
104 {
105  return ((ports[1]->read(time) & 0x0F) << 4) |
106  ((ports[0]->read(time) & 0x0F) << 0);
107 }
108 
109 void SVIPSG::writeB(byte value, EmuTime::param /*time*/)
110 {
111  getMotherBoard().getLedStatus().setLed(LedStatus::CAPS, (value & 0x20) != 0);
112 
113  // Default to bank 1 and 2
114  byte psreg = 0;
115  switch (~value & 0x14) {
116  case 0x04: // bk22
117  psreg = 0xa0;
118  break;
119  case 0x10: // bk32
120  psreg = 0xf0;
121  break;
122  }
123  switch (~value & 0x0B) {
124  case 1: // bk12 (cart)?
125  if ((~value & 0x80) || (~value & 0x40)) {
126  psreg = 0x50;
127  }
128  // bk11 (cart)
129  psreg |= 0x05;
130  break;
131  case 2: // bk21
132  psreg |= 0x0a;
133  break;
134  case 8: // bk31
135  psreg |= 0x0f;
136  break;
137  }
139 
140  prev = value;
141 }
142 
143 template<typename Archive>
144 void SVIPSG::serialize(Archive& ar, unsigned /*version*/)
145 {
146  ar.template serializeBase<MSXDevice>(*this);
147  ar.serialize("ay8910", *ay8910,
148  "registerLatch", registerLatch);
149  byte portB = prev;
150  ar.serialize("portB", portB);
151  if (ar.isLoader()) {
152  writeB(portB, getCurrentTime());
153  }
154 }
156 REGISTER_MSXDEVICE(SVIPSG, "SVI-328 PSG");
157 
158 } // namespace openmsx
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SVIPSG.cc:68
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: SVIPSG.cc:79
MSXCPUInterface & getCPUInterface()
void powerDown(EmuTime::param time) override
This method is called when MSX is powered down.
Definition: SVIPSG.cc:74
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void setPrimarySlots(byte value)
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
virtual byte read(EmuTime::param time)=0
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:129
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: SVIPSG.cc:89
void serialize(Archive &ar, unsigned version)
Definition: SVIPSG.cc:144
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
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: SVIPSG.cc:84
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:73
JoystickPortIf & getJoystickPort(unsigned port)
SVIPSG(const DeviceConfig &config)
Definition: SVIPSG.cc:50
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
~SVIPSG() override
Definition: SVIPSG.cc:63
void setLed(Led led, bool status)
Definition: LedStatus.cc:39