openMSX
ESE_SCC.cc
Go to the documentation of this file.
1 /*
2  * 'Ese-SCC' cartride and 'MEGA-SCSI with SCC'(alias WAVE-SCSI) cartrige.
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  * 7FFEH, 7FFFH SRAM write control.
11  * bit4 = 1..SRAM writing in 4000H-7FFDH can be done.
12  * It is given priority more than bank changing.
13  * = 0..SRAM read only
14  * othet 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 "serialize.hh"
53 #include <memory>
54 
55 namespace openmsx {
56 
57 unsigned ESE_SCC::getSramSize(bool withSCSI) const
58 {
59  unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 256); // size in kb
60  if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
61  throw MSXException(
62  "SRAM size for ", getName(),
63  " should be 128, 256, 512 or 1024kB and not ",
64  sramSize, "kB!");
65  }
66  if (!withSCSI && sramSize == 1024) {
67  throw MSXException("1024kB SRAM is only allowed in WAVE-SCSI!");
68  }
69  return sramSize * 1024; // in bytes
70 }
71 
72 ESE_SCC::ESE_SCC(const DeviceConfig& config, bool withSCSI)
73  : MSXDevice(config)
74  , sram(getName() + " SRAM", getSramSize(withSCSI), config)
75  , scc(getName(), config, getCurrentTime())
76  , spc(withSCSI ? std::make_unique<MB89352>(config) : nullptr)
77  , romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
78  , mapperMask((sram.getSize() / 0x2000) - 1)
79 {
80  // initialized mapper
81  sccEnable = false;
82  spcEnable = false;
83  writeEnable = false;
84  for (int i = 0; i < 4; ++i) {
85  mapper[i] = i;
86  }
87 }
88 
89 void ESE_SCC::powerUp(EmuTime::param time)
90 {
91  scc.powerUp(time);
92  reset(time);
93 }
94 
95 void ESE_SCC::reset(EmuTime::param time)
96 {
97  setMapperHigh(0);
98  for (int i = 0; i < 4; ++i) {
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 |= 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  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 
151 byte 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 
171 byte 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 
191 const 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 
206 void 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 4000-7FFDH)
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(word /*address*/) const
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 }
264 REGISTER_MSXDEVICE(ESE_SCC, "ESE_SCC");
265 
266 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:31
openmsx::ESE_SCC::writeMem
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
one_of.hh
openmsx::ESE_SCC::powerUp
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: ESE_SCC.cc:89
serialize.hh
openmsx::ESE_SCC::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: ESE_SCC.cc:95
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
openmsx::ESE_SCC::getWriteCacheLine
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
MSXException.hh
openmsx::SCC::reset
void reset(EmuTime::param time)
Definition: SCC.cc:172
openmsx::ESE_SCC
Definition: ESE_SCC.hh:13
openmsx::ESE_SCC::serialize
void serialize(Archive &ar, unsigned version)
Definition: ESE_SCC.cc:252
openmsx::ESE_SCC::readMem
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
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::SCC::readMem
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
openmsx::MB89352
Definition: MB89352.hh:23
ESE_SCC.hh
openmsx::ESE_SCC::getReadCacheLine
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
openmsx::ESE_SCC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: ESE_SCC.cc:171
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:740
one_of
Definition: one_of.hh:7
openmsx::SCC::powerUp
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
openmsx::ESE_SCC::ESE_SCC
ESE_SCC(const DeviceConfig &config, bool withSCSI)
Definition: ESE_SCC.cc:72
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::SRAM::write
void write(unsigned addr, byte value)
Definition: SRAM.cc:67
openmsx::MSXDevice::invalidateDeviceRWCache
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition: MSXDevice.hh:208
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:381
openmsx::SCC::peekMem
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
MB89352.hh
openmsx::XMLElement::getChildDataAsInt
int getChildDataAsInt(std::string_view childName, int defaultValue=0) const
Definition: XMLElement.cc:186
openmsx::SCC::writeMem
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:289
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::MSXDevice::getDeviceConfig
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition: MSXDevice.hh:230