OXYGENHUB
◆ main openmsx / src / memory / SRAM.cc
3.6 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "SRAM.hh"
2
3
#include "DeviceConfig.hh"
4
#include "File.hh"
5
#include "FileContext.hh"
6
#include "FileException.hh"
7
#include "FileNotFoundException.hh"
8
#include "MSXCliComm.hh"
9
#include "Reactor.hh"
10
11
#include "serialize.hh"
12
#include "small_buffer.hh"
13
14
#include <algorithm>
15
16
namespace openmsx {
17
18
// class SRAM
19
20
// Like the constructor below, but doesn't create a debuggable.
21
// For use in unit-tests.
22
SRAM::SRAM(size_t size, const XMLElement& xml, DontLoadTag)
23
	: ram(xml, size)
24
{
25
}
26
27
/* Creates a SRAM that is not loaded from or saved to a file.
28
 * The only reason to use this (instead of a plain Ram object) is when you
29
 * dynamically need to decide whether load/save is needed.
30
 */
31
SRAM::SRAM(const std::string& name, static_string_view description,
32
           size_t size, const DeviceConfig& config_, DontLoadTag)
33
	: ram(config_, name, description, size)
34
{
35
}
36
37
SRAM::SRAM(const std::string& name, size_t size,
38
           const DeviceConfig& config_, const char* header_, bool* loaded)
39
	: schedulable(std::in_place, config_.getReactor().getRTScheduler(), *this)
40
	, config(config_)
41
	, ram(config, name, "sram", size)
42
	, header(header_)
43
{
44
	load(loaded);
45
}
46
47
SRAM::SRAM(const std::string& name, static_string_view description, size_t size,
48
	   const DeviceConfig& config_, const char* header_, bool* loaded)
49
	: schedulable(std::in_place, config_.getReactor().getRTScheduler(), *this)
50
	, config(config_)
51
	, ram(config, name, description, size)
52
	, header(header_)
53
{
54
	load(loaded);
55
}
56
57
SRAM::~SRAM()
58
{
59
	if (schedulable && schedulable->isPendingRT()) {
60
		schedulable->cancelRT();
61
		save();
62
	}
63
}
64
65
void SRAM::write(size_t addr, uint8_t value)
66
{
67
	if (schedulable && !schedulable->isPendingRT()) {
68
		schedulable->scheduleRT(5000000); // sync to disk after 5s
69
	}
70
	assert(addr < size());
71
	ram.write(addr, value);
72
}
73
74
void SRAM::memset(size_t addr, uint8_t c, size_t aSize)
75
{
76
	if (schedulable && !schedulable->isPendingRT()) {
77
		schedulable->scheduleRT(5000000); // sync to disk after 5s
78
	}
79
	assert((addr + aSize) <= size());
80
	std::ranges::fill(ram.getWriteBackdoor().subspan(addr, aSize), c);
81
}
82
83
void SRAM::load(bool* loaded)
84
{
85
	assert(config.getXML());
86
	if (loaded) *loaded = false;
87
	const auto& filename = config.getChildData("sramname");
88
	try {
89
		bool headerOk = true;
90
		File file(config.getFileContext().resolveCreate(filename));
91
		if (header) {
92
			size_t length = strlen(header);
93
			small_buffer<char, 64> buf(uninitialized_tag{}, length);
94
			file.read(std::span{buf});
95
			headerOk = std::ranges::equal(buf, std::span{header, length});
96
		}
97
		if (headerOk) {
98
			file.read(ram.getWriteBackdoor());
99
			if (loaded) *loaded = true;
100
		} else {
101
			config.getCliComm().printWarning(
102
				"Warning no correct SRAM file: ", filename);
103
		}
104
	} catch (FileNotFoundException& /*e*/) {
105
		// SRAM file not found, assuming blank SRAM content.
106
	} catch (FileException& e) {
107
		config.getCliComm().printWarning(
108
			"Couldn't load SRAM ", filename,
109
			" (", e.getMessage(), ").");
110
	}
111
}
112
113
void SRAM::save() const
114
{
115
	assert(config.getXML());
116
	const auto& filename = config.getChildData("sramname");
117
	try {
118
		File file(config.getFileContext().resolveCreate(filename),
119
			  File::OpenMode::TRUNCATE);
120
		if (header) {
121
			auto length = strlen(header);
122
			file.write(std::span{header, length});
123
		}
124
		file.write(std::span{ram});
125
	} catch (FileException& e) {
126
		config.getCliComm().printWarning(
127
			"Couldn't save SRAM ", filename,
128
			" (", e.getMessage(), ").");
129
	}
130
}
131
132
void SRAM::SRAMSchedulable::executeRT()
133
{
134
	sram.save();
135
}
136
137
template<typename Archive>
138
void SRAM::serialize(Archive& ar, unsigned /*version*/)
139
{
140
	ar.serialize("ram", ram);
141
}
142
INSTANTIATE_SERIALIZE_METHODS(SRAM);
143
144
} // namespace openmsx