OXYGENHUB
◆ main openmsx / src / memory / Ram.cc
2.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "Ram.hh"
2
3
#include "DeviceConfig.hh"
4
#include "MSXException.hh"
5
#include "XMLElement.hh"
6
7
#include "Base64.hh"
8
#include "HexDump.hh"
9
#include "narrow.hh"
10
#include "one_of.hh"
11
#include "serialize.hh"
12
13
#include <zlib.h>
14
15
#include <algorithm>
16
#include <bit>
17
18
namespace openmsx {
19
20
Ram::Ram(const DeviceConfig& config, const std::string& name,
21
         static_string_view description, size_t size, bool* debugWrite)
22
	: xml(*config.getXML())
23
	, ram(size)
24
	, debuggable(std::in_place,
25
		config.getMotherBoard(), name, description, *this, debugWrite ? debugWrite : &dummyDebugWrite)
26
{
27
	clear();
28
}
29
30
Ram::Ram(const XMLElement& xml_, size_t size)
31
	: xml(xml_)
32
	, ram(size)
33
{
34
	clear();
35
}
36
37
void Ram::clear(uint8_t c)
38
{
39
	if (const auto* init = xml.findChild("initialContent")) {
40
		// get pattern (and decode)
41
		auto encoding = init->getAttributeValue("encoding");
42
		size_t done = 0;
43
		if (encoding == "gz-base64") {
44
			auto buf = Base64::decode(init->getData());
45
			auto dstLen = narrow<uLongf>(size());
46
			if (uncompress(std::bit_cast<Bytef*>(ram.data()), &dstLen,
47
			               std::bit_cast<const Bytef*>(buf.data()), uLong(buf.size()))
48
			     != Z_OK) {
49
				throw MSXException("Error while decompressing initialContent.");
50
			}
51
			done = dstLen;
52
		} else if (encoding == one_of("hex", "base64")) {
53
			auto buf = (encoding == "hex")
54
			       ? HexDump::decode(init->getData())
55
			       : Base64 ::decode(init->getData());
56
			if (buf.empty()) {
57
				throw MSXException("Zero-length initial pattern");
58
			}
59
			done = std::min(size(), buf.size());
60
			copy_to_range(buf.first(done), ram);
61
		} else {
62
			throw MSXException("Unsupported encoding \"", encoding,
63
			                   "\" for initialContent");
64
		}
65
66
		// repeat pattern over whole ram
67
		auto left = size() - done;
68
		while (left) {
69
			auto tmp = std::min(done, left);
70
			copy_to_range(std::span{ram.data(), tmp}, subspan(ram, done));
71
			done += tmp;
72
			left -= tmp;
73
		}
74
	} else {
75
		// no init pattern specified
76
		std::ranges::fill(*this, c);
77
	}
78
}
79
80
const std::string& Ram::getName() const
81
{
82
	assert(debuggable);
83
	return debuggable->getName();
84
}
85
86
RamDebuggable::RamDebuggable(MSXMotherBoard& motherBoard_,
87
                             const std::string& name_,
88
                             static_string_view description_, Ram& ram_, bool* debugWrite_)
89
	: SimpleDebuggable(motherBoard_, name_, description_, narrow<unsigned>(ram_.size()))
90
	, ram(ram_)
91
	, debugWrite(debugWrite_)
92
{
93
}
94
95
uint8_t RamDebuggable::read(unsigned address)
96
{
97
	return ram[address];
98
}
99
100
void RamDebuggable::readBlock(unsigned start, std::span<uint8_t> output)
101
{
102
	copy_to_range(std::span{ram}.subspan(start, output.size()), output);
103
}
104
105
void RamDebuggable::write(unsigned address, uint8_t value)
106
{
107
	ram[address] = value;
108
	*debugWrite = true; // for TrackedRam
109
}
110
111
112
template<typename Archive>
113
void Ram::serialize(Archive& ar, unsigned /*version*/)
114
{
115
	ar.serialize_blob("ram", std::span{*this});
116
}
117
INSTANTIATE_SERIALIZE_METHODS(Ram);
118
119
} // namespace openmsx