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 "serialize.hh"
52 #include <memory>
53 
54 namespace openmsx {
55 
56 unsigned ESE_SCC::getSramSize(bool withSCSI) const
57 {
58  unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 256); // size in kb
59  if (sramSize != 1024 && sramSize != 512 && sramSize != 256 && sramSize != 128) {
60  throw MSXException(
61  "SRAM size for ", getName(),
62  " should be 128, 256, 512 or 1024kB and not ",
63  sramSize, "kB!");
64  }
65  if (!withSCSI && sramSize == 1024) {
66  throw MSXException("1024kB SRAM is only allowed in WAVE-SCSI!");
67  }
68  return sramSize * 1024; // in bytes
69 }
70 
71 ESE_SCC::ESE_SCC(const DeviceConfig& config, bool withSCSI)
72  : MSXDevice(config)
73  , sram(getName() + " SRAM", getSramSize(withSCSI), config)
74  , scc(getName(), config, getCurrentTime())
75  , spc(withSCSI ? std::make_unique<MB89352>(config) : nullptr)
76  , romBlockDebug(*this, mapper, 0x4000, 0x8000, 13)
77  , mapperMask((sram.getSize() / 0x2000) - 1)
78 {
79  // initialized mapper
80  sccEnable = false;
81  spcEnable = false;
82  writeEnable = false;
83  for (int i = 0; i < 4; ++i) {
84  mapper[i] = i;
85  }
86 }
87 
88 void ESE_SCC::powerUp(EmuTime::param time)
89 {
90  scc.powerUp(time);
91  reset(time);
92 }
93 
94 void ESE_SCC::reset(EmuTime::param time)
95 {
96  setMapperHigh(0);
97  for (int i = 0; i < 4; ++i) {
98  setMapperLow(i, i);
99  }
100  scc.reset(time);
101  if (spc) spc->reset(true);
102 }
103 
104 void ESE_SCC::setMapperLow(unsigned page, byte value)
105 {
106  value &= 0x3f; // use only 6bit
107  bool flush = false;
108  if (page == 2) {
109  bool newSccEnable = (value == 0x3f);
110  if (newSccEnable != sccEnable) {
111  sccEnable = newSccEnable;
112  flush = true;
113  }
114  }
115  byte newValue = value;
116  if (page == 0) newValue |= mapper[0] & 0x40;
117  newValue &= mapperMask;
118  if (mapper[page] != newValue) {
119  mapper[page] = newValue;
120  flush = true;
121  }
122  if (flush) {
123  invalidateMemCache(0x4000 + 0x2000 * page, 0x2000);
124  }
125 }
126 
127 void ESE_SCC::setMapperHigh(byte value)
128 {
129  writeEnable = (value & 0x10) != 0; // no need to flush cache
130  if (!spc) return; // only WAVE-SCSI supports 1024kB
131 
132  bool flush = false;
133  byte mapperHigh = value & 0x40;
134  bool newSpcEnable = mapperHigh && !writeEnable;
135  if (spcEnable != newSpcEnable) {
136  spcEnable = newSpcEnable;
137  flush = true;
138  }
139 
140  byte newValue = ((mapper[0] & 0x3F) | mapperHigh) & mapperMask;
141  if (mapper[0] != newValue) {
142  mapper[0] = newValue;
143  flush = true;
144  }
145  if (flush) {
146  invalidateMemCache(0x4000, 0x2000);
147  }
148 }
149 
150 byte ESE_SCC::readMem(word address, EmuTime::param time)
151 {
152  unsigned page = address / 0x2000 - 2;
153  // SPC
154  if (spcEnable && (page == 0)) {
155  address &= 0x1fff;
156  if (address < 0x1000) {
157  return spc->readDREG();
158  } else {
159  return spc->readRegister(address & 0x0f);
160  }
161  }
162  // SCC bank
163  if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
164  return scc.readMem(address & 0xff, time);
165  }
166  // SRAM read
167  return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
168 }
169 
170 byte ESE_SCC::peekMem(word address, EmuTime::param time) const
171 {
172  unsigned page = address / 0x2000 - 2;
173  // SPC
174  if (spcEnable && (page == 0)) {
175  address &= 0x1fff;
176  if (address < 0x1000) {
177  return spc->peekDREG();
178  } else {
179  return spc->peekRegister(address & 0x0f);
180  }
181  }
182  // SCC bank
183  if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
184  return scc.peekMem(address & 0xff, time);
185  }
186  // SRAM read
187  return sram[mapper[page] * 0x2000 + (address & 0x1fff)];
188 }
189 
190 const byte* ESE_SCC::getReadCacheLine(word address) const
191 {
192  unsigned page = address / 0x2000 - 2;
193  // SPC
194  if (spcEnable && (page == 0)) {
195  return nullptr;
196  }
197  // SCC bank
198  if (sccEnable && (address >= 0x9800) && (address < 0xa000)) {
199  return nullptr;
200  }
201  // SRAM read
202  return &sram[mapper[page] * 0x2000 + (address & 0x1fff)];
203 }
204 
205 void ESE_SCC::writeMem(word address, byte value, EmuTime::param time)
206 {
207  unsigned page = address / 0x2000 - 2;
208  // SPC Write
209  if (spcEnable && (page == 0)) {
210  address &= 0x1fff;
211  if (address < 0x1000) {
212  spc->writeDREG(value);
213  } else {
214  spc->writeRegister(address & 0x0f, value);
215  }
216  return;
217  }
218 
219  // SCC write
220  if (sccEnable && (0x9800 <= address) && (address < 0xa000)) {
221  scc.writeMem(address & 0xff, value, time);
222  return;
223  }
224 
225  // set mapper high control register
226  if ((address | 0x0001) == 0x7FFF) {
227  setMapperHigh(value);
228  return;
229  }
230 
231  // SRAM write (processing of 4000-7FFDH)
232  if (writeEnable && (page < 2)) {
233  sram.write(mapper[page] * 0x2000 + (address & 0x1FFF), value);
234  return;
235  }
236 
237  // Bank change
238  if (((address & 0x1800) == 0x1000)) {
239  setMapperLow(page, value);
240  return;
241  }
242 }
243 
245 {
246  return nullptr; // not cacheable
247 }
248 
249 
250 template<typename Archive>
251 void ESE_SCC::serialize(Archive& ar, unsigned /*version*/)
252 {
253  ar.template serializeBase<MSXDevice>(*this);
254  ar.serialize("sram", sram,
255  "scc", scc);
256  if (spc) ar.serialize("MB89352", *spc);
257  ar.serialize("mapper", mapper,
258  "spcEnable", spcEnable,
259  "sccEnable", sccEnable,
260  "writeEnable", writeEnable);
261 }
263 REGISTER_MSXDEVICE(ESE_SCC, "ESE_SCC");
264 
265 } // namespace openmsx
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:190
void writeMem(byte address, byte value, EmuTime::param time)
Definition: SCC.cc:289
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:150
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void write(unsigned addr, byte value)
Definition: SRAM.cc:67
STL namespace.
void reset(EmuTime::param time)
Definition: SCC.cc:172
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:374
ESE_SCC(const DeviceConfig &config, bool withSCSI)
Definition: ESE_SCC.cc:71
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
void serialize(Archive &ar, unsigned version)
Definition: ESE_SCC.cc:251
byte readMem(byte address, EmuTime::param time)
Definition: SCC.cc:192
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:133
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: ESE_SCC.cc:88
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
byte peekMem(byte address, EmuTime::param time) const
Definition: SCC.cc:205
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
int getChildDataAsInt(string_view name, int defaultValue=0) const
Definition: XMLElement.cc:187
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
void reset(EmuTime::param time) override
This method is called on reset.
Definition: ESE_SCC.cc:94
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:244
void powerUp(EmuTime::param time)
Definition: SCC.cc:140
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition: MSXDevice.hh:218
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:205
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:458
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: ESE_SCC.cc:170