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 "narrow.hh"
46#include "one_of.hh"
47#include "serialize.hh"
48#include "xrange.hh"
49#include <cassert>
50
51namespace openmsx {
52
53static constexpr byte SPC = 0x7F;
54
55size_t MegaSCSI::getSramSize() const
56{
57 size_t sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 1024); // size in kb
58 if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
59 throw MSXException(
60 "SRAM size for ", getName(),
61 " should be 128, 256, 512 or 1024kB and not ",
62 sramSize, "kB!");
63 }
64 return sramSize * 1024; // in bytes
65}
66
68 : MSXDevice(config)
69 , mb89352(config)
70 , sram(getName() + " SRAM", getSramSize(), config)
71 , romBlockDebug(*this, mapped, 0x4000, 0x8000, 13)
72 , blockMask(narrow<byte>((sram.size() / 0x2000) - 1))
73{
74}
75
76void MegaSCSI::reset(EmuTime::param /*time*/)
77{
78 for (auto i : xrange(4)) {
79 setSRAM(i, 0);
80 }
81 mb89352.reset(true);
82}
83
84byte MegaSCSI::readMem(word address, EmuTime::param /*time*/)
85{
86 if ((0x4000 <= address) && (address < 0xC000)) {
87 unsigned page = (address / 0x2000) - 2;
88 word addr = address & 0x1FFF;
89 if (mapped[page] == SPC) {
90 // SPC read
91 if (addr < 0x1000) {
92 // Data Register
93 return mb89352.readDREG();
94 } else {
95 return mb89352.readRegister(addr & 0x0F);
96 }
97 } else {
98 return sram[0x2000 * mapped[page] + addr];
99 }
100 } else {
101 return 0xFF;
102 }
103}
104
105byte 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
119const 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.data();
131 }
132}
133
134void 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
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.data();
167}
168
169void 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
177template<typename Archive>
178void MegaSCSI::serialize(Archive& ar, unsigned /*version*/)
179{
180 ar.serialize("SRAM", sram,
181 "MB89352", mb89352,
182 "isWriteable", isWriteable,
183 "mapped", mapped);
184}
187
188} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
uint8_t peekRegister(uint8_t reg) const
Definition MB89352.cc:711
void reset(bool scsiReset)
Definition MB89352.cc:166
void writeRegister(uint8_t reg, uint8_t value)
Definition MB89352.cc:440
uint8_t readRegister(uint8_t reg)
Definition MB89352.cc:661
void writeDREG(uint8_t value)
Definition MB89352.cc:425
uint8_t peekDREG() const
Definition MB89352.cc:702
uint8_t readDREG()
Definition MB89352.cc:407
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
static std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition MSXDevice.cc:375
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition MSXDevice.hh:214
const XMLElement & getDeviceConfig() const
Get the configuration section for this device.
Definition MSXDevice.hh:236
byte * getWriteCacheLine(word address) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition MegaSCSI.cc:154
void serialize(Archive &ar, unsigned version)
Definition MegaSCSI.cc:178
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition MegaSCSI.cc:84
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition MegaSCSI.cc:105
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
MegaSCSI(const DeviceConfig &config)
Definition MegaSCSI.cc:67
void reset(EmuTime::param time) override
This method is called on reset.
Definition MegaSCSI.cc:76
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
void write(size_t addr, byte value)
Definition SRAM.cc:64
int getChildDataAsInt(std::string_view childName, int defaultValue) const
Definition XMLElement.cc:83
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint8_t byte
8 bit unsigned integer
Definition openmsx.hh:26
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)
Definition xrange.hh:132