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#include <memory>
18
19namespace openmsx {
20
21Ram::Ram(const DeviceConfig& config, const std::string& name,
22 static_string_view description, size_t size)
23 : xml(*config.getXML())
24 , ram(size)
25 , sz(size)
26 , debuggable(std::in_place,
27 config.getMotherBoard(), name, description, *this)
28{
29 clear();
30}
31
32Ram::Ram(const XMLElement& xml_, size_t size)
33 : xml(xml_)
34 , ram(size)
35 , sz(size)
36{
37 clear();
38}
39
40void Ram::clear(byte c)
41{
42 if (const auto* init = xml.findChild("initialContent")) {
43 // get pattern (and decode)
44 auto encoding = init->getAttributeValue("encoding");
45 size_t done = 0;
46 if (encoding == "gz-base64") {
47 auto [buf, bufSize] = Base64::decode(init->getData());
48 auto dstLen = narrow<uLongf>(size());
49 if (uncompress(std::bit_cast<Bytef*>(ram.data()), &dstLen,
50 std::bit_cast<const Bytef*>(buf.data()), uLong(bufSize))
51 != Z_OK) {
52 throw MSXException("Error while decompressing initialContent.");
53 }
54 done = dstLen;
55 } else if (encoding == one_of("hex", "base64")) {
56 auto [buf, bufSize] = (encoding == "hex")
57 ? HexDump::decode(init->getData())
58 : Base64 ::decode(init->getData());
59 if (bufSize == 0) {
60 throw MSXException("Zero-length initial pattern");
61 }
62 done = std::min(size(), bufSize);
63 ranges::copy(std::span{buf.data(), done}, ram.data());
64 } else {
65 throw MSXException("Unsupported encoding \"", encoding,
66 "\" for initialContent");
67 }
68
69 // repeat pattern over whole ram
70 auto left = size() - done;
71 while (left) {
72 auto tmp = std::min(done, left);
73 ranges::copy(std::span{ram.data(), tmp}, &ram[done]);
74 done += tmp;
75 left -= tmp;
76 }
77 } else {
78 // no init pattern specified
79 ranges::fill(*this, c);
80 }
81}
82
83const std::string& Ram::getName() const
84{
85 return debuggable->getName();
86}
87
89 const std::string& name_,
90 static_string_view description_, Ram& ram_)
91 : SimpleDebuggable(motherBoard_, name_, description_, narrow<unsigned>(ram_.size()))
92 , ram(ram_)
93{
94}
95
96byte RamDebuggable::read(unsigned address)
97{
98 return ram[address];
99}
100
101void RamDebuggable::write(unsigned address, byte value)
102{
103 ram[address] = value;
104}
105
106
107template<typename Archive>
108void Ram::serialize(Archive& ar, unsigned /*version*/)
109{
110 // ar.serialize_blob("ram", std::span{*this}); // TODO error with clang-15/libc++
111 ar.serialize_blob("ram", std::span{begin(), end()});
112}
114
115} // namespace openmsx
const T * data() const
Returns pointer to the start of the memory buffer.
Definition MemBuffer.hh:81
byte read(unsigned address) override
Definition Ram.cc:96
void write(unsigned address, byte value) override
Definition Ram.cc:101
RamDebuggable(MSXMotherBoard &motherBoard, const std::string &name, static_string_view description, Ram &ram)
Definition Ram.cc:88
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:21
auto size() const
Definition Ram.hh:44
auto end()
Definition Ram.hh:49
void serialize(Archive &ar, unsigned version)
Definition Ram.cc:108
auto begin()
Definition Ram.hh:47
void clear(byte c=0xff)
Definition Ram.cc:40
const std::string & getName() const
Definition Ram.cc:83
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:305
auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:250
STL namespace.
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)