Some tweaks to Lua docs
[lsnes.git] / src / library / memoryspace.cpp
blobafd57b090f50730dbb89423801fd5950b9697ef2
1 #include "memoryspace.hpp"
2 #include "minmax.hpp"
3 #include "serialization.hpp"
4 #include "int24.hpp"
5 #include <algorithm>
7 namespace
9 template<typename T, bool linear> inline T internal_read(memory_space& m, uint64_t addr)
11 const int system_endian = memory_space::get_system_endian();
12 std::pair<memory_region*, uint64_t> g;
13 if(linear)
14 g = m.lookup_linear(addr);
15 else
16 g = m.lookup(addr);
17 if(!g.first || g.second + sizeof(T) > g.first->size)
18 return 0;
19 if(g.first->direct_map)
20 return serialization::read_endian<T>(g.first->direct_map + g.second, g.first->endian);
21 else {
22 T buf;
23 g.first->read(g.second, &buf, sizeof(T));
24 return serialization::read_endian<T>(&buf, g.first->endian);
28 template<typename T, bool linear> inline bool internal_write(memory_space& m, uint64_t addr, T value)
30 const int system_endian = memory_space::get_system_endian();
31 std::pair<memory_region*, uint64_t> g;
32 if(linear)
33 g = m.lookup_linear(addr);
34 else
35 g = m.lookup(addr);
36 if(!g.first || g.first->readonly || g.second + sizeof(T) > g.first->size)
37 return false;
38 if(g.first->direct_map)
39 serialization::write_endian(g.first->direct_map + g.second, value, g.first->endian);
40 else {
41 T buf;
42 serialization::write_endian(&buf, value, g.first->endian);
43 g.first->write(g.second, &buf, sizeof(T));
45 return true;
48 void read_range_r(memory_region& r, uint64_t offset, void* buffer, size_t bsize)
50 if(r.direct_map) {
51 if(offset >= r.size) {
52 memset(buffer, 0, bsize);
53 return;
55 uint64_t maxcopy = min(static_cast<uint64_t>(bsize), r.size - offset);
56 memcpy(buffer, r.direct_map + offset, maxcopy);
57 if(maxcopy < bsize)
58 memset(reinterpret_cast<char*>(buffer) + maxcopy, 0, bsize - maxcopy);
59 } else
60 r.read(offset, buffer, bsize);
63 bool write_range_r(memory_region& r, uint64_t offset, const void* buffer, size_t bsize)
65 if(r.readonly)
66 return false;
67 if(r.direct_map) {
68 if(offset >= r.size)
69 return false;
70 uint64_t maxcopy = min(static_cast<uint64_t>(bsize), r.size - offset);
71 memcpy(r.direct_map + offset, buffer, maxcopy);
72 return true;
73 } else
74 return r.write(offset, buffer, bsize);
78 memory_region::~memory_region() throw()
82 void memory_region::read(uint64_t offset, void* buffer, size_t tsize)
84 if(!direct_map || offset >= size) {
85 memset(buffer, 0, tsize);
86 return;
88 uint64_t maxcopy = min(static_cast<uint64_t>(tsize), size - offset);
89 memcpy(buffer, direct_map + offset, maxcopy);
90 if(maxcopy < tsize)
91 memset(reinterpret_cast<char*>(buffer) + maxcopy, 0, tsize - maxcopy);
94 bool memory_region::write(uint64_t offset, const void* buffer, size_t tsize)
96 if(!direct_map || readonly || offset >= size)
97 return false;
98 uint64_t maxcopy = min(static_cast<uint64_t>(tsize), size - offset);
99 memcpy(direct_map + offset, buffer, maxcopy);
100 return true;
103 std::pair<memory_region*, uint64_t> memory_space::lookup(uint64_t address)
105 umutex_class m(mutex);
106 size_t lb = 0;
107 size_t ub = u_regions.size();
108 while(lb < ub) {
109 size_t mb = (lb + ub) / 2;
110 if(u_regions[mb]->base > address) {
111 ub = mb;
112 continue;
114 if(u_regions[mb]->last_address() < address) {
115 lb = mb + 1;
116 continue;
118 return std::make_pair(u_regions[mb], address - u_regions[mb]->base);
120 return std::make_pair(reinterpret_cast<memory_region*>(NULL), 0);
123 std::pair<memory_region*, uint64_t> memory_space::lookup_linear(uint64_t linear)
125 umutex_class m(mutex);
126 if(linear >= linear_size)
127 return std::make_pair(reinterpret_cast<memory_region*>(NULL), 0);
128 size_t lb = 0;
129 size_t ub = linear_bases.size() - 1;
130 while(lb < ub) {
131 size_t mb = (lb + ub) / 2;
132 if(linear_bases[mb] > linear) {
133 ub = mb;
134 continue;
136 if(linear_bases[mb + 1] <= linear) {
137 lb = mb + 1;
138 continue;
140 return std::make_pair(u_lregions[mb], linear - linear_bases[mb]);
142 return std::make_pair(reinterpret_cast<memory_region*>(NULL), 0);
145 void memory_space::read_all_linear_memory(uint8_t* buffer)
147 auto g = lookup_linear(0);
148 size_t off = 0;
149 while(g.first) {
150 read_range_r(*g.first, g.second, buffer + off, g.first->size);
151 off += g.first->size;
152 g = lookup_linear(off);
156 #define MSR memory_space::read
157 #define MSW memory_space::write
158 #define MSRL memory_space::read_linear
159 #define MSWL memory_space::write_linear
161 template<> int8_t MSR (uint64_t address) { return internal_read<int8_t, false>(*this, address); }
162 template<> uint8_t MSR (uint64_t address) { return internal_read<uint8_t, false>(*this, address); }
163 template<> int16_t MSR (uint64_t address) { return internal_read<int16_t, false>(*this, address); }
164 template<> uint16_t MSR (uint64_t address) { return internal_read<uint16_t, false>(*this, address); }
165 template<> ss_int24_t MSR (uint64_t address) { return internal_read<ss_int24_t, false>(*this, address); }
166 template<> ss_uint24_t MSR (uint64_t address) { return internal_read<ss_uint24_t, false>(*this, address); }
167 template<> int32_t MSR (uint64_t address) { return internal_read<int32_t, false>(*this, address); }
168 template<> uint32_t MSR (uint64_t address) { return internal_read<uint32_t, false>(*this, address); }
169 template<> int64_t MSR (uint64_t address) { return internal_read<int64_t, false>(*this, address); }
170 template<> uint64_t MSR (uint64_t address) { return internal_read<uint64_t, false>(*this, address); }
171 template<> float MSR (uint64_t address) { return internal_read<float, false>(*this, address); }
172 template<> double MSR (uint64_t address) { return internal_read<double, false>(*this, address); }
173 template<> bool MSW (uint64_t a, int8_t v) { return internal_write<int8_t, false>(*this, a, v); }
174 template<> bool MSW (uint64_t a, uint8_t v) { return internal_write<uint8_t, false>(*this, a, v); }
175 template<> bool MSW (uint64_t a, int16_t v) { return internal_write<int16_t, false>(*this, a, v); }
176 template<> bool MSW (uint64_t a, uint16_t v) { return internal_write<uint16_t, false>(*this, a, v); }
177 template<> bool MSW (uint64_t a, ss_int24_t v) { return internal_write<ss_int24_t, false>(*this, a, v); }
178 template<> bool MSW (uint64_t a, ss_uint24_t v) { return internal_write<ss_uint24_t, false>(*this, a, v); }
179 template<> bool MSW (uint64_t a, int32_t v) { return internal_write<int32_t, false>(*this, a, v); }
180 template<> bool MSW (uint64_t a, uint32_t v) { return internal_write<uint32_t, false>(*this, a, v); }
181 template<> bool MSW (uint64_t a, int64_t v) { return internal_write<int64_t, false>(*this, a, v); }
182 template<> bool MSW (uint64_t a, uint64_t v) { return internal_write<uint64_t, false>(*this, a, v); }
183 template<> bool MSW (uint64_t a, float v) { return internal_write<float, false>(*this, a, v); }
184 template<> bool MSW (uint64_t a, double v) { return internal_write<double, false>(*this, a, v); }
185 template<> int8_t MSRL (uint64_t address) { return internal_read<int8_t, true>(*this, address); }
186 template<> uint8_t MSRL (uint64_t address) { return internal_read<uint8_t, true>(*this, address); }
187 template<> int16_t MSRL (uint64_t address) { return internal_read<int16_t, true>(*this, address); }
188 template<> uint16_t MSRL (uint64_t address) { return internal_read<uint16_t, true>(*this, address); }
189 template<> ss_int24_t MSRL (uint64_t address) { return internal_read<ss_int24_t, true>(*this, address); }
190 template<> ss_uint24_t MSRL (uint64_t address) { return internal_read<ss_uint24_t, true>(*this, address); }
191 template<> int32_t MSRL (uint64_t address) { return internal_read<int32_t, true>(*this, address); }
192 template<> uint32_t MSRL (uint64_t address) { return internal_read<uint32_t, true>(*this, address); }
193 template<> int64_t MSRL (uint64_t address) { return internal_read<int64_t, true>(*this, address); }
194 template<> uint64_t MSRL (uint64_t address) { return internal_read<uint64_t, true>(*this, address); }
195 template<> float MSRL (uint64_t address) { return internal_read<float, true>(*this, address); }
196 template<> double MSRL (uint64_t address) { return internal_read<double, true>(*this, address); }
197 template<> bool MSWL (uint64_t a, int8_t v) { return internal_write<int8_t, true>(*this, a, v); }
198 template<> bool MSWL (uint64_t a, uint8_t v) { return internal_write<uint8_t, true>(*this, a, v); }
199 template<> bool MSWL (uint64_t a, int16_t v) { return internal_write<int16_t, true>(*this, a, v); }
200 template<> bool MSWL (uint64_t a, uint16_t v) { return internal_write<uint16_t, true>(*this, a, v); }
201 template<> bool MSWL (uint64_t a, ss_int24_t v) { return internal_write<ss_int24_t, true>(*this, a, v); }
202 template<> bool MSWL (uint64_t a, ss_uint24_t v) { return internal_write<ss_uint24_t, true>(*this, a, v); }
203 template<> bool MSWL (uint64_t a, int32_t v) { return internal_write<int32_t, true>(*this, a, v); }
204 template<> bool MSWL (uint64_t a, uint32_t v) { return internal_write<uint32_t, true>(*this, a, v); }
205 template<> bool MSWL (uint64_t a, int64_t v) { return internal_write<int64_t, true>(*this, a, v); }
206 template<> bool MSWL (uint64_t a, uint64_t v) { return internal_write<uint64_t, true>(*this, a, v); }
207 template<> bool MSWL (uint64_t a, float v) { return internal_write<float, true>(*this, a, v); }
208 template<> bool MSWL (uint64_t a, double v) { return internal_write<double, true>(*this, a, v); }
210 void memory_space::read_range(uint64_t address, void* buffer, size_t bsize)
212 auto g = lookup(address);
213 if(!g.first) {
214 memset(buffer, 0, bsize);
215 return;
217 read_range_r(*g.first, g.second, buffer, bsize);
220 bool memory_space::write_range(uint64_t address, const void* buffer, size_t bsize)
222 auto g = lookup(address);
223 if(!g.first)
224 return false;
225 return write_range_r(*g.first, g.second, buffer, bsize);
228 void memory_space::read_range_linear(uint64_t address, void* buffer, size_t bsize)
230 auto g = lookup_linear(address);
231 if(!g.first) {
232 memset(buffer, 0, bsize);
233 return;
235 read_range_r(*g.first, g.second, buffer, bsize);
238 bool memory_space::write_range_linear(uint64_t address, const void* buffer, size_t bsize)
240 auto g = lookup_linear(address);
241 if(!g.first)
242 return false;
243 return write_range_r(*g.first, g.second, buffer, bsize);
246 memory_region* memory_space::lookup_n(size_t n)
248 umutex_class m(mutex);
249 if(n >= u_regions.size())
250 return NULL;
251 return u_regions[n];
255 std::list<memory_region*> memory_space::get_regions()
257 umutex_class m(mutex);
258 std::list<memory_region*> r;
259 for(auto i : u_regions)
260 r.push_back(i);
261 return r;
264 char* memory_space::get_physical_mapping(uint64_t base, uint64_t size)
266 uint64_t last = base + size - 1;
267 if(last < base)
268 return NULL; //Warps around.
269 auto g1 = lookup(base);
270 auto g2 = lookup(last);
271 if(g1.first != g2.first)
272 return NULL; //Not the same VMA.
273 if(!g1.first || !g1.first->direct_map)
274 return NULL; //Not mapped.
275 //OK.
276 return reinterpret_cast<char*>(g1.first->direct_map + g1.second);
279 void memory_space::set_regions(const std::list<memory_region*>& regions)
281 umutex_class m(mutex);
282 std::vector<memory_region*> n_regions;
283 std::vector<memory_region*> n_lregions;
284 std::vector<uint64_t> n_linear_bases;
285 //Calculate array sizes.
286 n_regions.resize(regions.size());
287 size_t linear_c = 0;
288 for(auto i : regions)
289 if(!i->readonly && !i->special)
290 linear_c++;
291 n_lregions.resize(linear_c);
292 n_linear_bases.resize(linear_c + 1);
294 //Fill the main array (it must be sorted!).
295 size_t i = 0;
296 for(auto j : regions)
297 n_regions[i++] = j;
298 std::sort(n_regions.begin(), n_regions.end(),
299 [](memory_region* a, memory_region* b) -> bool { return a->base < b->base; });
301 //Fill linear address arrays from the main array.
302 i = 0;
303 uint64_t base = 0;
304 for(auto j : n_regions) {
305 if(j->readonly || j->special)
306 continue;
307 n_lregions[i] = j;
308 n_linear_bases[i] = base;
309 base = base + j->size;
310 i++;
312 n_linear_bases[i] = base;
314 std::swap(u_regions, n_regions);
315 std::swap(u_lregions, n_lregions);
316 std::swap(linear_bases, n_linear_bases);
317 linear_size = base;
320 int memory_space::_get_system_endian()
322 if(sysendian)
323 return sysendian;
324 uint16_t magic = 258;
325 return (*reinterpret_cast<uint8_t*>(&magic) == 1) ? 1 : -1;
328 int memory_space::sysendian = 0;
330 memory_region_direct::memory_region_direct(const std::string& _name, uint64_t _base, int _endian,
331 unsigned char* _memory, size_t _size, bool _readonly)
333 name = _name;
334 base = _base;
335 endian = _endian;
336 direct_map = _memory;
337 size = _size;
338 readonly = _readonly;
339 special = false;
342 memory_region_direct::~memory_region_direct() throw() {}