openMSX
MegaSCSI.cc
Go to the documentation of this file.
1 /*
2  * MEGA-SCSI and ESE-RAM cartridge:
3  * The mapping does SRAM and MB89352A(MEGA-SCSI) to ASCII8 or
4  * an interchangeable bank controller.
5  *
6  * Specification:
7  * SRAM(MegaROM) controller: ASCII8 type
8  * SRAM capacity : 128, 256, 512 and 1024KB
9  * SCSI Protocol Controller: Fujitsu MB89352A
10  *
11  * Bank changing address:
12  * bank 4(0x4000-0x5fff): 0x6000 - 0x67FF (0x6000 used)
13  * bank 6(0x6000-0x7fff): 0x6800 - 0x6FFF (0x6800 used)
14  * bank 8(0x8000-0x9fff): 0x7000 - 0x77FF (0x7000 used)
15  * bank A(0xa000-0xbfff): 0x7800 - 0x7FFF (0x7800 used)
16  *
17  * ESE-RAM Bank Map:
18  * BANK 00H-7FH (read only)
19  * BANK 80H-FFH (write and read. mirror of 00H-7FH)
20  *
21  * MEGA-SCSI Bank Map:
22  * BANK 00H-3FH (sram read only. mirror of 80H-BFH)
23  * BANK 40H-7EH (mirror of 7FH. Use is prohibited)
24  * BANK 7FH (SPC)
25  * BANK 80H-FFH (sram write and read)
26  *
27  * SPC Bank:
28  * 0x0000 - 0x0FFF :
29  * SPC Data register r/w (mirror of all 0x1FFA)
30  * 0x1000 - 0x1FEF :
31  * mirror of 0x1FF0 - 0x1FFF
32  * Use is prohibited about the image
33  * 0x1FF0 - 0x1FFE :
34  * SPC register
35  * 0x1FFF :
36  * un mapped
37  *
38  * Note:
39  * It is possible to access it by putting it out to 8000H - BFFFH
40  * though the SPC bank is arranged in chiefly 4000H-5FFF.
41  */
42 
43 #include "MegaSCSI.hh"
44 #include "MSXException.hh"
45 #include "one_of.hh"
46 #include "serialize.hh"
47 #include <cassert>
48 
49 namespace openmsx {
50 
51 constexpr byte SPC = 0x7F;
52 
53 unsigned MegaSCSI::getSramSize() const
54 {
55  unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 1024); // size in kb
56  if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
57  throw MSXException(
58  "SRAM size for ", getName(),
59  " should be 128, 256, 512 or 1024kB and not ",
60  sramSize, "kB!");
61  }
62  return sramSize * 1024; // in bytes
63 }
64 
66  : MSXDevice(config)
67  , mb89352(config)
68  , sram(getName() + " SRAM", getSramSize(), config)
69  , romBlockDebug(*this, mapped, 0x4000, 0x8000, 13)
70  , blockMask((sram.getSize() / 0x2000) - 1)
71 {
72 }
73 
74 void MegaSCSI::reset(EmuTime::param /*time*/)
75 {
76  for (int i = 0; i < 4; ++i) {
77  setSRAM(i, 0);
78  }
79  mb89352.reset(true);
80 }
81 
82 byte MegaSCSI::readMem(word address, EmuTime::param /*time*/)
83 {
84  byte result;
85  if ((0x4000 <= address) && (address < 0xC000)) {
86  unsigned page = (address / 0x2000) - 2;
87  word addr = address & 0x1FFF;
88  if (mapped[page] == SPC) {
89  // SPC read
90  if (addr < 0x1000) {
91  // Data Register
92  result = mb89352.readDREG();
93  } else {
94  result = mb89352.readRegister(addr & 0x0F);
95  }
96  } else {
97  result = sram[0x2000 * mapped[page] + addr];
98  }
99  } else {
100  result = 0xFF;
101  }
102  return result;
103 }
104 
105 byte MegaSCSI::peekMem(word address, EmuTime::param /*time*/) const
106 {
107  if (const byte* cacheline = MegaSCSI::getReadCacheLine(address)) {
108  return *cacheline;
109  } else {
110  address &= 0x1FFF;
111  if (address < 0x1000) {
112  return mb89352.peekDREG();
113  } else {
114  return mb89352.peekRegister(address & 0x0F);
115  }
116  }
117 }
118 
119 const byte* MegaSCSI::getReadCacheLine(word address) const
120 {
121  if ((0x4000 <= address) && (address < 0xC000)) {
122  unsigned page = (address / 0x2000) - 2;
123  address &= 0x1FFF;
124  if (mapped[page] == SPC) {
125  return nullptr;
126  } else {
127  return &sram[0x2000 * mapped[page] + address];
128  }
129  } else {
130  return unmappedRead;
131  }
132 }
133 
134 void MegaSCSI::writeMem(word address, byte value, EmuTime::param /*time*/)
135 {
136  if ((0x6000 <= address) && (address < 0x8000)) {
137  byte region = ((address >> 11) & 3);
138  setSRAM(region, value);
139  } else if ((0x4000 <= address) && (address < 0xC000)) {
140  unsigned page = (address / 0x2000) - 2;
141  address &= 0x1FFF;
142  if (mapped[page] == SPC) {
143  if (address < 0x1000) {
144  mb89352.writeDREG(value);
145  } else {
146  mb89352.writeRegister(address & 0x0F, value);
147  }
148  } else if (isWriteable[page]) {
149  sram.write(0x2000 * mapped[page] + address, value);
150  }
151  }
152 }
153 
154 byte* MegaSCSI::getWriteCacheLine(word address) const
155 {
156  if ((0x6000 <= address) && (address < 0x8000)) {
157  return nullptr;
158  } else if ((0x4000 <= address) && (address < 0xC000)) {
159  unsigned page = (address / 0x2000) - 2;
160  if (mapped[page] == SPC) {
161  return nullptr;
162  } else if (isWriteable[page]) {
163  return nullptr;
164  }
165  }
166  return unmappedWrite;
167 }
168 
169 void MegaSCSI::setSRAM(unsigned region, byte block)
170 {
171  invalidateDeviceRWCache(region * 0x2000 + 0x4000, 0x2000);
172  assert(region < 4);
173  isWriteable[region] = (block & 0x80) != 0;
174  mapped[region] = ((block & 0xC0) == 0x40) ? 0x7F : (block & blockMask);
175 }
176 
177 template<typename Archive>
178 void MegaSCSI::serialize(Archive& ar, unsigned /*version*/)
179 {
180  ar.serialize("SRAM", sram,
181  "MB89352", mb89352,
182  "isWriteable", isWriteable,
183  "mapped", mapped);
184 }
186 REGISTER_MSXDEVICE(MegaSCSI, "MegaSCSI");
187 
188 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:31
one_of.hh
openmsx::MegaSCSI::MegaSCSI
MegaSCSI(const DeviceConfig &config)
Definition: MegaSCSI.cc:65
openmsx::MegaSCSI::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MegaSCSI.cc:105
serialize.hh
openmsx::MB89352::peekDREG
byte peekDREG() const
Definition: MB89352.cc:704
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
openmsx::MB89352::peekRegister
byte peekRegister(byte reg) const
Definition: MB89352.cc:713
MSXException.hh
openmsx::SPC
constexpr byte SPC
Definition: MegaSCSI.cc:51
openmsx::MSXException
Definition: MSXException.hh:9
openmsx::MB89352::reset
void reset(bool scsireset)
Definition: MB89352.cc:169
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::MB89352::writeRegister
void writeRegister(byte reg, byte value)
Definition: MB89352.cc:441
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::MegaSCSI::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: MegaSCSI.cc:82
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::MB89352::writeDREG
void writeDREG(byte value)
Definition: MB89352.cc:426
openmsx::SRAM::write
void write(unsigned addr, byte value)
Definition: SRAM.cc:67
openmsx::MB89352::readDREG
byte readDREG()
Definition: MB89352.cc:408
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::MegaSCSI::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: MegaSCSI.cc:154
openmsx::MegaSCSI::getReadCacheLine
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: MegaSCSI.cc:119
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:381
openmsx::MB89352::readRegister
byte readRegister(byte reg)
Definition: MB89352.cc:664
openmsx::MegaSCSI
Definition: MegaSCSI.hh:11
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
MegaSCSI.hh
openmsx::XMLElement::getChildDataAsInt
int getChildDataAsInt(std::string_view childName, int defaultValue=0) const
Definition: XMLElement.cc:186
openmsx::MegaSCSI::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: MegaSCSI.cc:134
openmsx::MegaSCSI::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MegaSCSI.cc:74
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::MegaSCSI::serialize
void serialize(Archive &ar, unsigned version)
Definition: MegaSCSI.cc:178
openmsx::MSXDevice::getDeviceConfig
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition: MSXDevice.hh:230