openMSX
Ram.cc
Go to the documentation of this file.
1 #include "Ram.hh"
2 #include "DeviceConfig.hh"
3 #include "SimpleDebuggable.hh"
4 #include "XMLElement.hh"
5 #include "Base64.hh"
6 #include "HexDump.hh"
7 #include "MSXException.hh"
8 #include "one_of.hh"
9 #include "serialize.hh"
10 #include <zlib.h>
11 #include <algorithm>
12 #include <cstring>
13 #include <memory>
14 
15 using std::string;
16 
17 namespace openmsx {
18 
19 class RamDebuggable final : public SimpleDebuggable
20 {
21 public:
22  RamDebuggable(MSXMotherBoard& motherBoard, const string& name,
23  const string& description, Ram& ram);
24  byte read(unsigned address) override;
25  void write(unsigned address, byte value) override;
26 private:
27  Ram& ram;
28 };
29 
30 
31 Ram::Ram(const DeviceConfig& config, const string& name,
32  const string& description, unsigned size_)
33  : xml(*config.getXML())
34  , ram(size_)
35  , size(size_)
36  , debuggable(std::make_unique<RamDebuggable>(
37  config.getMotherBoard(), name, description, *this))
38 {
39  clear();
40 }
41 
42 Ram::Ram(const XMLElement& xml_, unsigned size_)
43  : xml(xml_)
44  , ram(size_)
45  , size(size_)
46 {
47  clear();
48 }
49 
50 Ram::~Ram() = default;
51 
52 void Ram::clear(byte c)
53 {
54  if (const XMLElement* init = xml.findChild("initialContent")) {
55  // get pattern (and decode)
56  const string& encoding = init->getAttribute("encoding");
57  size_t done = 0;
58  if (encoding == "gz-base64") {
59  auto [buf, bufSize] = Base64::decode(init->getData());
60  uLongf dstLen = getSize();
61  if (uncompress(reinterpret_cast<Bytef*>(ram.data()), &dstLen,
62  reinterpret_cast<const Bytef*>(buf.data()), uLong(bufSize))
63  != Z_OK) {
64  throw MSXException("Error while decompressing initialContent.");
65  }
66  done = dstLen;
67  } else if (encoding == one_of("hex", "base64")) {
68  auto [buf, bufSize] = (encoding == "hex")
69  ? HexDump::decode(init->getData())
70  : Base64 ::decode(init->getData());
71  if (bufSize == 0) {
72  throw MSXException("Zero-length initial pattern");
73  }
74  done = std::min(size_t(size), bufSize);
75  memcpy(ram.data(), buf.data(), done);
76  } else {
77  throw MSXException("Unsupported encoding \"", encoding,
78  "\" for initialContent");
79  }
80 
81  // repeat pattern over whole ram
82  auto left = size - done;
83  while (left) {
84  auto tmp = std::min(done, left);
85  memcpy(&ram[done], &ram[0], tmp);
86  done += tmp;
87  left -= tmp;
88  }
89  } else {
90  // no init pattern specified
91  memset(ram.data(), c, size);
92  }
93 
94 }
95 
96 const string& Ram::getName() const
97 {
98  return debuggable->getName();
99 }
100 
102  const string& name_,
103  const string& description_, Ram& ram_)
104  : SimpleDebuggable(motherBoard_, name_, description_, ram_.getSize())
105  , ram(ram_)
106 {
107 }
108 
109 byte RamDebuggable::read(unsigned address)
110 {
111  return ram[address];
112 }
113 
114 void RamDebuggable::write(unsigned address, byte value)
115 {
116  ram[address] = value;
117 }
118 
119 
120 template<typename Archive>
121 void Ram::serialize(Archive& ar, unsigned /*version*/)
122 {
123  ar.serialize_blob("ram", ram.data(), size);
124 }
126 
127 } // namespace openmsx
one_of.hh
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
serialize.hh
openmsx::Ram::serialize
void serialize(Archive &ar, unsigned version)
Definition: Ram.cc:121
openmsx::RamDebuggable::write
void write(unsigned address, byte value) override
Definition: Ram.cc:114
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
openmsx::SimpleDebuggable
Definition: SimpleDebuggable.hh:12
openmsx::Ram::getName
const std::string & getName() const
Definition: Ram.cc:96
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:10
XMLElement.hh
openmsx::RamDebuggable::RamDebuggable
RamDebuggable(MSXMotherBoard &motherBoard, const string &name, const string &description, Ram &ram)
Definition: Ram.cc:101
Ram.hh
openmsx::XMLElement::findChild
const XMLElement * findChild(std::string_view childName) const
Definition: XMLElement.cc:93
HexDump.hh
openmsx::XMLElement
Definition: XMLElement.hh:16
openmsx::Ram::~Ram
~Ram()
openmsx::RamDebuggable
Definition: Ram.cc:20
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:60
one_of
Definition: one_of.hh:7
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
SimpleDebuggable.hh
openmsx::Ram::clear
void clear(byte c=0xff)
Definition: Ram.cc:52
openmsx::Ram
Definition: Ram.hh:16
openmsx::MemBuffer::data
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:90
openmsx::RamDebuggable::read
byte read(unsigned address) override
Definition: Ram.cc:109
DeviceConfig.hh
Base64.hh
openmsx::Ram::Ram
Ram(const DeviceConfig &config, const std::string &name, const std::string &description, unsigned size)
Create Ram object with an associated debuggable.
Definition: Ram.cc:31
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::Ram::getSize
unsigned getSize() const
Definition: Ram.hh:33