openMSX
SRAM.cc
Go to the documentation of this file.
1 #include "SRAM.hh"
2 #include "DeviceConfig.hh"
3 #include "File.hh"
4 #include "FileContext.hh"
5 #include "FileException.hh"
7 #include "Reactor.hh"
8 #include "CliComm.hh"
9 #include "serialize.hh"
10 #include "openmsx.hh"
11 #include "vla.hh"
12 #include <cstring>
13 #include <memory>
14 
15 using std::string;
16 
17 namespace openmsx {
18 
19 // class SRAM
20 
21 // Like the constructor below, but doesn't create a debuggable.
22 // For use in unittests.
24  : ram(xml, size)
25  , header(nullptr) // not used
26 {
27 }
28 
29 /* Creates a SRAM that is not loaded from or saved to a file.
30  * The only reason to use this (instead of a plain Ram object) is when you
31  * dynamically need to decide whether load/save is needed.
32  */
33 SRAM::SRAM(const std::string& name, const std::string& description,
34  int size, const DeviceConfig& config_, DontLoadTag)
35  : ram(config_, name, description, size)
36  , header(nullptr) // not used
37 {
38 }
39 
40 SRAM::SRAM(const string& name, int size,
41  const DeviceConfig& config_, const char* header_, bool* loaded)
42  : schedulable(std::make_unique<SRAMSchedulable>(config_.getReactor().getRTScheduler(), *this))
43  , config(config_)
44  , ram(config, name, "sram", size)
45  , header(header_)
46 {
47  load(loaded);
48 }
49 
50 SRAM::SRAM(const string& name, const string& description, int size,
51  const DeviceConfig& config_, const char* header_, bool* loaded)
52  : schedulable(std::make_unique<SRAMSchedulable>(config_.getReactor().getRTScheduler(), *this))
53  , config(config_)
54  , ram(config, name, description, size)
55  , header(header_)
56 {
57  load(loaded);
58 }
59 
61 {
62  if (schedulable) {
63  save();
64  }
65 }
66 
67 void SRAM::write(unsigned addr, byte value)
68 {
69  if (schedulable && !schedulable->isPendingRT()) {
70  schedulable->scheduleRT(5000000); // sync to disk after 5s
71  }
72  assert(addr < getSize());
73  ram.write(addr, value);
74 }
75 
76 void SRAM::memset(unsigned addr, byte c, unsigned size)
77 {
78  if (schedulable && !schedulable->isPendingRT()) {
79  schedulable->scheduleRT(5000000); // sync to disk after 5s
80  }
81  assert((addr + size) <= getSize());
82  ::memset(ram.getWriteBackdoor() + addr, c, size);
83 }
84 
85 void SRAM::load(bool* loaded)
86 {
87  assert(config.getXML());
88  if (loaded) *loaded = false;
89  const string& filename = config.getChildData("sramname");
90  try {
91  bool headerOk = true;
92  File file(config.getFileContext().resolveCreate(filename),
94  if (header) {
95  size_t length = strlen(header);
96  VLA(char, temp, length);
97  file.read(temp, length);
98  if (memcmp(temp, header, length) != 0) {
99  headerOk = false;
100  }
101  }
102  if (headerOk) {
103  file.read(ram.getWriteBackdoor(), getSize());
104  loadedFilename = file.getURL();
105  if (loaded) *loaded = true;
106  } else {
107  config.getCliComm().printWarning(
108  "Warning no correct SRAM file: ", filename);
109  }
110  } catch (FileNotFoundException& /*e*/) {
111  config.getCliComm().printInfo(
112  "SRAM file ", filename, " not found, "
113  "assuming blank SRAM content.");
114  } catch (FileException& e) {
115  config.getCliComm().printWarning(
116  "Couldn't load SRAM ", filename,
117  " (", e.getMessage(), ").");
118  }
119 }
120 
121 void SRAM::save()
122 {
123  assert(config.getXML());
124  const string& filename = config.getChildData("sramname");
125  try {
126  File file(config.getFileContext().resolveCreate(filename),
128  if (header) {
129  int length = int(strlen(header));
130  file.write(header, length);
131  }
132  file.write(&ram[0], getSize());
133  } catch (FileException& e) {
134  config.getCliComm().printWarning(
135  "Couldn't save SRAM ", filename,
136  " (", e.getMessage(), ").");
137  }
138 }
139 
140 void SRAM::SRAMSchedulable::executeRT()
141 {
142  sram.save();
143 }
144 
145 template<typename Archive>
146 void SRAM::serialize(Archive& ar, unsigned /*version*/)
147 {
148  ar.serialize("ram", ram);
149 }
151 
152 } // namespace openmsx
T length(const vecN< N, T > &x)
Definition: gl_vec.hh:334
const std::string & getChildData(string_view name) const
Definition: DeviceConfig.cc:43
const std::string & getMessage() const &
Definition: MSXException.hh:23
byte * getWriteBackdoor()
Definition: TrackedRam.hh:52
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
SRAM(int size, const XMLElement &xml, DontLoadTag)
Definition: SRAM.cc:23
void write(unsigned addr, byte value)
Definition: SRAM.cc:67
STL namespace.
void printInfo(string_view message)
Definition: CliComm.cc:15
const FileContext & getFileContext() const
Definition: DeviceConfig.cc:9
void memset(unsigned addr, byte c, unsigned size)
Definition: SRAM.cc:76
CliComm & getCliComm() const
Definition: DeviceConfig.cc:18
size_t size(string_view utf8)
void serialize(Archive &ar, unsigned version)
Definition: SRAM.cc:146
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
unsigned getSize() const
Definition: SRAM.hh:33
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
const XMLElement * getXML() const
Definition: DeviceConfig.hh:54
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:10
void printWarning(string_view message)
Definition: CliComm.cc:20
const std::string resolveCreate(string_view filename) const
Definition: FileContext.cc:85
void write(unsigned addr, byte value)
Definition: TrackedRam.hh:38