openMSX
Ram.cc
Go to the documentation of this file.
1#include "Ram.hh"
2
3#include "DeviceConfig.hh"
4#include "XMLElement.hh"
5#include "MSXException.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
18namespace openmsx {
19
20Ram::Ram(const DeviceConfig& config, const std::string& name,
21 static_string_view description, size_t size)
22 : xml(*config.getXML())
23 , ram(size)
24 , debuggable(std::in_place,
25 config.getMotherBoard(), name, description, *this)
26{
27 clear();
28}
29
30Ram::Ram(const XMLElement& xml_, size_t size)
31 : xml(xml_)
32 , ram(size)
33{
34 clear();
35}
36
37void Ram::clear(byte 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 ranges::copy(buf.first(done), ram.data());
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 ranges::copy(std::span{ram.data(), tmp}, &ram[done]);
71 done += tmp;
72 left -= tmp;
73 }
74 } else {
75 // no init pattern specified
76 ranges::fill(*this, c);
77 }
78}
79
80const std::string& Ram::getName() const
81{
82 assert(debuggable);
83 return debuggable->getName();
84}
85
87 const std::string& name_,
88 static_string_view description_, Ram& ram_)
89 : SimpleDebuggable(motherBoard_, name_, description_, narrow<unsigned>(ram_.size()))
90 , ram(ram_)
91{
92}
93
94byte RamDebuggable::read(unsigned address)
95{
96 return ram[address];
97}
98
99void RamDebuggable::write(unsigned address, byte value)
100{
101 ram[address] = value;
102}
103
104
105template<typename Archive>
106void Ram::serialize(Archive& ar, unsigned /*version*/)
107{
108 // ar.serialize_blob("ram", std::span{*this}); // TODO error with clang-15/libc++
109 ar.serialize_blob("ram", std::span{begin(), end()});
110}
112
113} // namespace openmsx
const T * data() const
Returns pointer to the start of the memory buffer.
Definition MemBuffer.hh:79
byte read(unsigned address) override
Definition Ram.cc:94
void write(unsigned address, byte value) override
Definition Ram.cc:99
RamDebuggable(MSXMotherBoard &motherBoard, const std::string &name, static_string_view description, Ram &ram)
Definition Ram.cc:86
Ram(const DeviceConfig &config, const std::string &name, static_string_view description, size_t size)
Create Ram object with an associated debuggable.
Definition Ram.cc:20
auto size() const
Definition Ram.hh:44
auto end()
Definition Ram.hh:49
void serialize(Archive &ar, unsigned version)
Definition Ram.cc:106
auto begin()
Definition Ram.hh:47
void clear(byte c=0xff)
Definition Ram.cc:37
const std::string & getName() const
Definition Ram.cc:80
const XMLElement * findChild(std::string_view childName) const
Definition XMLElement.cc:21
static_string_view
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:315
constexpr auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:252
STL namespace.
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)