OXYGENHUB
◆ main openmsx / src / sound / SVIPSG.cc
3.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "SVIPSG.hh"
2
3
#include "JoystickPort.hh"
4
#include "LedStatus.hh"
5
#include "MSXCPUInterface.hh"
6
#include "MSXMotherBoard.hh"
7
#include "serialize.hh"
8
9
#include "stl.hh"
10
11
//        Slot 0    Slot 1    Slot 2    Slot 3
12
// FFFF +---------+---------+---------+---------+
13
//      | Bank 2  | Bank 12 | Bank 22 | Bank 32 | Page 3
14
//      |   RAM   |ROM Cart |   RAM   |   RAM   |
15
// 8000 |00000000 |01010000 |10100000 |11110000 | Page 2
16
//      +---------+---------+---------+---------+
17
// 7FFF | Bank 1  | Bank 11 | Bank 21 | Bank 31 | Page 1
18
//      |ROM BASIC|ROM Cart |   RAM   |   RAM   |
19
//      |00000000 |00000101 |00001010 |00001111 | Page 0
20
// 0000 +---------+---------+---------+---------+
21
//
22
// PSG Port A Input
23
// Bit Name   Description
24
//  0  FWD1   Joystick 1, Forward
25
//  1  BACK1  Joystick 1, Back
26
//  2  LEFT1  Joystick 1, Left
27
//  3  RIGHT1 Joystick 1, Right
28
//  4  FWD2   Joystick 2, Forward
29
//  5  BACK2  Joystick 2, Back
30
//  6  LEFT2  Joystick 2, Left
31
//  7  RIGHT2 Joystick 2, Right
32
//
33
// PSG Port B Output
34
// Bit Name    Description
35
// 0   /CART   Memory bank 11, ROM 0000-7FFF (cartridge /CCS1, /CCS2)
36
// 1   /BK21   Memory bank 21, RAM 0000-7FFF
37
// 2   /BK22   Memory bank 22, RAM 8000-FFFF
38
// 3   /BK31   Memory bank 31, RAM 0000-7FFF
39
// 4   /BK32   Memory bank 32, RAM 8000-7FFF
40
// 5   CAPS    Caps-Lock LED
41
// 6   /ROMEN0 Memory bank 12, ROM 8000-BFFF* (cartridge /CCS3)
42
// 7   /ROMEN1 Memory bank 12, ROM C000-FFFF* (cartridge /CCS4)
43
//
44
// * The /CART signal must be active for any effect,
45
//   then all banks of RAM are disabled.
46
47
namespace openmsx {
48
49
// MSXDevice
50
51
SVIPSG::SVIPSG(const DeviceConfig& config)
52
	: MSXDevice(config)
53
	, ports(generate_array<2>([&](auto i) { return &getMotherBoard().getJoystickPort(unsigned(i)); }))
54
	, ay8910("PSG", *this, config, getCurrentTime())
55
{
56
	reset(getCurrentTime());
57
}
58
59
SVIPSG::~SVIPSG()
60
{
61
	powerDown(EmuTime::dummy());
62
}
63
64
void SVIPSG::reset(EmuTime time)
65
{
66
	registerLatch = 0;
67
	ay8910.reset(time);
68
}
69
70
void SVIPSG::powerDown(EmuTime /*time*/)
71
{
72
	getMotherBoard().getLedStatus().setLed(LedStatus::CAPS, false);
73
}
74
75
byte SVIPSG::readIO(uint16_t /*port*/, EmuTime time)
76
{
77
	return ay8910.readRegister(registerLatch, time);
78
}
79
80
byte SVIPSG::peekIO(uint16_t /*port*/, EmuTime time) const
81
{
82
	return ay8910.peekRegister(registerLatch, time);
83
}
84
85
void SVIPSG::writeIO(uint16_t port, byte value, EmuTime time)
86
{
87
	switch (port & 0x07) {
88
	case 0:
89
		registerLatch = value & 0x0F;
90
		break;
91
	case 4:
92
		ay8910.writeRegister(registerLatch, value, time);
93
		break;
94
	}
95
}
96
97
// AY8910Periphery
98
99
byte SVIPSG::readA(EmuTime time)
100
{
101
	return byte(((ports[1]->read(time) & 0x0F) << 4) |
102
	            ((ports[0]->read(time) & 0x0F) << 0));
103
}
104
105
void SVIPSG::writeB(byte value, EmuTime /*time*/)
106
{
107
	getMotherBoard().getLedStatus().setLed(LedStatus::CAPS, (value & 0x20) != 0);
108
109
	// Default to bank 1 and 2
110
	byte psReg = 0;
111
	switch (~value & 0x14) {
112
	case 0x04: // bk22
113
		psReg = 0xa0;
114
		break;
115
	case 0x10: // bk32
116
		psReg = 0xf0;
117
		break;
118
	}
119
	switch (~value & 0x0B) {
120
	case 1: // bk12 (cart)?
121
		if ((~value & 0x80) || (~value & 0x40)) {
122
			psReg = 0x50;
123
		}
124
		// bk11 (cart)
125
		psReg |= 0x05;
126
		break;
127
	case 2: // bk21
128
		psReg |= 0x0a;
129
		break;
130
	case 8: // bk31
131
		psReg |= 0x0f;
132
		break;
133
	}
134
	getMotherBoard().getCPUInterface().setPrimarySlots(psReg);
135
136
	prev = value;
137
}
138
139
template<typename Archive>
140
void SVIPSG::serialize(Archive& ar, unsigned /*version*/)
141
{
142
	ar.template serializeBase<MSXDevice>(*this);
143
	ar.serialize("ay8910",        ay8910,
144
	             "registerLatch", registerLatch);
145
	byte portB = prev;
146
	ar.serialize("portB", portB);
147
	if constexpr (Archive::IS_LOADER) {
148
		writeB(portB, getCurrentTime());
149
	}
150
}
151
INSTANTIATE_SERIALIZE_METHODS(SVIPSG);
152
REGISTER_MSXDEVICE(SVIPSG, "SVI-328 PSG");
153
154
} // namespace openmsx