OXYGENHUB
◆ main openmsx / src / memory / MegaFlashRomSCCPlus.cc
18.6 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "MegaFlashRomSCCPlus.hh"
2
3
#include "CacheLine.hh"
4
#include "DummyAY8910Periphery.hh"
5
#include "MSXCPUInterface.hh"
6
#include "serialize.hh"
7
8
#include "narrow.hh"
9
#include "ranges.hh"
10
#include "xrange.hh"
11
12
#include <array>
13
#include <cassert>
14
15
/******************************************************************************
16
 * DOCUMENTATION AS PROVIDED BY MANUEL PAZOS, WHO DEVELOPED THE CARTRIDGE     *
17
 ******************************************************************************
18
19
--------------------------------------------------------------------------------
20
MegaFlashROM SCC+ Technical Details
21
(c) Manuel Pazos 28-09-2010
22
--------------------------------------------------------------------------------
23
24
Main features:
25
 - 1024KB flashROM memory (M29W800DB)
26
 - SCC-I (2312P001)
27
 - PSG (AY-3-8910/YM2149)
28
 - Mappers: ASCII8, ASCII16, Konami, Konami SCC, linear 64K
29
 - Subslot simulation (4 x 256K)
30
31
32
--------------------------------------------------------------------------------
33
[Memory]
34
35
 - Model Numonyx M29W800DB TSOP48
36
 - Datasheet: https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/parallel/m29w/m29w800d.pdf
37
 - Block layout:
38
     #00000 16K
39
     #04000  8K
40
     #06000  8K
41
     #08000 32K
42
     #10000 64K x 15
43
 - Command addresses #4555 and #5AAA
44
 - Commands:
45
    AUTOSELECT  #90
46
    WRITE       #A0
47
    CHIP_ERASE  #10
48
    BLOCK_ERASE #30
49
    RESET       #F0
50
 - FlashROM ID = #5B
51
52
53
--------------------------------------------------------------------------------
54
[PSG]
55
56
 The PSG included in the cartridge is mapped to ports #10-#12
57
58
 Port #A0 -> #10
59
 Port #A1 -> #11
60
 Port #A2 -> #12
61
62
 The PSG is read only.
63
64
--------------------------------------------------------------------------------
65
[REGISTERS]
66
67
 -#7FFE or #7FFF = CONFIGURATION REGISTER:
68
    7 mapper mode 1: \ %00 = Konami/Konami-SCC,  %01 = 64K
69
    6 mapper mode 0: / %10 = ASC8, %11 = ASC16
70
    5 mapper mode  :   Select Konami mapper (0 = SCC, 1 = normal) [1]
71
    4 Enable subslot mode and register #FFFF (1 = Enable, 0 = Disable)
72
    3 Disable #4000-#5FFF mapper in Konami mode (0 = Enable, 1 = Disable)
73
    2 Disable configuration register (1 = Disabled)
74
    1 Disable mapper registers (0 = Enable, 1 = Disable)
75
    0 Enable 512K mapper limit in SCC mapper or 256K limit in Konami mapper
76
(1 = Enable, 0 = Disable)
77
78
[1] bit 5 only changes the address range of the mapper (Konami or Konami SCC)
79
but the SCC is always available.  This is done for the subslot mode because all
80
subslots share the same mapper type. So to make Konami combinations (i.e.:
81
Konami ROM with Konami SCC ROM) a "common mapper" is needed and the SCC must be
82
available. So I made a "Konami mapper" with SCC.  In fact, all Konami and
83
Konami SCC ROMs should work with "Konami" mapper.
84
85
86
--------------------------------------------------------------------------------
87
[MAPPERS]
88
89
 - ASCII 8:    Common ASC8 mapper
90
91
 - ASCII 16:   Common ASC16 mapper
92
93
 - Konami:     Common Konami mapper.
94
               Bank0 (#4000-#5FFF) can be also changed unless CONF_REG bit3 is 1
95
96
 - Konami SCC: Common Konami SCC mapper
97
               Bank0 mapper register: if bank number bit 7 is 1 then bit 6-0 sets mapper offset.
98
99
 - Linear 64:  #0000-#3FFF bank0
100
               #4000-#7FFF bank1
101
               #8000-#BFFF bank2
102
               #C000-#FFFF bank3
103
               Banks mapper registers addresses = Konami
104
105
--------------------------------------------------------------------------------
106
[DEFAULT VALUES]
107
 - CONFIGURATION REGISTER = 0
108
 - Bank0 = 0
109
 - Bank1 = 1
110
 - Bank2 = 2
111
 - Bank3 = 3
112
 - Bank offset = 0
113
 - Subslot register = 0
114
115
--------------------------------------------------------------------------------
116
[LOGIC]
117
118
  Banks0-3: are set depending on the mapper mode.
119
  Subslots: are set writing to #FFFF in the MegaFlashROM SCC+ slot when CONFIG_REG bit 4 is set.
120
  Offset:   is set by writing offset value + #80 to bank0 mapper register in Konami SCC mode.
121
122
  -- Subslots offsets
123
  SubOff0 = subslot(1-0) & "0000" + mapOff;	-- In 64K mode, the banks are 16K, with the offsets halved
124
  SubOff1 = subslot(3-2) & "0000" + mapOff when maptyp = "10" else subslot(3-2) & "00000" + mapOff;
125
  SubOff2 = subslot(5-4) & "0000" + mapOff when maptyp = "10" else subslot(5-4) & "00000" + mapOff;
126
  SubOff3 = subslot(7-6) & "0000" + mapOff when maptyp = "10" else subslot(7-6) & "00000";
127
128
  -- Calculate the bank mapper to use taking into account the offset
129
  Bank0 =  SubBank0(x) + SubOff0 when SccModeA(4) = '1' and subslot(1 downto 0) = "00" and maptyp = "10" else
130
           SubBank0(1) + SubOff0 when SccModeA(4) = '1' and subslot(1 downto 0) = "01" and maptyp = "10" else
131
           SubBank0(2) + SubOff0 when SccModeA(4) = '1' and subslot(1 downto 0) = "10" and maptyp = "10" else
132
           SubBank0(3) + SubOff0 when SccModeA(4) = '1' and subslot(1 downto 0) = "11" and maptyp = "10" else
133
134
           SubBank0(0) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "00" else
135
           SubBank0(1) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "01" else
136
           SubBank0(2) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "10" else
137
           SubBank0(3) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "11" else
138
           SccBank0    + mapOff;
139
140
  Bank1 <= SubBank1(0) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "00" else
141
           SubBank1(1) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "01" else
142
           SubBank1(2) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "10" else
143
           SubBank1(3) + SubOff1 when SccModeA(4) = '1' and subslot(3 downto 2) = "11" else
144
           SccBank1    + mapOff;
145
146
  Bank2 <= SubBank2(0) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "00" else
147
           SubBank2(1) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "01" else
148
           SubBank2(2) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "10" else
149
           SubBank2(3) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "11" else
150
           SccBank2    + mapOff;
151
152
  Bank3 <= SubBank3(0) + SubOff3 when SccModeA(4) = '1' and subslot(7 downto 6) = "00" and maptyp = "10" else
153
           SubBank3(1) + SubOff3 when SccModeA(4) = '1' and subslot(7 downto 6) = "01" and maptyp = "10" else
154
           SubBank3(2) + SubOff3 when SccModeA(4) = '1' and subslot(7 downto 6) = "10" and maptyp = "10" else
155
           SubBank3(3) + SubOff3 when SccModeA(4) = '1' and subslot(7 downto 6) = "11" and maptyp = "10" else
156
157
           SubBank3(0) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "00" else
158
           SubBank3(1) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "01" else
159
           SubBank3(2) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "10" else
160
           SubBank3(3) + SubOff2 when SccModeA(4) = '1' and subslot(5 downto 4) = "11" else
161
           SccBank3    + mapOff;
162
163
164
            -- 64K Mode
165
  RamAdr <= Bank0(5 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "00" and maptyp = "10" else 	--#0000-#3FFF
166
            Bank1(5 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "01" and maptyp = "10" else 	--#4000-#7FFF
167
            Bank2(5 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "10" and maptyp = "10" else 	--#8000-#BFFF
168
            Bank3(5 downto 0) & adr(13 downto 0) when adr(15 downto 14) = "11" and maptyp = "10" else 	--#C000-#FFFF
169
            -- Modes SCC, ASC8 and ASC16
170
            Bank0(6 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "10" else 	--#4000-#5FFF
171
            Bank1(6 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "11" else 	--#6000-#7FFF
172
            Bank2(6 downto 0) & adr(12 downto 0) when adr(14 downto 13) = "00" else 	--#8000-#9FFF
173
            Bank3(6 downto 0) & adr(12 downto 0);
174
175
--------------------------------------------------------------------------------
176
[FLASH ROM ADDRESSING]
177
178
 In order to be compatible with OPFX which sends command sequences like
179
 (0x555) = 0xAA, (0xAAA) = 0x55, whilst dual mode 8/16-bit chips like the
180
 M29W800DB expect (0xAAA) = 0xAA, (0x555) = 0x55 when operating in byte mode,
181
 CPU line A12 is connected to Flash line A0.
182
183
  CPU line | Flash line (-1 on datasheet)
184
 ----------+------------------------------
185
  A0-A11   |  A1-A12
186
  A12      |  A0
187
  A13-A15  |  A13-A19 (through mapper)
188
189
 Since the smallest sector size is 8 kB, sector numbers are unaffected, only
190
 sector offsets are. Unfortunately, this prohibits read caching.
191
192
******************************************************************************/
193
194
namespace openmsx {
195
196
MegaFlashRomSCCPlus::MegaFlashRomSCCPlus(
197
		DeviceConfig& config, Rom&& rom_)
198
	: MSXRom(config, std::move(rom_))
199
	, scc("MFR SCC+ SCC-I", config, getCurrentTime(), SCC::Mode::Compatible)
200
	, psg("MFR SCC+ PSG", DummyAY8910Periphery::instance(), config,
201
	      getCurrentTime())
202
	, flash(rom, AmdFlashChip::M29W800DB, {}, config)
203
{
204
	// adjust PSG volume, see details in https://github.com/openMSX/openMSX/issues/1934
205
	// note: this is a theoretical value. The actual relative volume should be measured!
206
	psg.setSoftwareVolume(21000.0f/9000.0f, getCurrentTime());
207
208
	powerUp(getCurrentTime());
209
	getCPUInterface().register_IO_Out_range(0x10, 2, this);
210
}
211
212
MegaFlashRomSCCPlus::~MegaFlashRomSCCPlus()
213
{
214
	getCPUInterface().unregister_IO_Out_range(0x10, 2, this);
215
}
216
217
void MegaFlashRomSCCPlus::powerUp(EmuTime time)
218
{
219
	scc.powerUp(time);
220
	reset(time);
221
}
222
223
void MegaFlashRomSCCPlus::reset(EmuTime time)
224
{
225
	configReg = 0;
226
	offsetReg = 0;
227
	subslotReg = 0;
228
	for (auto& regs : bankRegs) {
229
		ranges::iota(regs, byte(0));
230
	}
231
232
	sccModeReg = 0;
233
	ranges::iota(sccBanks, byte(0));
234
	scc.reset(time);
235
236
	psgLatch = 0;
237
	psg.reset(time);
238
239
	flash.reset();
240
241
	invalidateDeviceRCache(); // flush all to be sure
242
}
243
244
MegaFlashRomSCCPlus::SCCMode MegaFlashRomSCCPlus::getSCCMode() const
245
{
246
	using enum SCCMode;
247
	if ((sccModeReg & 0x20) && (sccBanks[3] & 0x80)) {
248
		return SCCPLUS;
249
	} else if ((!(sccModeReg & 0x20)) && ((sccBanks[2] & 0x3F) == 0x3F)) {
250
		return SCC;
251
	} else {
252
		return NONE;
253
	}
254
}
255
256
unsigned MegaFlashRomSCCPlus::getSubslot(unsigned addr) const
257
{
258
	return (configReg & 0x10)
259
	     ? (subslotReg >> (2 * (addr >> 14))) & 0x03
260
	     : 0;
261
}
262
263
unsigned MegaFlashRomSCCPlus::getFlashAddr(unsigned addr) const
264
{
265
	// Pazos: FlashROM A0 (A-1 on datasheet) is connected to CPU A12.
266
	addr = (addr & 0xE000) | ((addr & 0x1000) >> 12) | ((addr & 0x0FFF) << 1);
267
268
	unsigned subslot = getSubslot(addr);
269
	unsigned tmp = [&] {
270
		if ((configReg & 0xC0) == 0x40) {
271
			unsigned bank = bankRegs[subslot][addr >> 14] + offsetReg;
272
			return (bank * 0x4000) + (addr & 0x3FFF);
273
		} else {
274
			unsigned page = (addr >> 13) - 2;
275
			if (page >= 4) {
276
				// Bank: -2, -1, 4, 5. So not mapped in this region,
277
				// returned value should not be used. But querying it
278
				// anyway is easier, see start of writeMem().
279
				return unsigned(-1);
280
			}
281
			unsigned bank = bankRegs[subslot][page] + offsetReg;
282
			return (bank * 0x2000) + (addr & 0x1FFF);
283
		}
284
	}();
285
	return ((0x40000 * subslot) + tmp) & 0xFFFFF; // wrap at 1MB
286
}
287
288
bool MegaFlashRomSCCPlus::isSCCAccessEnabled() const
289
{
290
	// In both Konami and Konami SCC mappers the SCC is available (see note
291
	// above)
292
	return (configReg & 0xE0) == one_of(0x00, 0x20);
293
}
294
295
byte MegaFlashRomSCCPlus::peekMem(uint16_t addr, EmuTime time) const
296
{
297
	if ((configReg & 0x10) && (addr == 0xFFFF)) {
298
		// read subslot register
299
		return subslotReg ^ 0xFF;
300
	}
301
302
	if (isSCCAccessEnabled()) {
303
		auto mode = getSCCMode();
304
		if (((mode == SCCMode::SCC)     && (0x9800 <= addr) && (addr < 0xA000)) ||
305
		    ((mode == SCCMode::SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
306
			return scc.peekMem(narrow_cast<uint8_t>(addr & 0xFF), time);
307
		}
308
	}
309
310
	if (((configReg & 0xC0) == 0x40) ||
311
	    ((0x4000 <= addr) && (addr < 0xC000))) {
312
		// read (flash)rom content
313
		unsigned flashAddr = getFlashAddr(addr);
314
		assert(flashAddr != unsigned(-1));
315
		return flash.peek(flashAddr, time);
316
	} else {
317
		// unmapped read
318
		return 0xFF;
319
	}
320
}
321
322
byte MegaFlashRomSCCPlus::readMem(uint16_t addr, EmuTime time)
323
{
324
	if ((configReg & 0x10) && (addr == 0xFFFF)) {
325
		// read subslot register
326
		return subslotReg ^ 0xFF;
327
	}
328
329
	if (isSCCAccessEnabled()) {
330
		auto mode = getSCCMode();
331
		if (((mode == SCCMode::SCC)     && (0x9800 <= addr) && (addr < 0xA000)) ||
332
		    ((mode == SCCMode::SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
333
			return scc.readMem(narrow_cast<uint8_t>(addr & 0xFF), time);
334
		}
335
	}
336
337
	if (((configReg & 0xC0) == 0x40) ||
338
	    ((0x4000 <= addr) && (addr < 0xC000))) {
339
		// read (flash)rom content
340
		unsigned flashAddr = getFlashAddr(addr);
341
		assert(flashAddr != unsigned(-1));
342
		return flash.read(flashAddr, time);
343
	} else {
344
		// unmapped read
345
		return 0xFF;
346
	}
347
}
348
349
const byte* MegaFlashRomSCCPlus::getReadCacheLine(uint16_t addr) const
350
{
351
	if ((configReg & 0x10) &&
352
	    ((addr & CacheLine::HIGH) == (0xFFFF & CacheLine::HIGH))) {
353
		// read subslot register
354
		return nullptr;
355
	}
356
357
	if (isSCCAccessEnabled()) {
358
		auto mode = getSCCMode();
359
		if (((mode == SCCMode::SCC)     && (0x9800 <= addr) && (addr < 0xA000)) ||
360
		    ((mode == SCCMode::SCCPLUS) && (0xB800 <= addr) && (addr < 0xC000))) {
361
			return nullptr;
362
		}
363
	}
364
365
	if (((configReg & 0xC0) == 0x40) ||
366
	    ((0x4000 <= addr) && (addr < 0xC000))) {
367
		return nullptr; // uncacheable due to address swizzling
368
	} else {
369
		// unmapped read
370
		return unmappedRead.data();
371
	}
372
}
373
374
void MegaFlashRomSCCPlus::writeMem(uint16_t addr, byte value, EmuTime time)
375
{
376
	// address is calculated before writes to other regions take effect
377
	unsigned flashAddr = getFlashAddr(addr);
378
379
	// There are several overlapping functional regions in the address
380
	// space. A single write can trigger behaviour in multiple regions. In
381
	// other words there's no priority amongst the regions where a higher
382
	// priority region blocks the write from the lower priority regions.
383
	if ((configReg & 0x10) && (addr == 0xFFFF)) {
384
		// write subslot register
385
		byte diff = value ^ subslotReg;
386
		subslotReg = value;
387
		for (auto i : xrange(4)) {
388
			if (diff & (3 << (2 * i))) {
389
				invalidateDeviceRCache(0x4000 * i, 0x4000);
390
			}
391
		}
392
	}
393
394
	if (((configReg & 0x04) == 0x00) && ((addr & 0xFFFE) == 0x7FFE)) {
395
		// write config register
396
		configReg = value;
397
		invalidateDeviceRCache(); // flush all to be sure
398
	}
399
400
	if (isSCCAccessEnabled()) {
401
		// Konami-SCC
402
		if ((addr & 0xFFFE) == 0xBFFE) {
403
			sccModeReg = value;
404
			scc.setMode((value & 0x20) ? SCC::Mode::Plus
405
			                           : SCC::Mode::Compatible);
406
			invalidateDeviceRCache(0x9800, 0x800);
407
			invalidateDeviceRCache(0xB800, 0x800);
408
		}
409
		auto mode = getSCCMode();
410
		bool isRamSegment2 = ((sccModeReg & 0x24) == 0x24) ||
411
		                     ((sccModeReg & 0x10) == 0x10);
412
		bool isRamSegment3 = ((sccModeReg & 0x10) == 0x10);
413
		if (((mode == SCCMode::SCC)     && !isRamSegment2 &&
414
		     (0x9800 <= addr) && (addr < 0xA000)) ||
415
		    ((mode == SCCMode::SCCPLUS) && !isRamSegment3 &&
416
		     (0xB800 <= addr) && (addr < 0xC000))) {
417
			scc.writeMem(narrow_cast<uint8_t>(addr & 0xFF), value, time);
418
			return; // Pazos: when SCC registers are selected flashROM is not seen, so it does not accept commands.
419
		}
420
	}
421
422
	unsigned subslot = getSubslot(addr);
423
	unsigned page8kB = (addr >> 13) - 2;
424
	if (((configReg & 0x02) == 0x00) && (page8kB < 4)) {
425
		// (possibly) write to bank registers
426
		switch (configReg & 0xE0) {
427
		case 0x00:
428
			// Konami-SCC
429
			if ((addr & 0x1800) == 0x1000) {
430
				// Storing 'sccBanks' may seem redundant at
431
				// first, but it's required to calculate
432
				// whether the SCC is enabled or not.
433
				sccBanks[page8kB] = value;
434
				if ((value & 0x80) && (page8kB == 0)) {
435
					offsetReg = value & 0x7F;
436
					invalidateDeviceRCache(0x4000, 0x8000);
437
				} else {
438
					// Masking of the mapper bits is done on
439
					// write (and only in Konami(-scc) mode)
440
					byte mask = (configReg & 0x01) ? 0x3F : 0x7F;
441
					bankRegs[subslot][page8kB] = value & mask;
442
					invalidateDeviceRCache(0x4000 + 0x2000 * page8kB, 0x2000);
443
				}
444
			}
445
			break;
446
		case 0x20: {
447
			// Konami
448
			if (((configReg & 0x08) == 0x08) && (addr < 0x6000)) {
449
				// Switching 0x4000-0x5FFF disabled.
450
				// This bit blocks writing to the bank register
451
				// (an alternative was forcing a 0 on read).
452
				// It only has effect in Konami mode.
453
				break;
454
			}
455
			// Making of the mapper bits is done on
456
			// write (and only in Konami(-scc) mode)
457
			if ((addr < 0x5000) || ((0x5800 <= addr) && (addr < 0x6000))) break; // only SCC range works
458
			byte mask = (configReg & 0x01) ? 0x1F : 0x7F;
459
			bankRegs[subslot][page8kB] = value & mask;
460
			sccBanks[page8kB] = value;
461
			invalidateDeviceRCache(0x4000 + 0x2000 * page8kB, 0x2000);
462
			break;
463
		}
464
		case 0x40:
465
		case 0x60:
466
			// 64kB
467
			bankRegs[subslot][page8kB] = value;
468
			invalidateDeviceRCache(0x0000 + 0x4000 * page8kB, 0x4000);
469
			break;
470
		case 0x80:
471
		case 0xA0:
472
			// ASCII-8
473
			if ((0x6000 <= addr) && (addr < 0x8000)) {
474
				byte bank = (addr >> 11) & 0x03;
475
				bankRegs[subslot][bank] = value;
476
				invalidateDeviceRCache(0x4000 + 0x2000 * bank, 0x2000);
477
			}
478
			break;
479
		case 0xC0:
480
		case 0xE0:
481
			// ASCII-16
482
			// This behaviour is confirmed by Manuel Pazos (creator
483
			// of the cartridge): ASCII-16 uses all 4 bank registers
484
			// and one bank switch changes 2 registers at once.
485
			// This matters when switching mapper mode, because
486
			// the content of the bank registers is unchanged after
487
			// a switch.
488
			if ((0x6000 <= addr) && (addr < 0x6800)) {
489
				bankRegs[subslot][0] = narrow_cast<uint8_t>(2 * value + 0);
490
				bankRegs[subslot][1] = narrow_cast<uint8_t>(2 * value + 1);
491
				invalidateDeviceRCache(0x4000, 0x4000);
492
			}
493
			if ((0x7000 <= addr) && (addr < 0x7800)) {
494
				bankRegs[subslot][2] = narrow_cast<uint8_t>(2 * value + 0);
495
				bankRegs[subslot][3] = narrow_cast<uint8_t>(2 * value + 1);
496
				invalidateDeviceRCache(0x8000, 0x4000);
497
			}
498
			break;
499
		}
500
	}
501
502
	// write to flash
503
	if (((configReg & 0xC0) == 0x40) ||
504
	    ((0x4000 <= addr) && (addr < 0xC000))) {
505
		assert(flashAddr != unsigned(-1));
506
		flash.write(flashAddr, value, time);
507
	}
508
}
509
510
byte* MegaFlashRomSCCPlus::getWriteCacheLine(uint16_t /*addr*/)
511
{
512
	return nullptr;
513
}
514
515
516
void MegaFlashRomSCCPlus::writeIO(uint16_t port, byte value, EmuTime time)
517
{
518
	if ((port & 0xFF) == 0x10) {
519
		psgLatch = value & 0x0F;
520
	} else {
521
		assert((port & 0xFF) == 0x11);
522
		psg.writeRegister(psgLatch, value, time);
523
	}
524
}
525
526
527
template<typename Archive>
528
void MegaFlashRomSCCPlus::serialize(Archive& ar, unsigned /*version*/)
529
{
530
	// skip MSXRom base class
531
	ar.template serializeBase<MSXDevice>(*this);
532
533
	ar.serialize("scc",        scc,
534
	             "psg",        psg,
535
	             "flash",      flash,
536
537
	             "configReg",  configReg,
538
	             "offsetReg",  offsetReg,
539
	             "subslotReg", subslotReg,
540
	             "bankRegs",   bankRegs,
541
	             "psgLatch",   psgLatch,
542
	             "sccMode",    sccModeReg,
543
	             "sccBanks",   sccBanks);
544
}
545
INSTANTIATE_SERIALIZE_METHODS(MegaFlashRomSCCPlus);
546
REGISTER_MSXDEVICE(MegaFlashRomSCCPlus, "MegaFlashRomSCCPlus");
547
548
} // namespace openmsx