1 #include "core/command.hpp"
2 #include "core/instance.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/messages.hpp"
5 #include "core/misc.hpp"
6 #include "core/moviedata.hpp"
7 #include "core/rom.hpp"
8 #include "interface/romtype.hpp"
9 #include "library/hex.hpp"
10 #include "library/int24.hpp"
11 #include "library/memorysearch.hpp"
12 #include "library/minmax.hpp"
13 #include "library/string.hpp"
24 uint8_t lsnes_mmio_iospace_read(movie_logic
* mlogic
, uint64_t offset
)
27 if(offset
>= 0 && offset
< 8) {
29 uint64_t x
= CORE().mlogic
->get_movie().get_current_frame();
30 return x
>> (8 * (offset
& 7));
31 } else if(offset
>= 8 && offset
< 16) {
33 uint64_t x
= CORE().mlogic
->get_movie().get_frame_count();
34 return x
>> (8 * (offset
& 7));
35 } else if(offset
>= 16 && offset
< 24) {
37 uint64_t x
= CORE().mlogic
->get_movie().get_lag_frames();
38 return x
>> (8 * (offset
& 7));
39 } else if(offset
>= 24 && offset
< 32) {
41 uint64_t x
= CORE().mlogic
->get_rrdata().count();
42 return x
>> (8 * (offset
& 7));
50 void lsnes_mmio_iospace_write(movie_logic
* mlogic
, uint64_t offset
, uint8_t data
)
55 class iospace_region
: public memory_space::region
58 iospace_region(const std::string
& _name
, uint64_t _base
, uint64_t _size
, bool _special
,
59 std::function
<uint8_t(uint64_t)> _read
, std::function
<void(uint64_t, uint8_t)> _write
)
67 readonly
= (_write
== NULL
);
71 ~iospace_region() throw() {}
72 void read(uint64_t offset
, void* buffer
, size_t rsize
)
74 uint8_t* _buffer
= reinterpret_cast<uint8_t*>(buffer
);
75 for(size_t i
= 0; i
< rsize
; i
++)
76 _buffer
[i
] = Xread(offset
+ i
);
78 bool write(uint64_t offset
, const void* buffer
, size_t rsize
)
80 const uint8_t* _buffer
= reinterpret_cast<const uint8_t*>(buffer
);
81 for(size_t i
= 0; i
< rsize
; i
++)
82 Xwrite(offset
+ i
, _buffer
[i
]);
83 return offset
+ rsize
<= size
;
85 std::function
<uint8_t(uint64_t)> Xread
;
86 std::function
<void(uint64_t, uint8_t)> Xwrite
;
90 cart_mappings_refresher::cart_mappings_refresher(memory_space
& _mspace
, movie_logic
& _mlogic
, loaded_rom
& _rom
)
91 : mspace(_mspace
), mlogic(_mlogic
), rom(_rom
)
95 void cart_mappings_refresher::operator()() throw(std::bad_alloc
)
97 std::list
<memory_space::region
*> cur_regions
= mspace
.get_regions();
98 std::list
<memory_space::region
*> regions
;
99 memory_space::region
* tmp
= NULL
;
100 auto vmalist
= rom
.vma_list();
101 auto _mlogic
= &mlogic
;
103 tmp
= new iospace_region("LSNESMMIO", 0xFFFFFFFF00000000ULL
, 32, true,
104 [_mlogic
](uint64_t addr
) -> uint8_t { return lsnes_mmio_iospace_read(_mlogic
, addr
); },
105 [_mlogic
](uint64_t addr
, uint8_t value
) { lsnes_mmio_iospace_write(_mlogic
, addr
, value
); });
106 regions
.push_back(tmp
);
108 for(auto i
: vmalist
) {
110 tmp
= new iospace_region(i
.name
, i
.base
, i
.size
, i
.special
, i
.read
, i
.write
);
112 tmp
= new memory_space::region_direct(i
.name
, i
.base
, i
.endian
,
113 reinterpret_cast<uint8_t*>(i
.backing_ram
), i
.size
, i
.readonly
);
114 regions
.push_back(tmp
);
117 mspace
.set_regions(regions
);
121 for(auto i
: regions
)
125 for(auto i
: cur_regions
)
131 uint64_t parse_address(std::string addr
)
133 if(regex_match("[0-9]+|0x[0-9A-Fa-f]+", addr
)) {
134 //Absolute in mapspace.
135 return parse_value
<uint64_t>(addr
);
136 } else if(regex_match("[^+]+\\+[0-9A-Fa-f]+", addr
)) {
138 regex_results r
= regex("([^+]+)\\+([0-9A-Fa-f]+)", addr
);
139 std::string vma
= r
[1];
140 std::string _offset
= r
[2];
141 uint64_t offset
= parse_value
<uint64_t>("0x" + _offset
);
142 for(auto i
: CORE().memory
->get_regions())
144 if(offset
>= i
->size
)
145 throw std::runtime_error("Offset out of range");
146 return i
->base
+ offset
;
148 throw std::runtime_error("No such VMA");
150 throw std::runtime_error("Unknown syntax");
153 std::string
format_address(uint64_t addr
)
155 for(auto i
: CORE().memory
->get_regions())
156 if(i
->base
<= addr
&& i
->base
+ i
->size
> addr
) {
159 uint64_t t
= i
->size
;
160 while(t
> 0x10) { hcount
++; t
>>= 4; }
161 return (stringfmt() << i
->name
<< "+" << std::hex
<< std::setw(hcount
)
163 << (addr
- i
->base
)).str();
166 return hex::to(addr
);
169 class memorymanip_command
: public command::base
172 memorymanip_command(command::group
& grp
, const std::string
& cmd
) throw(std::bad_alloc
)
173 : command::base(grp
, cmd
, true)
177 ~memorymanip_command() throw() {}
178 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
180 regex_results t
= regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args
);
187 has_tail
= (t
[6] != "");
190 has_value
= (secondword
!= "");
192 address
= parse_address(firstword
);
198 valuef
= parse_value
<double>(secondword
);
204 value
= parse_value
<uint64_t>(secondword
);
210 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
211 std::string firstword
;
212 std::string secondword
;
221 std::string _command
;
224 template<typename ret
, ret (memory_space::*_rfn
)(uint64_t addr
), bool hexd
>
225 class read_command
: public memorymanip_command
228 read_command(command::group
& grp
, const std::string
& cmd
) throw(std::bad_alloc
)
229 : memorymanip_command(grp
, cmd
)
232 ~read_command() throw() {}
233 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
235 if(address_bad
|| has_value
|| has_tail
)
236 throw std::runtime_error("Syntax: " + _command
+ " <address>");
238 std::ostringstream x
;
240 x
<< format_address(address
) << " -> "
241 << hex::to((CORE().memory
->*_rfn
)(address
), true);
242 else if(sizeof(ret
) > 1)
243 x
<< format_address(address
) << " -> " << std::dec
244 << (CORE().memory
->*_rfn
)(address
);
246 x
<< format_address(address
) << " -> " << std::dec
247 << (int)(CORE().memory
->*_rfn
)(address
);
248 messages
<< x
.str() << std::endl
;
251 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
252 std::string
get_long_help() throw(std::bad_alloc
)
254 return "Syntax: " + _command
+ " <address>\n"
255 "Reads data from memory.\n";
259 template<typename arg
, int64_t low
, uint64_t high
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
260 class write_command
: public memorymanip_command
263 write_command(command::group
& grp
, const std::string
& cmd
)
264 throw(std::bad_alloc
)
265 : memorymanip_command(grp
, cmd
)
268 ~write_command() throw() {}
269 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
271 if(address_bad
|| value_bad
|| has_tail
)
272 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
273 int64_t value2
= static_cast<int64_t>(value
);
274 if(value2
< low
|| (value
> high
&& value2
>= 0))
275 throw std::runtime_error("Value to write out of range");
276 (CORE().memory
->*_wfn
)(address
, value
& high
);
278 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
279 std::string
get_long_help() throw(std::bad_alloc
)
281 return "Syntax: " + _command
+ " <address> <value>\n"
282 "Writes data to memory.\n";
286 template<typename arg
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
287 class writef_command
: public memorymanip_command
290 writef_command(command::group
& grp
, const std::string
& cmd
)
291 throw(std::bad_alloc
)
292 : memorymanip_command(grp
, cmd
)
295 ~writef_command() throw() {}
296 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
298 if(address_bad
|| !has_valuef
|| has_tail
)
299 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
300 (CORE().memory
->*_wfn
)(address
, valuef
);
302 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
303 std::string
get_long_help() throw(std::bad_alloc
)
305 return "Syntax: " + _command
+ " <address> <value>\n"
306 "Writes data to memory.\n";
310 command::byname_factory
<read_command
<uint8_t, &memory_space::read
<uint8_t>, false>> CMD_ru1(lsnes_cmds
,
312 command::byname_factory
<read_command
<uint16_t, &memory_space::read
<uint16_t>, false>> CMD_ru2(lsnes_cmds
,
314 command::byname_factory
<read_command
<ss_uint24_t
, &memory_space::read
<ss_uint24_t
>, false>> CMD_ru3(
315 lsnes_cmds
, "read-hword");
316 command::byname_factory
<read_command
<uint32_t, &memory_space::read
<uint32_t>, false>> CMD_ru4(lsnes_cmds
,
318 command::byname_factory
<read_command
<uint64_t, &memory_space::read
<uint64_t>, false>> CMD_ru8(lsnes_cmds
,
320 command::byname_factory
<read_command
<uint8_t, &memory_space::read
<uint8_t>, true>> CMD_rh1(lsnes_cmds
,
322 command::byname_factory
<read_command
<uint16_t, &memory_space::read
<uint16_t>, true>> CMD_rh2(lsnes_cmds
,
324 command::byname_factory
<read_command
<ss_uint24_t
, &memory_space::read
<ss_uint24_t
>, true>>
325 CMD_rh3(lsnes_cmds
, "read-hword-hex");
326 command::byname_factory
<read_command
<uint32_t, &memory_space::read
<uint32_t>, true>> CMD_rh4(lsnes_cmds
,
328 command::byname_factory
<read_command
<uint64_t, &memory_space::read
<uint64_t>, true>> CMD_rh8(lsnes_cmds
,
330 command::byname_factory
<read_command
<int8_t, &memory_space::read
<int8_t>, false>> CMD_rs1(lsnes_cmds
,
332 command::byname_factory
<read_command
<int16_t, &memory_space::read
<int16_t>, false>> CMD_rs2(lsnes_cmds
,
334 command::byname_factory
<read_command
<ss_int24_t
, &memory_space::read
<ss_int24_t
>, false>> CMD_rs3(lsnes_cmds
,
336 command::byname_factory
<read_command
<int32_t, &memory_space::read
<int32_t>, false>> CMD_rs4(lsnes_cmds
,
338 command::byname_factory
<read_command
<float, &memory_space::read
<float>, false>> CMD_rf4(lsnes_cmds
,
340 command::byname_factory
<read_command
<double, &memory_space::read
<double>, false>> CMD_rf8(lsnes_cmds
,
342 command::byname_factory
<write_command
<uint8_t, -128, 0xFF, &memory_space::write
<uint8_t>>> CMD_w1(lsnes_cmds
,
344 command::byname_factory
<write_command
<uint16_t, -32768, 0xFFFF, &memory_space::write
<uint16_t>>>
345 CMD_w2(lsnes_cmds
, "write-word");
346 command::byname_factory
<write_command
<ss_uint24_t
, -8388608, 0xFFFFFF, &memory_space::write
<ss_uint24_t
>>>
347 CMD_w3(lsnes_cmds
, "write-hword");
348 command::byname_factory
<write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
, &memory_space::write
<uint32_t>>>
349 CMD_w4(lsnes_cmds
, "write-dword");
350 //Just straight writing the constant would cause a warning.
351 command::byname_factory
<write_command
<uint64_t, -9223372036854775807LL-1, 0xFFFFFFFFFFFFFFFFULL
,
352 &memory_space::write
<uint64_t>>> CMD_w8(lsnes_cmds
, "write-qword");
353 command::byname_factory
<writef_command
<float, &memory_space::write
<float>>> CMD_wf4(lsnes_cmds
,
355 command::byname_factory
<writef_command
<double, &memory_space::write
<double>>> CMD_wf8(lsnes_cmds
,