OXYGENHUB
◆ main openmsx / src / memory / ColecoSuperGameModule.cc
5.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "ColecoSuperGameModule.hh"
2
3
#include "DummyAY8910Periphery.hh"
4
#include "MSXCPUInterface.hh"
5
#include "MSXException.hh"
6
#include "serialize.hh"
7
8
namespace openmsx {
9
10
// Disabling the SGM RAM has no effect on 0-0x1FFF, according to Oscar Toledo.
11
// So, if the BIOS is disabled to show RAM and the SGM RAM is disabled, is
12
// there is 8kB SGM RAM on 0-0x1FFF.
13
14
static constexpr unsigned MAIN_RAM_AREA_START = 0x6000;
15
static constexpr unsigned MAIN_RAM_SIZE = 0x400; // 1kB
16
static constexpr unsigned SGM_RAM_SIZE = 0x8000; // 32kB
17
static constexpr unsigned BIOS_ROM_SIZE = 0x2000; // 8kB
18
19
ColecoSuperGameModule::ColecoSuperGameModule(DeviceConfig& config)
20
	: MSXDevice(config)
21
	, psg(getName() + " PSG", DummyAY8910Periphery::instance(), config, getCurrentTime())
22
	, sgmRam(config, getName() + " RAM", "SGM RAM", SGM_RAM_SIZE)
23
	, mainRam(config, "Main RAM", "Main RAM", MAIN_RAM_SIZE)
24
	, biosRom(getName(), "BIOS ROM", config)
25
{
26
	// adjust PSG volume, see details in https://github.com/openMSX/openMSX/issues/1934
27
	// note: this is a theoretical value. The actual relative volume should be measured!
28
	psg.setSoftwareVolume(21000.0f/9000.0f, getCurrentTime());
29
30
	if (biosRom.size() != BIOS_ROM_SIZE) {
31
		throw MSXException("ColecoVision BIOS ROM must be exactly 8kB in size.");
32
	}
33
	auto& cpuInterface = getCPUInterface();
34
	for (auto port : {0x50, 0x51, 0x53, 0x7F}) {
35
		cpuInterface.register_IO_Out(narrow_cast<byte>(port), this);
36
	}
37
	cpuInterface.register_IO_In(0x52, this);
38
	reset(getCurrentTime());
39
}
40
41
ColecoSuperGameModule::~ColecoSuperGameModule()
42
{
43
	auto& cpuInterface = getCPUInterface();
44
	for (auto port : {0x50, 0x51, 0x53, 0x7F}) {
45
		cpuInterface.unregister_IO_Out(narrow_cast<byte>(port), this);
46
	}
47
	cpuInterface.unregister_IO_In(0x52, this);
48
}
49
50
static constexpr unsigned translateMainRamAddress(unsigned address)
51
{
52
	return address & (MAIN_RAM_SIZE - 1);
53
}
54
55
void ColecoSuperGameModule::reset(EmuTime time)
56
{
57
	ramEnabled = false;
58
	ramAtBiosEnabled = false;
59
	psgLatch = 0;
60
	psg.reset(time);
61
	invalidateDeviceRWCache(); // flush all to be sure
62
}
63
64
byte ColecoSuperGameModule::readIO(uint16_t port, EmuTime time)
65
{
66
	if ((port & 0xFF) == 0x52) {
67
		return psg.readRegister(psgLatch, time);
68
	}
69
	return 0xFF;
70
}
71
72
byte ColecoSuperGameModule::peekIO(uint16_t port, EmuTime time) const
73
{
74
	if ((port & 0xFF) == 0x52) {
75
		return psg.peekRegister(psgLatch, time);
76
	}
77
	return 0xFF;
78
}
79
80
void ColecoSuperGameModule::writeIO(uint16_t port, byte value, EmuTime time)
81
{
82
	switch (port & 0xFF) {
83
		case 0x50: // PSG address (latch?)
84
			psgLatch = value & 0x0F;
85
			break;
86
		case 0x51: // PSG data (register write?)
87
			psg.writeRegister(psgLatch, value, time);
88
			break;
89
		case 0x53: // bit0=1 means enable SGM RAM in 0x2000-0x7FFF range
90
			ramEnabled = (value & 1) != 0;
91
			invalidateDeviceRWCache(0x0000, SGM_RAM_SIZE); // just flush the whole area
92
			break;
93
		case 0x7F: // bit1=0 means enable SGM RAM in BIOS area (0-0x1FFF), 1 means BIOS
94
			ramAtBiosEnabled = (value & 2) == 0;
95
			invalidateDeviceRWCache(0x0000, BIOS_ROM_SIZE);
96
			break;
97
		default:
98
			// ignore
99
			break;
100
	}
101
}
102
103
byte ColecoSuperGameModule::peekMem(uint16_t address, EmuTime /*time*/) const
104
{
105
	if (address < BIOS_ROM_SIZE) {
106
		return ramAtBiosEnabled ? sgmRam.peek(address) : biosRom[address];
107
	} else if (address < SGM_RAM_SIZE) {
108
		if (ramEnabled) {
109
			return sgmRam.peek(address);
110
		} else if (address >= MAIN_RAM_AREA_START) {
111
			return mainRam.peek(translateMainRamAddress(address));
112
		}
113
	}
114
	return 0xFF;
115
}
116
117
byte ColecoSuperGameModule::readMem(uint16_t address, EmuTime /*time*/)
118
{
119
	if (address < BIOS_ROM_SIZE) {
120
		return ramAtBiosEnabled ? sgmRam.read(address) : biosRom[address];
121
	} else if (address < SGM_RAM_SIZE) {
122
		if (ramEnabled) {
123
			return sgmRam.read(address);
124
		} else if (address >= MAIN_RAM_AREA_START) {
125
			return mainRam.read(translateMainRamAddress(address));
126
		}
127
	}
128
	return 0xFF;
129
}
130
131
void ColecoSuperGameModule::writeMem(uint16_t address, byte value, EmuTime /*time*/)
132
{
133
	if (address < BIOS_ROM_SIZE) {
134
		if (ramAtBiosEnabled) {
135
			sgmRam.write(address, value);
136
		}
137
	} else if (address < SGM_RAM_SIZE) {
138
		if (ramEnabled) {
139
			sgmRam.write(address, value);
140
		} else if (address >= MAIN_RAM_AREA_START) {
141
			mainRam.write(translateMainRamAddress(address), value);
142
		}
143
	}
144
}
145
146
const byte* ColecoSuperGameModule::getReadCacheLine(uint16_t start) const
147
{
148
	if (start < BIOS_ROM_SIZE) {
149
		return ramAtBiosEnabled ? sgmRam.getReadCacheLine(start) : &biosRom[start];
150
	} else if (start < SGM_RAM_SIZE) {
151
		if (ramEnabled) {
152
			return sgmRam.getReadCacheLine(start);
153
		} else if (start >= MAIN_RAM_AREA_START) {
154
			return mainRam.getReadCacheLine(translateMainRamAddress(start));
155
		}
156
	}
157
	return unmappedRead.data();
158
}
159
160
byte* ColecoSuperGameModule::getWriteCacheLine(uint16_t start)
161
{
162
	if (start < BIOS_ROM_SIZE) {
163
		if (ramAtBiosEnabled) {
164
			return sgmRam.getWriteCacheLine(start);
165
		}
166
	} else if (start < SGM_RAM_SIZE) {
167
		if (ramEnabled) {
168
			return sgmRam.getWriteCacheLine(start);
169
		} else if (start >= MAIN_RAM_AREA_START) {
170
			return mainRam.getWriteCacheLine(translateMainRamAddress(start));
171
		}
172
	}
173
	return unmappedWrite.data();
174
}
175
176
template<typename Archive>
177
void ColecoSuperGameModule::serialize(Archive& ar, unsigned /*version*/)
178
{
179
	ar.serialize("mainRam",          mainRam.getUncheckedRam(),
180
	             "sgmRam",           sgmRam.getUncheckedRam(),
181
	             "psg",              psg,
182
	             "psgLatch",         psgLatch,
183
	             "ramEnabled",       ramEnabled,
184
	             "ramAtBiosEnabled", ramAtBiosEnabled);
185
}
186
INSTANTIATE_SERIALIZE_METHODS(ColecoSuperGameModule);
187
REGISTER_MSXDEVICE(ColecoSuperGameModule, "ColecoSuperGameModule");
188
189
} // namespace openmsx