OXYGENHUB
◆ main openmsx / src / memory / ESE_SCC.cc
6.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
/*
2
 * 'Ese-SCC' cartridge and 'MEGA-SCSI with SCC'(alias WAVE-SCSI) cartridge.
3
 *
4
 * Specification:
5
 *  SRAM(MegaROM) controller: KONAMI_SCC type
6
 *  SRAM capacity           : 128, 256, 512kB and 1024kb(WAVE-SCSI only)
7
 *  SCSI Protocol controller: Fujitsu MB89352A
8
 *
9
 * ESE-SCC sram write control register:
10
 *  0x7FFE, 0x7FFF SRAM write control.
11
 *   bit4       = 1..SRAM writing in 0x4000-0x7FFD can be done.
12
 *                   It is given priority more than bank changing.
13
 *              = 0..SRAM read only
14
 *   other bit  = not used
15
 *
16
 * WAVE-SCSI bank control register
17
 *             6bit register (MA13-MA18, B0-B5)
18
 *  5000-57FF: 4000-5FFF change
19
 *  7000-77FF: 6000-7FFF change
20
 *  9000-97FF: 8000-9FFF change
21
 *  B000-B7FF: A000-BFFF change
22
 *
23
 *  7FFE,7FFF: 2bit register
24
 *       bit4: bank control MA20 (B7)
25
 *       bit6: bank control MA19 (B6)
26
 *  other bit: not used
27
 *
28
 * WAVE-SCSI bank map:
29
 *  00-3F: SRAM read only. mirror of 80-BF.
30
 *     3F: SCC
31
 *  40-7F: SPC (MB89352A)
32
 *  80-FF: SRAM read and write
33
 *
34
 * SPC BANK address map:
35
 * 4000-4FFF spc data register (mirror of 5FFA)
36
 * 5000-5FEF undefined specification
37
 * 5FF0-5FFE spc register
38
 *      5FFF unmapped
39
 *
40
 * WAVE-SCSI bank access map (X = accessible)
41
 *           00-3F 80-BF C0-FF SPC  SCC
42
 * 4000-5FFF   X     X     X    X    .
43
 * 6000-7FFF   X     X     .    .    .
44
 * 8000-9FFF   X     .     .    .    X
45
 * A000-BFFF   X     .     .    .    .
46
 */
47
48
#include "ESE_SCC.hh"
49
#include "MB89352.hh"
50
#include "MSXException.hh"
51
#include "narrow.hh"
52
#include "one_of.hh"
53
#include "ranges.hh"
54
#include "serialize.hh"
55
#include "xrange.hh"
56
#include <memory>
57
58
namespace openmsx {
59
60
size_t ESE_SCC::getSramSize(bool withSCSI) const
61
{
62
	size_t sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 256); // size in kb
63
	if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
64
		throw MSXException(
65
			"SRAM size for ", getName(),
66
			" should be 128, 256, 512 or 1024kB and not ",
67
			sramSize, "kB!");
68
	}
69
	if (!withSCSI && sramSize == 1024) {
70
		throw MSXException("1024kB SRAM is only allowed in WAVE-SCSI!");
71
	}
72
	return sramSize * 1024; // in bytes
73
}
74
75
ESE_SCC::ESE_SCC(DeviceConfig& config, bool withSCSI)
76
	: MSXDevice(config)
77
	, sram(getName() + " SRAM", getSramSize(withSCSI), config)
78
	, scc(getName(), config, getCurrentTime())
79
	, spc(withSCSI ? std::make_unique<MB89352>(config) : nullptr)
80
	, romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
81
	, mapperMask(narrow<byte>((sram.size() / 0x2000) - 1))
