OXYGENHUB
◆ main openmsx / src / memory / RomPanasonic.cc
5.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "RomPanasonic.hh"
2
3
#include "PanasonicMemory.hh"
4
#include "SRAM.hh"
5
6
#include "CacheLine.hh"
7
#include "DeviceConfig.hh"
8
#include "MSXMotherBoard.hh"
9
10
#include "one_of.hh"
11
#include "serialize.hh"
12
#include "xrange.hh"
13
14
#include <algorithm>
15
#include <memory>
16
17
namespace openmsx {
18
19
const unsigned SRAM_BASE = 0x80;
20
const unsigned RAM_BASE  = 0x180;
21
22
RomPanasonic::RomPanasonic(const DeviceConfig& config, Rom&& rom_)
23
	: Rom8kBBlocks(config, std::move(rom_))
24
	, panasonicMem(getMotherBoard().getPanasonicMemory())
25
{
26
	unsigned sramSize = config.getChildDataAsInt("sramsize", 0);
27
	if (sramSize) {
28
		sram = std::make_unique<SRAM>(
29
			getName() + " SRAM", sramSize * 1024, config);
30
	}
31
32
	if (config.getChildDataAsBool("sram-mirrored", false)) {
33
		maxSRAMBank = SRAM_BASE + 8;
34
	} else {
35
		maxSRAMBank = SRAM_BASE + (sramSize / 8);
36
	}
37
38
	// Inform base class about PanasonicMemory (needed for serialization).
39
	// This relies on the order of MSXDevice instantiation, the PanasonicRam
40
	// device must be create before this one. (In the hardwareconfig.xml
41
	// we added a device-reference from this device to the PanasonicRam
42
	// device, this should protected against wrong future edits in the
43
	// config file).
44
	setExtraMemory({panasonicMem.getRamBlock(0), panasonicMem.getRamSize()});
45
46
	reset(EmuTime::dummy());
47
}
48
49
void RomPanasonic::reset(EmuTime /*time*/)
50
{
51
	control = 0;
52
	std::ranges::fill(bankSelect, 0);
53
	for (auto region : xrange(8)) {
54
		setRom(region, 0);
55
	}
56
	invalidateDeviceRCache(0x7FF0 & CacheLine::HIGH, CacheLine::SIZE);
57
}
58
59
byte RomPanasonic::peekMem(uint16_t address, EmuTime time) const
60
{
61
	if ((control & 0x04) && (0x7FF0 <= address) && (address < 0x7FF8)) {
62
		// read mapper state (lower 8 bit)
63
		return bankSelect[address & 7] & 0xFF;
64
	} else if ((control & 0x10) && (address == 0x7FF8)) {
65
		// read mapper state (9th bit)
66
		byte result = 0;
67
		for (int i = 7; i >= 0; i--) {
68
			result <<= 1;
69
			if (bankSelect[i] & 0x100) {
70
				result++;
71
			}
72
		}
73
		return result;
74
	} else if ((control & 0x08) && (address == 0x7FF9)) {
75
		// read control byte
76
		return control;
77
	} else {
78
		return Rom8kBBlocks::peekMem(address, time);
79
	}
80
}
81
82
byte RomPanasonic::readMem(uint16_t address, EmuTime time)
83
{
84
	return RomPanasonic::peekMem(address, time);
85
}
86
87
const byte* RomPanasonic::getReadCacheLine(uint16_t address) const
88
{
89
	if ((0x7FF0 & CacheLine::HIGH) == address) {
90
		// TODO check mirrored
91
		return nullptr;
92
	} else {
93
		return Rom8kBBlocks::getReadCacheLine(address);
94
	}
95
}
96
97
void RomPanasonic::writeMem(uint16_t address, byte value, EmuTime /*time*/)
98
{
99
	if ((0x6000 <= address) && (address < 0x7FF0)) {
100
		// set mapper state (lower 8 bits)
101
		auto region = (address & 0x1C00) >> 10;
102
		if (region == one_of(5, 6)) region ^= 3;
103
		auto selectedBank = bankSelect[region];
104
		auto newBank = (selectedBank & ~0xFF) | value;
105
		changeBank(region, newBank);
106
	} else if (address == 0x7FF8) {
107
		// set mapper state (9th bit)
108
		for (auto region : xrange(8)) {
109
			if (value & 1) {
110
				changeBank(region, bankSelect[region] |  0x100);
111
			} else {
112
				changeBank(region, bankSelect[region] & ~0x100);
113
			}
114
			value >>= 1;
115
		}
116
	} else if (address == 0x7FF9) {
117
		// write control byte
118
		control = value;
119
	} else {
120
		// Tested on real FS-A1GT:
121
		//  SRAM/RAM can be written to from all regions, including e.g.
122
		//  address 0x7ff0. (I didn't actually test 0xc000-0xffff).
123
		auto region = address >> 13;
124
		auto selectedBank = bankSelect[region];
125
		if (sram && (SRAM_BASE <= selectedBank) &&
126
		    (selectedBank < maxSRAMBank)) {
127
			// SRAM
128
			auto block = selectedBank - SRAM_BASE;
129
			sram->write((block * 0x2000) | (address & 0x1FFF), value);
130
		} else if (RAM_BASE <= selectedBank) {
131
			// RAM
132
			const_cast<byte*>(bankPtr[region])[address & 0x1FFF] = value;
133
		}
134
	}
135
}
136
137
byte* RomPanasonic::getWriteCacheLine(uint16_t address)
138
{
139
	if ((0x6000 <= address) && (address < 0x8000)) {
140
		// mapper select (low/high), control
141
		return nullptr;
142
	} else {
143
		auto region = address >> 13;
144
		auto selectedBank = bankSelect[region];
145
		if (sram && (SRAM_BASE <= selectedBank) &&
146
		    (selectedBank < maxSRAMBank)) {
147
			// SRAM
148
			return nullptr;
149
		} else if (RAM_BASE <= selectedBank) {
150
			// RAM
151
			return const_cast<byte*>(&bankPtr[region][address & 0x1FFF]);
152
		} else {
153
			return unmappedWrite.data();
154
		}
155
	}
156
}
157
158
void RomPanasonic::changeBank(unsigned region, unsigned bank)
159
{
160
	if (bank == bankSelect[region]) {
161
		return;
162
	}
163
	bankSelect[region] = bank;
164
165
	if (sram && (SRAM_BASE <= bank) && (bank < maxSRAMBank)) {
166
		// SRAM
167
		auto offset = (bank - SRAM_BASE) * size_t(0x2000);
168
		if (auto sramSize = sram->size(); offset >= sramSize) {
169
			offset &= (sramSize - 1);
170
		}
171
		// TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
172
		setBank(region, &sram->operator[](offset), narrow_cast<byte>(bank));
173
	} else if (panasonicMem.getRamSize() && (RAM_BASE <= bank)) {
174
		// RAM
175
		// TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
176
		setBank(region, panasonicMem.getRamBlock(bank - RAM_BASE), narrow_cast<byte>(bank));
177
	} else {
178
		// ROM
179
		setRom(region, bank);
180
	}
181
	invalidateDeviceWCache(0x2000 * region, 0x2000); // 'R' is already handled
182
	if (region == 3) {
183
		// don't pre-fill [0x7ff0, 0x7fff]
184
		invalidateDeviceRCache(0x7FF0 & CacheLine::HIGH, CacheLine::SIZE);
185
	}
186
}
187
188
template<typename Archive>
189
void RomPanasonic::serialize(Archive& ar, unsigned /*version*/)
190
{
191
	ar.template serializeBase<Rom8kBBlocks>(*this);
192
	ar.serialize("bankSelect", bankSelect,
193
	             "control",    control);
194
}
195
INSTANTIATE_SERIALIZE_METHODS(RomPanasonic);
196
REGISTER_MSXDEVICE(RomPanasonic, "RomPanasonic");
197
198
} // namespace openmsx