OXYGENHUB
◆ main openmsx / src / memory / RomKonamiSCC.cc
4.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
// KONAMI 8kB cartridges with SCC
2
//
3
// this type is used by Konami cartridges that do have an SCC and some others
4
// examples of cartridges: Nemesis 2, Nemesis 3, King's Valley 2, Space Manbow
5
// Solid Snake, Quarth, Ashguine 1, Animal, Arkanoid 2, ...
6
// Those last 3 were probably modified ROM images, they should be ASCII8
7
//
8
// The address to change banks:
9
//  bank 1: 0x5000 - 0x57ff (0x5000 used)
10
//  bank 2: 0x7000 - 0x77ff (0x7000 used)
11
//  bank 3: 0x9000 - 0x97ff (0x9000 used)
12
//  bank 4: 0xB000 - 0xB7ff (0xB000 used)
13
14
#include "RomKonamiSCC.hh"
15
16
#include "CacheLine.hh"
17
#include "MSXCliComm.hh"
18
#include "MSXMotherBoard.hh"
19
#include "serialize.hh"
20
21
#include "xrange.hh"
22
23
namespace openmsx {
24
25
RomKonamiSCC::RomKonamiSCC(const DeviceConfig& config, Rom&& rom_)
26
	: Rom8kBBlocks(config, std::move(rom_))
27
	, scc(getName() + " SCC", config, getCurrentTime())
28
{
29
	// warn if a ROM is used that would not work on a real KonamiSCC mapper
30
	if (rom.size() > 512 * 1024) {
31
		getMotherBoard().getMSXCliComm().printWarning(
32
			"The size of this ROM image is larger than 512kB, "
33
			"which is not supported on real Konami SCC mapper "
34
			"chips!");
35
	}
36
	powerUp(getCurrentTime());
37
}
38
39
void RomKonamiSCC::powerUp(EmuTime time)
40
{
41
	scc.powerUp(time);
42
	reset(time);
43
}
44
45
void RomKonamiSCC::bankSwitch(unsigned page, unsigned block)
46
{
47
	setRom(page, block);
48
49
	// Note: the mirror behavior is different from RomKonami !
50
	if (page == 2 || page == 3) {
51
		// [0x4000-0x8000), mirrored in [0xC000-0x10000)
52
		setRom(page + 4, block);
53
	} else if (page == 4 || page == 5) {
54
		// [0x8000-0xC000), mirrored in [0x0000-0x4000)
55
		setRom(page - 4, block);
56
	} else {
57
		assert(false);
58
	}
59
}
60
61
void RomKonamiSCC::reset(EmuTime time)
62
{
63
	for (auto i : xrange(2, 6)) {
64
		bankSwitch(i, i - 2);
65
	}
66
67
	sccEnabled = false;
68
	scc.reset(time);
69
}
70
71
byte RomKonamiSCC::peekMem(uint16_t address, EmuTime time) const
72
{
73
	if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
74
		return scc.peekMem(narrow_cast<uint8_t>(address & 0xFF), time);
75
	} else {
76
		return Rom8kBBlocks::peekMem(address, time);
77
	}
78
}
79
80
byte RomKonamiSCC::readMem(uint16_t address, EmuTime time)
81
{
82
	if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
83
		return scc.readMem(narrow_cast<uint8_t>(address & 0xFF), time);
84
	} else {
85
		return Rom8kBBlocks::readMem(address, time);
86
	}
87
}
88
89
const byte* RomKonamiSCC::getReadCacheLine(uint16_t address) const
90
{
91
	if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
92
		// don't cache SCC
93
		return nullptr;
94
	} else {
95
		return Rom8kBBlocks::getReadCacheLine(address);
96
	}
97
}
98
99
void RomKonamiSCC::writeMem(uint16_t address, byte value, EmuTime time)
100
{
101
	if ((address < 0x5000) || (address >= 0xC000)) {
102
		return;
103
	}
104
	if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
105
		// write to SCC
106
		scc.writeMem(narrow_cast<uint8_t>(address & 0xFF), value, time);
107
		return;
108
	}
109
	if ((address & 0xF800) == 0x9000) {
110
		// SCC enable/disable
111
		bool newSccEnabled = ((value & 0x3F) == 0x3F);
112
		if (newSccEnabled != sccEnabled) {
113
			sccEnabled = newSccEnabled;
114
			invalidateDeviceRWCache(0x9800, 0x0800);
115
		}
116
	}
117
	if ((address & 0x1800) == 0x1000) {
118
		// page selection
119
		auto region = address >> 13;
120
		bankSwitch(region, value);
121
		if ((region == 4) && sccEnabled) {
122
			invalidateDeviceRCache(0x9800, 0x0800);
123
		}
124
	}
125
}
126
127
byte* RomKonamiSCC::getWriteCacheLine(uint16_t address)
128
{
129
	if ((address < 0x5000) || (address >= 0xC000)) {
130
		return unmappedWrite.data();
131
	} else if (sccEnabled && (0x9800 <= address) && (address < 0xA000)) {
132
		// write to SCC
133
		return nullptr;
134
	} else if ((address & 0xF800) == (0x9000 & CacheLine::HIGH)) {
135
		// SCC enable/disable
136
		return nullptr;
137
	} else if ((address & 0x1800) == (0x1000 & CacheLine::HIGH)) {
138
		// page selection
139
		return nullptr;
140
	} else {
141
		return unmappedWrite.data();
142
	}
143
}
144
145
template<typename Archive>
146
void RomKonamiSCC::serialize(Archive& ar, unsigned /*version*/)
147
{
148
	ar.template serializeBase<Rom8kBBlocks>(*this);
149
	ar.serialize("scc",        scc,
150
	             "sccEnabled", sccEnabled);
151
}
152
INSTANTIATE_SERIALIZE_METHODS(RomKonamiSCC);
153
REGISTER_MSXDEVICE(RomKonamiSCC, "RomKonamiSCC");
154
155
} // namespace openmsx