openMSX
MSXMegaRam.cc
Go to the documentation of this file.
1 /*
2  * Adriano Camargo Rodrigues da Cunha wrote:
3  *
4  * Any address inside a 8k page can change the page. In other
5  * words:
6  *
7  * for 4000h-5FFFh, mapping addresses are 4000h-5FFFh
8  * for 6000h-7FFFh, mapping addresses are 6000h-7FFFh
9  * for 8000h-9FFFh, mapping addresses are 8000h-9FFFh
10  * for A000h-BFFFh, mapping addresses are A000h-BFFFh
11  *
12  * If you do an IN A,(8Eh) (the value of A register is unknown and
13  * never used) you can write on MegaRAM pages, but you can't map
14  * pages. If you do an OUT (8Eh),A (the value of A register doesn't
15  * matter) you can't write to MegaRAM pages, but you can map them.
16  *
17  * Another thing: the MegaRAMs of Ademir Carchano have a mirror
18  * effect: if you map the page 0 of MegaRAM slot, you'll be
19  * acessing the same area of 8000h-BFFFh of this slot; if you map
20  * the page 3 of MegaRAM slot, you'll be acessing the same area of
21  * 4000h-7FFFh of this slot. I don't know any software that makes
22  * use of this feature, except UZIX for MSX1.
23  */
24 
25 #include "MSXMegaRam.hh"
26 #include "Rom.hh"
27 #include "Math.hh"
28 #include "serialize.hh"
29 #include <memory>
30 
31 namespace openmsx {
32 
34  : MSXDevice(config)
35  , numBlocks(config.getChildDataAsInt("size") / 8) // 8kB blocks
36  , ram(config, getName() + " RAM", "Mega-RAM", numBlocks * 0x2000)
37  , rom(config.findChild("rom")
38  ? std::make_unique<Rom>(getName() + " ROM", "Mega-RAM DiskROM", config)
39  : nullptr)
40  , romBlockDebug(*this, bank, 0x0000, 0x10000, 13, 0, 3)
41  , maskBlocks(Math::ceil2(numBlocks) - 1)
42 {
43  powerUp(EmuTime::dummy());
44 }
45 
46 MSXMegaRam::~MSXMegaRam() = default;
47 
48 void MSXMegaRam::powerUp(EmuTime::param time)
49 {
50  for (unsigned i = 0; i < 4; i++) {
51  setBank(i, 0);
52  }
53  writeMode = false;
54  ram.clear();
55  reset(time);
56 }
57 
58 void MSXMegaRam::reset(EmuTime::param /*time*/)
59 {
60  // selected banks nor writeMode does change after reset
61  romMode = rom != nullptr; // select rom mode if there is a rom
62 }
63 
64 byte MSXMegaRam::readMem(word address, EmuTime::param /*time*/)
65 {
66  return *MSXMegaRam::getReadCacheLine(address);
67 }
68 
69 const byte* MSXMegaRam::getReadCacheLine(word address) const
70 {
71  if (romMode) {
72  if (address >= 0x4000 && address <= 0xBFFF) {
73  return &(*rom)[address - 0x4000];
74  }
75  return unmappedRead;
76  }
77  unsigned block = bank[(address & 0x7FFF) / 0x2000];
78  return (block < numBlocks)
79  ? &ram[(block * 0x2000) + (address & 0x1FFF)]
80  : unmappedRead;
81 }
82 
83 void MSXMegaRam::writeMem(word address, byte value, EmuTime::param /*time*/)
84 {
85  if (byte* tmp = getWriteCacheLine(address)) {
86  *tmp = value;
87  } else {
88  assert(!romMode && !writeMode);
89  setBank((address & 0x7FFF) / 0x2000, value);
90  }
91 }
92 
93 byte* MSXMegaRam::getWriteCacheLine(word address) const
94 {
95  if (romMode) return unmappedWrite;
96  if (writeMode) {
97  unsigned block = bank[(address & 0x7FFF) / 0x2000];
98  return (block < numBlocks)
99  ? const_cast<byte*>(&ram[(block * 0x2000) + (address & 0x1FFF)])
100  : unmappedWrite;
101  } else {
102  return nullptr;
103  }
104 }
105 
106 byte MSXMegaRam::readIO(word port, EmuTime::param /*time*/)
107 {
108  switch (port & 1) {
109  case 0:
110  // enable writing
111  writeMode = true;
112  romMode = false;
113  break;
114  case 1:
115  if (rom) romMode = true;
116  break;
117  }
119  return 0xFF; // return value doesn't matter
120 }
121 
122 byte MSXMegaRam::peekIO(word /*port*/, EmuTime::param /*time*/) const
123 {
124  return 0xFF;
125 }
126 
127 void MSXMegaRam::writeIO(word port, byte /*value*/, EmuTime::param /*time*/)
128 {
129  switch (port & 1) {
130  case 0:
131  // enable switching
132  writeMode = false;
133  romMode = false;
134  break;
135  case 1:
136  if (rom) romMode = true;
137  break;
138  }
140 }
141 
142 void MSXMegaRam::setBank(byte page, byte block)
143 {
144  bank[page] = block & maskBlocks;
145  word adr = page * 0x2000;
146  invalidateDeviceRWCache(adr + 0x0000, 0x2000);
147  invalidateDeviceRWCache(adr + 0x8000, 0x2000);
148 }
149 
150 template<typename Archive>
151 void MSXMegaRam::serialize(Archive& ar, unsigned /*version*/)
152 {
153  ar.template serializeBase<MSXDevice>(*this);
154  ar.serialize("ram", ram,
155  "bank", bank,
156  "writeMode", writeMode,
157  "romMode", romMode);
158 }
160 REGISTER_MSXDEVICE(MSXMegaRam, "MegaRAM");
161 
162 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:31
serialize.hh
Rom.hh
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:293
openmsx::MSXMegaRam::peekIO
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: MSXMegaRam.cc:122
openmsx::MSXMegaRam::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MSXMegaRam.cc:58
openmsx::MSXMegaRam
Definition: MSXMegaRam.hh:13
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::MSXMegaRam::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: MSXMegaRam.cc:83
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:589
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::MSXMegaRam::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: MSXMegaRam.cc:64
openmsx::MSXMegaRam::serialize
void serialize(Archive &ar, unsigned version)
Definition: MSXMegaRam.cc:151
openmsx::Rom
Definition: Rom.hh:20
MSXMegaRam.hh
openmsx::MSXMegaRam::writeIO
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition: MSXMegaRam.cc:127
openmsx::Ram::clear
void clear(byte c=0xff)
Definition: Ram.cc:51
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::MSXMegaRam::~MSXMegaRam
~MSXMegaRam() override
openmsx::MSXMegaRam::powerUp
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: MSXMegaRam.cc:48
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:292
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::MSXMegaRam::readIO
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: MSXMegaRam.cc:106
openmsx::MSXMegaRam::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: MSXMegaRam.cc:93
openmsx::MSXMegaRam::getReadCacheLine
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: MSXMegaRam.cc:69
Math.hh
Math::ceil2
constexpr T ceil2(T x) noexcept
Returns the smallest number that is both >=a and a power of two.
Definition: Math.hh:85
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
Math
Definition: Math.hh:30
openmsx::MSXMegaRam::MSXMegaRam
MSXMegaRam(const DeviceConfig &config)
Definition: MSXMegaRam.cc:33