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 0x00-0x7F (read only)
19 * BANK 0x80-0xFF (write and read. mirror of 0x00-0x7F)
20 *
21 * MEGA-SCSI Bank Map:
22 * BANK 0x00-0x3F (sram read only. mirror of 0x80-0xBF)
23 * BANK 0x40-0x7E (mirror of 0x7F. Use is prohibited)
24 * BANK 0x7F (SPC)
25 * BANK 0x80-0xFF (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 0x8000 - 0xBFFF
40 * though the SPC bank is arranged in chiefly 0x4000-0x5FFF.
41 */
42
43#include "MegaSCSI.hh"
44#include "MSXException.hh"
45#include "one_of.hh"
46#include "serialize.hh"
47#include "xrange.hh"
48#include <cassert>
49
50namespace openmsx {
51
52constexpr byte SPC = 0x7F;
53
54unsigned MegaSCSI::getSramSize() const
55{
56 unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 1024); // size in kb
57 if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
58 throw MSXException(
59 "SRAM size for ", getName(),
60 " should be 128, 256, 512 or 1024kB and not ",
61 sramSize, "kB!");
62 }
63 return sramSize * 1024; // in bytes
64}
65
67 : MSXDevice(config)
68 , mb89352(config)
69 , sram(getName() + " SRAM", getSramSize(), config)
70 , romBlockDebug(*this, mapped, 0x4000, 0x8000, 13)
71 , blockMask((sram.getSize() / 0x2000) - 1)
72{
73}
74
75void MegaSCSI::reset(EmuTime::param /*time*/)
76{
77 for (auto i : xrange(4)) {
78 setSRAM(i, 0);
79 }
80 mb89352.reset(true);
81}
82
83byte MegaSCSI::readMem(word address, EmuTime::param /*time*/)
84{
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 return mb89352.readDREG();
93 } else {
94 return mb89352.readRegister(addr & 0x0F);
95 }
96 } else {
97 return sram[0x2000 * mapped[page] + addr];
98 }
99 } else {
100 return 0xFF;
101 }
102}
103
104byte MegaSCSI::peekMem(word address, EmuTime::param /*time*/) const
105{
106 if (const byte* cacheline = MegaSCSI::getReadCacheLine(address)) {
107 return *cacheline;
108 } else {
109 address &= 0x1FFF;
110 if (address < 0x1000) {
111 return mb89352.peekDREG();
112 } else {
113 return mb89352.peekRegister(address & 0x0F);
114 }
115 }
116}
117
118const byte* MegaSCSI::getReadCacheLine(word address) const
119{
120 if ((0x4000 <= address) && (address < 0xC000)) {
121 unsigned page = (address / 0x2000) - 2;
122 address &= 0x1FFF;
123 if (mapped[page] == SPC) {
124 return nullptr;
125 } else {
126 return &sram[0x2000 * mapped[page] + address];
127 }
128 } else {
129 return unmappedRead;
130 }
131}
132
133void MegaSCSI::writeMem(word address, byte value, EmuTime::param /*time*/)
134{
135 if ((0x6000 <= address) && (address < 0x8000)) {
136 byte region = ((address >> 11) & 3);
137 setSRAM(region, value);
138 } else if ((0x4000 <= address) && (address < 0xC000)) {
139 unsigned page = (address / 0x2000) - 2;
140 address &= 0x1FFF;
141 if (mapped[page] == SPC) {
142 if (address < 0x1000) {
143 mb89352.writeDREG(value);
144 } else {
145 mb89352.writeRegister(address & 0x0F, value);
146 }
147 } else if (isWriteable[page]) {
148 sram.write(0x2000 * mapped[page] + address, value);
149 }
150 }
151}
152
154{
155 if ((0x6000 <= address) && (address < 0x8000)) {
156 return nullptr;
157 } else if ((0x4000 <= address) && (address < 0xC000)) {
158 unsigned page = (address / 0x2000) - 2;
159 if (mapped[page] == SPC) {
160 return nullptr;
161 } else if (isWriteable[page]) {
162 return nullptr;
163 }
164 }
165 return unmappedWrite;
166}
167
168void MegaSCSI::setSRAM(unsigned region, byte block)
169{
170 invalidateDeviceRWCache(region * 0x2000 + 0x4000, 0x2000);
171 assert(region < 4);
172 isWriteable[region] = (block & 0x80) != 0;
173 mapped[region] = ((block & 0xC0) == 0x40) ? 0x7F : (block & blockMask);
174}
175
176template<typename Archive>
177void MegaSCSI::serialize(Archive& ar, unsigned /*version*/)
178{
179 ar.serialize("SRAM", sram,
180 "MB89352", mb89352,
181 "isWriteable", isWriteable,
182 "mapped", mapped);
183}
186
187} // namespace openmsx
Definition: one_of.hh:7
void writeDREG(byte value)
Definition: MB89352.cc:423
byte peekRegister(byte reg) const
Definition: MB89352.cc:710
void writeRegister(byte reg, byte value)
Definition: MB89352.cc:438
byte readRegister(byte reg)
Definition: MB89352.cc:661
void reset(bool scsireset)
Definition: MB89352.cc:166
byte peekDREG() const
Definition: MB89352.cc:701
byte readDREG()
Definition: MB89352.cc:405
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
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
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
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:302
void serialize(Archive &ar, unsigned version)
Definition: MegaSCSI.cc:177
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: MegaSCSI.cc:153
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: MegaSCSI.cc:83
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MegaSCSI.cc:104
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:133
MegaSCSI(const DeviceConfig &config)
Definition: MegaSCSI.cc:66
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MegaSCSI.cc:75
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:118
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")
constexpr byte SPC
Definition: MegaSCSI.cc:52
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009
constexpr auto xrange(T e)
Definition: xrange.hh:133