openMSX
ESE_SCC.cc
Go to the documentation of this file.
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
58namespace openmsx {
59
60size_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
75ESE_SCC::ESE_SCC(const 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
87void ESE_SCC::powerUp(EmuTime::param time)
88{
89 scc.powerUp(time);
90 reset(time);
91}
92
93void ESE_SCC::reset(EmuTime::param time)
94{
95 setMapperHigh(0);
96 for (auto i : xrange(byte(4))) {
97 setMapperLow(i, i);
98 }
99 scc.reset(time);
100 if (spc) spc->reset(true);
101}
102
103void ESE_SCC::setMapperLow(unsigned page, byte value)
104{
105 value &= 0x3f; // use only 6bit
106 bool flush = false;
107 if (page == 2) {
108 bool newSccEnable = (value == 0x3f);
109 if (newSccEnable != sccEnable) {
110 sccEnable = newSccEnable;
111 flush = true;
112 }
113 }
114 byte newValue = value;
115 if (page == 0) newValue |= byte(mapper[0] & 0x40);
116 newValue &= mapperMask;
117 if (mapper[page] != newValue) {
118 mapper[page] = newValue;
119 flush = true;
120 }
121 if (flush) {
122 invalidateDeviceRWCache(0x4000 + 0x2000 * page, 0x2000);
123 }
124}
125
126void ESE_SCC::setMapperHigh(byte value)
127{
128 writeEnable = (value & 0x10) != 0; // no need to flush cache
129 if (!spc) return; // only WAVE-SCSI supports 1024kB
130
131 bool flush = false;
132 byte mapperHigh = value & 0x40;
133 if (bool newSpcEnable = mapperHigh && !writeEnable;
134 spcEnable != newSpcEnable) {
135 spcEnable = newSpcEnable;
136 flush = true;
137 }
138
139 if (byte newValue = ((mapper[0] & 0x3F) | mapperHigh) & mapperMask;
140 mapper[0] != newValue) {
141 mapper[0] = newValue;
142 flush = true;
143 }
144 if (flush) {
145 invalidateDeviceRWCache(0x4000, 0x2000);
146 }
147}
148
149byte ESE_SCC::readMem(word address, EmuTime::param time)
150{
151 unsigned page = address / 0x2000 - 2;
152 // SPC
153 if (spcEnable && (page == 0)) {
154 address &= 0x1fff;
155 if (address < 0x1000) {
156 return spc->readDREG();
157 } else {
158 return spc->readRegister(address & 0x0f);
159 }
160 }
161 // SCC bank
162 if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
163 return scc.readMem(narrow_cast<uint8_t>(address & 0xff), time);
164 }
165 // SRAM read
166 return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
167}
168
169byte ESE_SCC::peekMem(word address, EmuTime::param time) const
170{
171 unsigned page = address / 0x2000 - 2;
172 // SPC
173 if (spcEnable && (page == 0)) {
174 address &= 0x1fff;
175 if (address < 0x1000) {
176 return spc->peekDREG();
177 } else {
178 return spc->peekRegister(address & 0x0f);
179 }
180 }
181 // SCC bank
182 if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
183 return scc.peekMem(narrow_cast<uint8_t>(address & 0xff), time);
184 }
185 // SRAM read
186 return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
187}
188
189const byte* ESE_SCC::getReadCacheLine(word address) const
190{
191 unsigned page = address / 0x2000 - 2;
192 // SPC
193 if (spcEnable && (page == 0)) {
194 return nullptr;
195 }
196 // SCC bank
197 if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
198 return nullptr;
199 }
200 // SRAM read
201 return &sram[mapper[page] * 0x2000 + (address & 0x1fff)];
202}
203
204void ESE_SCC::writeMem(word address, byte value, EmuTime::param time)
205{
206 unsigned page = address / 0x2000 - 2;
207 // SPC Write
208 if (spcEnable && (page == 0)) {
209 address &= 0x1fff;
210 if (address < 0x1000) {
211 spc->writeDREG(value);
212 } else {
213 spc->writeRegister(address & 0x0f, value);
214 }
215 return;
216 }
217
218 // SCC write
219 if (sccEnable && (0x9800 <= address) && (address < 0xa000)) {
220 scc.writeMem(narrow_cast<uint8_t>(address & 0xff), value, time);
221 return;
222 }
223
224 // set mapper high control register
225 if ((address | 0x0001) == 0x7FFF) {
226 setMapperHigh(value);
227 return;
228 }
229
230 // SRAM write (processing of 0x4000-0x7FFD)
231 if (writeEnable && (page < 2)) {
232 sram.write(mapper[page] * 0x2000 + (address & 0x1FFF), value);
233 return;
234 }
235
236 // Bank change
237 if ((address & 0x1800) == 0x1000) {
238 setMapperLow(page, value);
239 return;
240 }
241}
242
244{
245 return nullptr; // not cacheable
246}
247
248
249template<typename Archive>
250void ESE_SCC::serialize(Archive& ar, unsigned /*version*/)
251{
252 ar.template serializeBase<MSXDevice>(*this);
253 ar.serialize("sram", sram,
254 "scc", scc);
255 if (spc) ar.serialize("MB89352", *spc);
256 ar.serialize("mapper", mapper,
257 "spcEnable", spcEnable,
258 "sccEnable", sccEnable,
259 "writeEnable", writeEnable);
260}
263
264} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
Definition ESE_SCC.cc:204
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition ESE_SCC.cc:189
void reset(EmuTime::param time) override
This method is called on reset.
Definition ESE_SCC.cc:93
void serialize(Archive &ar, unsigned version)
Definition ESE_SCC.cc:250
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition ESE_SCC.cc:87
ESE_SCC(const DeviceConfig &config, bool withSCSI)
Definition ESE_SCC.cc:75
byte * getWriteCacheLine(word address) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition ESE_SCC.cc:243
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition ESE_SCC.cc:169
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition ESE_SCC.cc:149
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition MSXDevice.cc:375
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition MSXDevice.hh:214
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition MSXDevice.hh:236
void powerUp(EmuTime::param time)
Definition SCC.cc:141
uint8_t readMem(uint8_t address, EmuTime::param time)
Definition SCC.cc:193
void reset(EmuTime::param time)
Definition SCC.cc:173
uint8_t peekMem(uint8_t address, EmuTime::param time) const
Definition SCC.cc:206
void writeMem(uint8_t address, uint8_t value, EmuTime::param time)
Definition SCC.cc:285
void write(size_t addr, byte value)
Definition SRAM.cc:64
int getChildDataAsInt(std::string_view childName, int defaultValue) const
Definition XMLElement.cc:83
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint8_t byte
8 bit unsigned integer
Definition openmsx.hh:26
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition ranges.hh:322
STL namespace.
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)
Definition xrange.hh:132