OXYGENHUB
◆ main openmsx / src / memory / ESE_RAM.cc
3.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 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
 *  The rest of this documentation is only about ESE-RAM specifically.
6
 *
7
 * Specification:
8
 *  SRAM(MegaROM) controller: ASCII8 type
9
 *  SRAM capacity           : 128, 256, 512 and 1024KB
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 00H-7FH (read only)
19
 *  BANK 80H-FFH (write and read. mirror of 00H-7FH)
20
 */
21
22
#include "ESE_RAM.hh"
23
#include "MSXException.hh"
24
#include "narrow.hh"
25
#include "one_of.hh"
26
#include "serialize.hh"
27
#include "xrange.hh"
28
#include <cassert>
29
30
namespace openmsx {
31
32
size_t ESE_RAM::getSramSize() const
33
{
34
	size_t sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 256); // size in kb
35
	if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
36
		throw MSXException(
37
			"SRAM size for ", getName(),
38
			" should be 128, 256, 512 or 1024kB and not ",
39
			sramSize, "kB!");
40
	}
41
	return sramSize * 1024; // in bytes
42
}
43
44
ESE_RAM::ESE_RAM(const DeviceConfig& config)
45
	: MSXDevice(config)
46
	, sram(getName() + " SRAM", getSramSize(), config)
47
	, romBlockDebug(*this, mapped, 0x4000, 0x8000, 13)
48
	, blockMask(narrow<byte>((sram.size() / 0x2000) - 1))
49
{
50
	reset(EmuTime::dummy());
51
}
52
53
void ESE_RAM::reset(EmuTime /*time*/)
54
{
55
	for (auto i : xrange(4)) {
56
		setSRAM(i, 0);
57
	}
58
}
59
60
byte ESE_RAM::readMem(uint16_t address, EmuTime /*time*/)
61
{
62
	if ((0x4000 <= address) && (address < 0xC000)) {
63
		unsigned page = (address / 8192) - 2;
64
		uint16_t addr = address & 0x1FFF;
65
		return sram[8192 * mapped[page] + addr];
66
	} else {
67
		return 0xFF;
68
	}
69
}
70
71
const byte* ESE_RAM::getReadCacheLine(uint16_t address) const
72
{
73
	if ((0x4000 <= address) && (address < 0xC000)) {
74
		unsigned page = (address / 8192) - 2;
75
		address &= 0x1FFF;
76
		return &sram[8192 * mapped[page] + address];
77
	} else {
78
		return unmappedRead.data();
79
	}
80
}
81
82
void ESE_RAM::writeMem(uint16_t address, byte value, EmuTime /*time*/)
83
{
84
	if ((0x6000 <= address) && (address < 0x8000)) {
85
		byte region = ((address >> 11) & 3);
86
		setSRAM(region, value);
87
	} else if ((0x4000 <= address) && (address < 0xC000)) {
88
		unsigned page = (address / 8192) - 2;
89
		address &= 0x1FFF;
90
		if (isWriteable[page]) {
91
			sram.write(8192 * mapped[page] + address, value);
92
		}
93
	}
94
}
95
96
byte* ESE_RAM::getWriteCacheLine(uint16_t address)
97
{
98
	if ((0x6000 <= address) && (address < 0x8000)) {
99
		return nullptr;
100
	} else if ((0x4000 <= address) && (address < 0xC000)) {
101
		unsigned page = (address / 8192) - 2;
102
		if (isWriteable[page]) {
103
			return nullptr;
104
		}
105
	}
106
	return unmappedWrite.data();
107
}
108
109
void ESE_RAM::setSRAM(unsigned region, byte block)
110
{
111
	invalidateDeviceRWCache(region * 0x2000 + 0x4000, 0x2000);
112
	assert(region < 4);
113
	isWriteable[region] = (block & 0x80) != 0;
114
	mapped[region] = block & blockMask;
115
}
116
117
template<typename Archive>
118
void ESE_RAM::serialize(Archive& ar, unsigned /*version*/)
119
{
120
	ar.template serializeBase<MSXDevice>(*this);
121
	ar.serialize("SRAM",        sram,
122
	             "isWriteable", isWriteable,
123
	             "mapped",      mapped);
124
}
125
INSTANTIATE_SERIALIZE_METHODS(ESE_RAM);
126
REGISTER_MSXDEVICE(ESE_RAM, "ESE_RAM");
127
128
} // namespace openmsx