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 * accessing the same area of 8000h-BFFFh of this slot; if you map
20 * the page 3 of MegaRAM slot, you'll be accessing 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 "DeviceConfig.hh"
27#include "MSXException.hh"
28#include "Rom.hh"
29#include "narrow.hh"
30#include "serialize.hh"
31#include "xrange.hh"
32#include <bit>
33#include <memory>
34
35namespace openmsx {
36
37[[nodiscard]] static unsigned getNumBlocks(const DeviceConfig& config)
38{
39 int size = config.getChildDataAsInt("size", 0); // size in kB
40 if (auto err = [&]() -> const char* {
41 if (size < 0) return "Cannot be negative.";
42 if (size > (8 * 256)) return "Cannot be larger than 2048.";
43 if ((size % 8) != 0) return "Must be a multiple of 8.";
44 return nullptr;
45 }()) {
46 throw MSXException("Invalid MegaRam size: ", size, ". ", err);
47 }
48 return size / 8;
49}
50
52 : MSXDevice(config)
53 , numBlocks(getNumBlocks(config)) // number of 8kB blocks
54 , ram(config, getName() + " RAM", "Mega-RAM", numBlocks * 0x2000)
55 , rom(config.findChild("rom")
56 ? std::make_unique<Rom>(getName() + " ROM", "Mega-RAM DiskROM", config)
57 : nullptr)
58 , romBlockDebug(*this, bank, 0x0000, 0x10000, 13, 0, 3)
59 , maskBlocks(narrow<byte>(std::bit_ceil(numBlocks) - 1))
60{
61 powerUp(EmuTime::dummy());
62}
63
64MSXMegaRam::~MSXMegaRam() = default;
65
66void MSXMegaRam::powerUp(EmuTime::param time)
67{
68 for (auto i : xrange(byte(4))) {
69 setBank(i, 0);
70 }
71 writeMode = false;
72 ram.clear();
73 reset(time);
74}
75
76void MSXMegaRam::reset(EmuTime::param /*time*/)
77{
78 // selected banks nor writeMode does change after reset
79 romMode = rom != nullptr; // select rom mode if there is a rom
80}
81
82byte MSXMegaRam::readMem(word address, EmuTime::param /*time*/)
83{
84 return *MSXMegaRam::getReadCacheLine(address);
85}
86
87const byte* MSXMegaRam::getReadCacheLine(word address) const
88{
89 if (romMode) {
90 if (address >= 0x4000 && address <= 0xBFFF) {
91 return &(*rom)[address - 0x4000];
92 }
93 return unmappedRead.data();
94 }
95 unsigned block = bank[(address & 0x7FFF) / 0x2000];
96 return (block < numBlocks)
97 ? &ram[(block * 0x2000) + (address & 0x1FFF)]
99}
100
101void MSXMegaRam::writeMem(word address, byte value, EmuTime::param /*time*/)
102{
103 if (byte* tmp = getWriteCacheLine(address)) {
104 *tmp = value;
105 } else {
106 assert(!romMode && !writeMode);
107 setBank(narrow<byte>((address & 0x7FFF) / 0x2000), value);
108 }
109}
110
112{
113 if (romMode) return unmappedWrite.data();
114 if (writeMode) {
115 unsigned block = bank[(address & 0x7FFF) / 0x2000];
116 return (block < numBlocks)
117 ? const_cast<byte*>(&ram[(block * 0x2000) + (address & 0x1FFF)])
118 : unmappedWrite.data();
119 } else {
120 return nullptr;
121 }
122}
123
124byte MSXMegaRam::readIO(word port, EmuTime::param /*time*/)
125{
126 switch (port & 1) {
127 case 0:
128 // enable writing
129 writeMode = true;
130 romMode = false;
131 break;
132 case 1:
133 if (rom) romMode = true;
134 break;
135 }
137 return 0xFF; // return value doesn't matter
138}
139
140byte MSXMegaRam::peekIO(word /*port*/, EmuTime::param /*time*/) const
141{
142 return 0xFF;
143}
144
145void MSXMegaRam::writeIO(word port, byte /*value*/, EmuTime::param /*time*/)
146{
147 switch (port & 1) {
148 case 0:
149 // enable switching
150 writeMode = false;
151 romMode = false;
152 break;
153 case 1:
154 if (rom) romMode = true;
155 break;
156 }
158}
159
160void MSXMegaRam::setBank(byte page, byte block)
161{
162 bank[page] = block & maskBlocks;
163 word adr = page * 0x2000;
164 invalidateDeviceRWCache(adr + 0x0000, 0x2000);
165 invalidateDeviceRWCache(adr + 0x8000, 0x2000);
166}
167
168template<typename Archive>
169void MSXMegaRam::serialize(Archive& ar, unsigned /*version*/)
170{
171 ar.template serializeBase<MSXDevice>(*this);
172 ar.serialize("ram", ram,
173 "bank", bank,
174 "writeMode", writeMode,
175 "romMode", romMode);
176}
179
180} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:354
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:304
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:305
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition MSXDevice.hh:212
void reset(EmuTime::param time) override
This method is called on reset.
Definition MSXMegaRam.cc:76
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition MSXMegaRam.cc:66
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition MSXMegaRam.cc:82
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.
~MSXMegaRam() override
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
void serialize(Archive &ar, unsigned version)
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
MSXMegaRam(const DeviceConfig &config)
Definition MSXMegaRam.cc:51
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.
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:87
auto data()
Definition Ram.hh:45
void clear(byte c=0xff)
Definition Ram.cc:35
This file implemented 3 utility functions:
Definition Autofire.cc:9
uint8_t byte
8 bit unsigned integer
Definition openmsx.hh:26
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
STL namespace.
size_t size(std::string_view utf8)
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)
Definition xrange.hh:132