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 
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  }
118  invalidateMemCache(0x0000, 0x10000);
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  }
139  invalidateMemCache(0x0000, 0x10000);
140 }
141 
142 void MSXMegaRam::setBank(byte page, byte block)
143 {
144  bank[page] = block & maskBlocks;
145  word adr = page * 0x2000;
146  invalidateMemCache(adr + 0x0000, 0x2000);
147  invalidateMemCache(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
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
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
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
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
STL namespace.
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
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
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: MSXMegaRam.cc:48
void clear(byte c=0xff)
Definition: Ram.cc:51
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
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: MSXMegaRam.cc:122
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
void serialize(Archive &ar, unsigned version)
Definition: MSXMegaRam.cc:151
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
MSXMegaRam(const DeviceConfig &config)
Definition: MSXMegaRam.cc:33
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:274
~MSXMegaRam() override
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:275
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:589
Definition: Math.hh:29
void reset(EmuTime::param time) override
This method is called on reset.
Definition: MSXMegaRam.cc:58
constexpr T ceil2(T x) noexcept
Returns the smallest number that is both >=a and a power of two.
Definition: Math.hh:84
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
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:458