openMSX
ESE_SCC.cc
Go to the documentation of this file.
1/*
2 * 'Ese-SCC' cartride 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 "one_of.hh"
52#include "ranges.hh"
53#include "serialize.hh"
54#include "xrange.hh"
55#include <memory>
56
57namespace openmsx {
58
59unsigned ESE_SCC::getSramSize(bool withSCSI) const
60{
61 unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 256); // size in kb
62 if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
63 throw MSXException(
64 "SRAM size for ", getName(),
65 " should be 128, 256, 512 or 1024kB and not ",
66 sramSize, "kB!");
67 }
68 if (!withSCSI && sramSize == 1024) {
69 throw MSXException("1024kB SRAM is only allowed in WAVE-SCSI!");
70 }
71 return sramSize * 1024; // in bytes
72}
73
74ESE_SCC::ESE_SCC(const DeviceConfig& config, bool withSCSI)
75 : MSXDevice(config)
76 , sram(getName() + " SRAM", getSramSize(withSCSI), config)
77 , scc(getName(), config, getCurrentTime())
78 , spc(withSCSI ? std::make_unique<MB89352>(config) : nullptr)
79 , romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
80 , mapperMask((sram.getSize() / 0x2000) - 1)
81 , spcEnable(false)
82 , sccEnable(false)
83 , writeEnable(false)
84{
85 // initialized mapper
86 ranges::iota(mapper, 0);
87}
88
89void ESE_SCC::powerUp(EmuTime::param time)
90{
91 scc.powerUp(time);
92 reset(time);
93}
94
95void ESE_SCC::reset(EmuTime::param time)
96{
97 setMapperHigh(0);
98 for (auto i : xrange(4)) {
99 setMapperLow(i, i);
100 }
101 scc.reset(time);
102 if (spc) spc->reset(true);
103}
104
105void 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 |= 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
128void 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 bool newSpcEnable = mapperHigh && !writeEnable;
136 if (spcEnable != newSpcEnable) {
137 spcEnable = newSpcEnable;
138 flush = true;
139 }
140
141 byte newValue = ((mapper[0] & 0x3F) | mapperHigh) & mapperMask;
142 if (mapper[0] != newValue) {
143 mapper[0] = newValue;
144 flush = true;
145 }
146 if (flush) {
147 invalidateDeviceRWCache(0x4000, 0x2000);
148 }
149}
150
151byte ESE_SCC::readMem(word address, EmuTime::param 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(address & 0xff, time);
166 }
167 // SRAM read
168 return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
169}
170
171byte ESE_SCC::peekMem(word address, EmuTime::param 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(address & 0xff, time);
186 }
187 // SRAM read
188 return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
189}
190
191const byte* ESE_SCC::getReadCacheLine(word 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
206void ESE_SCC::writeMem(word address, byte value, EmuTime::param 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(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
245byte* ESE_SCC::getWriteCacheLine(word /*address*/) const
246{
247 return nullptr; // not cacheable
248}
249
250
251template<typename Archive>
252void 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}
265
266} // namespace openmsx
Definition: one_of.hh:7
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:206
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:191
void reset(EmuTime::param time) override
This method is called on reset.
Definition: ESE_SCC.cc:95
void serialize(Archive &ar, unsigned version)
Definition: ESE_SCC.cc:252
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: ESE_SCC.cc:89
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: ESE_SCC.cc:245
ESE_SCC(const DeviceConfig &config, bool withSCSI)
Definition: ESE_SCC.cc:74
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: ESE_SCC.cc:171
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:151
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:33
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:376
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:209
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition: MSXDevice.hh:231
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:284
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
void reset(EmuTime::param time)
Definition: SCC.cc:172
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
void write(unsigned addr, byte value)
Definition: SRAM.cc:64
int getChildDataAsInt(std::string_view childName, int defaultValue) const
Definition: XMLElement.cc:81
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:727
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
constexpr void iota(ForwardIt first, ForwardIt last, T value)
Definition: ranges.hh:263
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009
constexpr auto xrange(T e)
Definition: xrange.hh:133