82
{
83
	// initialized mapper
84
	ranges::iota(mapper, byte(0));
85
86
	powerUp(getCurrentTime());
87
}
88
89
void ESE_SCC::powerUp(EmuTime time)
90
{
91
	scc.powerUp(time);
92
	reset(time);
93
}
94
95
void ESE_SCC::reset(EmuTime time)
96
{
97
	setMapperHigh(0);
98
	for (auto i : xrange(byte(4))) {
99
		setMapperLow(i, i);
100
	}
101
	scc.reset(time);
102
	if (spc) spc->reset(true);
103
}
104
105
void ESE_SCC::setMapperLow(unsigned page, byte value)
106
{
107
	value &= 0x3f; // use only 6bit
108
	bool flush = false;
109
	if (page == 2) {
110
		bool newSccEnable = (value == 0x3f);
111
		if (newSccEnable != sccEnable) {
112
			sccEnable = newSccEnable;
113
			flush = true;
114
		}
115
	}
116
	byte newValue = value;
117
	if (page == 0) newValue |= byte(mapper[0] & 0x40);
118
	newValue &= mapperMask;
119
	if (mapper[page] != newValue) {
120
		mapper[page] = newValue;
121
		flush = true;
122
	}
123
	if (flush) {
124
		invalidateDeviceRWCache(0x4000 + 0x2000 * page, 0x2000);
125
	}
126
}
127
128
void ESE_SCC::setMapperHigh(byte value)
129
{
130
	writeEnable = (value & 0x10) != 0; // no need to flush cache
131
	if (!spc) return; // only WAVE-SCSI supports 1024kB
132
133
	bool flush = false;
134
	byte mapperHigh = value & 0x40;
135
	if (bool newSpcEnable = mapperHigh && !writeEnable;
136
	    spcEnable != newSpcEnable) {
137
		spcEnable = newSpcEnable;
138
		flush = true;
139
	}
140
141
	if (byte newValue = ((mapper[0] & 0x3F) | mapperHigh) & mapperMask;
142
	    mapper[0] != newValue) {
143
		mapper[0] = newValue;
144
		flush = true;
145
	}
146
	if (flush) {
147
		invalidateDeviceRWCache(0x4000, 0x2000);
148
	}
149
}
150
151
byte ESE_SCC::readMem(uint16_t address, EmuTime time)
152
{
153
	unsigned page = address / 0x2000 - 2;
154
	// SPC
155
	if (spcEnable && (page == 0)) {
156
		address &= 0x1fff;
157
		if (address < 0x1000) {
158
			return spc->readDREG();
159
		} else {
160
			return spc->readRegister(address & 0x0f);
161
		}
162
	}
163
	// SCC bank
164
	if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
165
		return scc.readMem(narrow_cast<uint8_t>(address & 0xff), time);
166
	}
167
	// SRAM read
168
	return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
169
}
170
171
byte ESE_SCC::peekMem(uint16_t address, EmuTime time) const
172
{
173
	unsigned page = address / 0x2000 - 2;
174
	// SPC
175
	if (spcEnable && (page == 0)) {
176
		address &= 0x1fff;
177
		if (address < 0x1000) {
178
			return spc->peekDREG();
179
		} else {
180
			return spc->peekRegister(address & 0x0f);
181
		}
182
	}
183
	// SCC bank
184
	if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
185
		return scc.peekMem(narrow_cast<uint8_t>(address & 0xff), time);
186
	}
187
	// SRAM read
188
	return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
189
}
190
191
const byte* ESE_SCC::getReadCacheLine(uint16_t address) const
192
{
193
	unsigned page = address / 0x2000 - 2;
194
	// SPC
195
	if (spcEnable && (page == 0)) {
196
		return nullptr;
197
	}
198
	// SCC bank
199
	if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
200
		return nullptr;
201
	}
202
	// SRAM read
203
	return &sram[mapper[page] * 0x2000 + (address & 0x1fff)];
204
}
205
206
void ESE_SCC::writeMem(uint16_t address, byte value, EmuTime time)
207
{
208
	unsigned page = address / 0x2000 - 2;
209
	// SPC Write
210
	if (spcEnable && (page == 0)) {
211
		address &= 0x1fff;
212
		if (address < 0x1000) {
213
			spc->writeDREG(value);
214
		} else {
215
			spc->writeRegister(address & 0x0f, value);
216
		}
217
		return;
218
	}
219
220
	// SCC write
221
	if (sccEnable && (0x9800 <= address) && (address < 0xa000)) {
222
		scc.writeMem(narrow_cast<uint8_t>(address & 0xff), value, time);
223
		return;
224
	}
225
226
	// set mapper high control register
227
	if ((address | 0x0001) == 0x7FFF) {
228
		setMapperHigh(value);
229
		return;
230
	}
231
232
	// SRAM write (processing of 0x4000-0x7FFD)
233
	if (writeEnable && (page < 2)) {
234
		sram.write(mapper[page] * 0x2000 + (address & 0x1FFF), value);
235
		return;
236
	}
237
238
	// Bank change
239
	if ((address & 0x1800) == 0x1000) {
240
		setMapperLow(page, value);
241
		return;
242
	}
243
}
244
245
byte* ESE_SCC::getWriteCacheLine(uint16_t /*address*/)
246
{
247
	return nullptr; // not cacheable
248
}
249
250
251
template<typename Archive>
252
void ESE_SCC::serialize(Archive& ar, unsigned /*version*/)
253
{
254
	ar.template serializeBase<MSXDevice>(*this);
255
	ar.serialize("sram", sram,
256
	             "scc",  scc);
257
	if (spc) ar.serialize("MB89352", *spc);
258
	ar.serialize("mapper",      mapper,
259
	             "spcEnable",   spcEnable,
260
	             "sccEnable",   sccEnable,
261
	             "writeEnable", writeEnable);
262
}
263
INSTANTIATE_SERIALIZE_METHODS(ESE_SCC);
264
REGISTER_MSXDEVICE(ESE_SCC, "ESE_SCC");
265
266
} // namespace openmsx