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"
25 uint8_t lsnes_mmio_iospace_read(movie_logic
* mlogic
, uint64_t offset
)
28 if(offset
>= 0 && offset
< 8) {
30 uint64_t x
= CORE().mlogic
->get_movie().get_current_frame();
31 return x
>> (8 * (offset
& 7));
32 } else if(offset
>= 8 && offset
< 16) {
34 uint64_t x
= CORE().mlogic
->get_movie().get_frame_count();
35 return x
>> (8 * (offset
& 7));
36 } else if(offset
>= 16 && offset
< 24) {
38 uint64_t x
= CORE().mlogic
->get_movie().get_lag_frames();
39 return x
>> (8 * (offset
& 7));
40 } else if(offset
>= 24 && offset
< 32) {
42 uint64_t x
= CORE().mlogic
->get_rrdata().count();
43 return x
>> (8 * (offset
& 7));
51 void lsnes_mmio_iospace_write(movie_logic
* mlogic
, uint64_t offset
, uint8_t data
)
56 class iospace_region
: public memory_space::region
59 iospace_region(const std::string
& _name
, uint64_t _base
, uint64_t _size
, bool _special
,
60 std::function
<uint8_t(uint64_t)> _read
, std::function
<void(uint64_t, uint8_t)> _write
)
68 readonly
= (_write
== NULL
);
72 ~iospace_region() throw() {}
73 void read(uint64_t offset
, void* buffer
, size_t rsize
)
75 uint8_t* _buffer
= reinterpret_cast<uint8_t*>(buffer
);
76 for(size_t i
= 0; i
< rsize
; i
++)
77 _buffer
[i
] = Xread(offset
+ i
);
79 bool write(uint64_t offset
, const void* buffer
, size_t rsize
)
81 const uint8_t* _buffer
= reinterpret_cast<const uint8_t*>(buffer
);
82 for(size_t i
= 0; i
< rsize
; i
++)
83 Xwrite(offset
+ i
, _buffer
[i
]);
84 return offset
+ rsize
<= size
;
86 std::function
<uint8_t(uint64_t)> Xread
;
87 std::function
<void(uint64_t, uint8_t)> Xwrite
;
91 cart_mappings_refresher::cart_mappings_refresher(memory_space
& _mspace
, movie_logic
& _mlogic
, loaded_rom
& _rom
)
92 : mspace(_mspace
), mlogic(_mlogic
), rom(_rom
)
96 void cart_mappings_refresher::operator()()
98 std::list
<memory_space::region
*> cur_regions
= mspace
.get_regions();
99 std::list
<memory_space::region
*> regions
;
100 memory_space::region
* tmp
= NULL
;
101 auto vmalist
= rom
.vma_list();
102 auto _mlogic
= &mlogic
;
104 tmp
= new iospace_region("LSNESMMIO", 0xFFFFFFFF00000000ULL
, 32, true,
105 [_mlogic
](uint64_t addr
) -> uint8_t { return lsnes_mmio_iospace_read(_mlogic
, addr
); },
106 [_mlogic
](uint64_t addr
, uint8_t value
) { lsnes_mmio_iospace_write(_mlogic
, addr
, value
); });
107 regions
.push_back(tmp
);
109 for(auto i
: vmalist
) {
111 tmp
= new iospace_region(i
.name
, i
.base
, i
.size
, i
.special
, i
.read
, i
.write
);
113 tmp
= new memory_space::region_direct(i
.name
, i
.base
, i
.endian
,
114 reinterpret_cast<uint8_t*>(i
.backing_ram
), i
.size
, i
.readonly
);
115 regions
.push_back(tmp
);
118 mspace
.set_regions(regions
);
122 for(auto i
: regions
)
126 for(auto i
: cur_regions
)
132 uint64_t parse_address(std::string addr
)
134 if(regex_match("[0-9]+|0x[0-9A-Fa-f]+", addr
)) {
135 //Absolute in mapspace.
136 return parse_value
<uint64_t>(addr
);
137 } else if(regex_match("[^+]+\\+[0-9A-Fa-f]+", addr
)) {
139 regex_results r
= regex("([^+]+)\\+([0-9A-Fa-f]+)", addr
);
140 std::string vma
= r
[1];
141 std::string _offset
= r
[2];
142 uint64_t offset
= parse_value
<uint64_t>("0x" + _offset
);
143 for(auto i
: CORE().memory
->get_regions())
145 if(offset
>= i
->size
)
146 throw std::runtime_error("Offset out of range");
147 return i
->base
+ offset
;
149 throw std::runtime_error("No such VMA");
151 throw std::runtime_error("Unknown syntax");
154 std::string
format_address(uint64_t addr
)
156 for(auto i
: CORE().memory
->get_regions())
157 if(i
->base
<= addr
&& i
->base
+ i
->size
> addr
) {
160 uint64_t t
= i
->size
;
161 while(t
> 0x10) { hcount
++; t
>>= 4; }
162 return (stringfmt() << i
->name
<< "+" << std::hex
<< std::setw(hcount
)
164 << (addr
- i
->base
)).str();
167 return hex::to(addr
);
170 class memorymanip_command
: public command::base
173 memorymanip_command(command::group
& grp
, const std::string
& cmd
)
174 : command::base(grp
, cmd
, true)
178 ~memorymanip_command() throw() {}
179 void invoke(const std::string
& args
)
181 regex_results t
= regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args
);
188 has_tail
= (t
[6] != "");
191 has_value
= (secondword
!= "");
193 address
= parse_address(firstword
);
199 valuef
= parse_value
<double>(secondword
);
205 value
= parse_value
<uint64_t>(secondword
);
211 virtual void invoke2() = 0;
212 std::string firstword
;
213 std::string secondword
;
222 std::string _command
;
225 template<typename ret
, ret (memory_space::*_rfn
)(uint64_t addr
), bool hexd
>
226 class read_command
: public memorymanip_command
229 read_command(command::group
& grp
, const std::string
& cmd
)
230 : memorymanip_command(grp
, cmd
)
233 ~read_command() throw() {}
236 if(address_bad
|| has_value
|| has_tail
)
237 throw std::runtime_error("Syntax: " + _command
+ " <address>");
239 std::ostringstream x
;
241 x
<< format_address(address
) << " -> "
242 << hex::to((CORE().memory
->*_rfn
)(address
), true);
243 else if(sizeof(ret
) > 1)
244 x
<< format_address(address
) << " -> " << std::dec
245 << (CORE().memory
->*_rfn
)(address
);
247 x
<< format_address(address
) << " -> " << std::dec
248 << (int)(CORE().memory
->*_rfn
)(address
);
249 messages
<< x
.str() << std::endl
;
252 std::string
get_short_help() { return "Read memory"; }
253 std::string
get_long_help()
255 return "Syntax: " + _command
+ " <address>\n"
256 "Reads data from memory.\n";
260 template<typename arg
, int64_t low
, uint64_t high
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
261 class write_command
: public memorymanip_command
264 write_command(command::group
& grp
, const std::string
& cmd
)
265 : memorymanip_command(grp
, cmd
)
268 ~write_command() throw() {}
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() { return "Write memory"; }
279 std::string
get_long_help()
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 : memorymanip_command(grp
, cmd
)
294 ~writef_command() throw() {}
297 if(address_bad
|| !has_valuef
|| has_tail
)
298 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
299 (CORE().memory
->*_wfn
)(address
, valuef
);
301 std::string
get_short_help() { return "Write memory"; }
302 std::string
get_long_help()
304 return "Syntax: " + _command
+ " <address> <value>\n"
305 "Writes data to memory.\n";
309 command::byname_factory
<read_command
<uint8_t, &memory_space::read
<uint8_t>, false>> CMD_ru1(lsnes_cmds
,
311 command::byname_factory
<read_command
<uint16_t, &memory_space::read
<uint16_t>, false>> CMD_ru2(lsnes_cmds
,
313 command::byname_factory
<read_command
<ss_uint24_t
, &memory_space::read
<ss_uint24_t
>, false>> CMD_ru3(
314 lsnes_cmds
, "read-hword");
315 command::byname_factory
<read_command
<uint32_t, &memory_space::read
<uint32_t>, false>> CMD_ru4(lsnes_cmds
,
317 command::byname_factory
<read_command
<uint64_t, &memory_space::read
<uint64_t>, false>> CMD_ru8(lsnes_cmds
,
319 command::byname_factory
<read_command
<uint8_t, &memory_space::read
<uint8_t>, true>> CMD_rh1(lsnes_cmds
,
321 command::byname_factory
<read_command
<uint16_t, &memory_space::read
<uint16_t>, true>> CMD_rh2(lsnes_cmds
,
323 command::byname_factory
<read_command
<ss_uint24_t
, &memory_space::read
<ss_uint24_t
>, true>>
324 CMD_rh3(lsnes_cmds
, "read-hword-hex");
325 command::byname_factory
<read_command
<uint32_t, &memory_space::read
<uint32_t>, true>> CMD_rh4(lsnes_cmds
,
327 command::byname_factory
<read_command
<uint64_t, &memory_space::read
<uint64_t>, true>> CMD_rh8(lsnes_cmds
,
329 command::byname_factory
<read_command
<int8_t, &memory_space::read
<int8_t>, false>> CMD_rs1(lsnes_cmds
,
331 command::byname_factory
<read_command
<int16_t, &memory_space::read
<int16_t>, false>> CMD_rs2(lsnes_cmds
,
333 command::byname_factory
<read_command
<ss_int24_t
, &memory_space::read
<ss_int24_t
>, false>> CMD_rs3(lsnes_cmds
,
335 command::byname_factory
<read_command
<int32_t, &memory_space::read
<int32_t>, false>> CMD_rs4(lsnes_cmds
,
337 command::byname_factory
<read_command
<float, &memory_space::read
<float>, false>> CMD_rf4(lsnes_cmds
,
339 command::byname_factory
<read_command
<double, &memory_space::read
<double>, false>> CMD_rf8(lsnes_cmds
,
341 command::byname_factory
<write_command
<uint8_t, -128, 0xFF, &memory_space::write
<uint8_t>>> CMD_w1(lsnes_cmds
,
343 command::byname_factory
<write_command
<uint16_t, -32768, 0xFFFF, &memory_space::write
<uint16_t>>>
344 CMD_w2(lsnes_cmds
, "write-word");
345 command::byname_factory
<write_command
<ss_uint24_t
, -8388608, 0xFFFFFF, &memory_space::write
<ss_uint24_t
>>>
346 CMD_w3(lsnes_cmds
, "write-hword");
347 command::byname_factory
<write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
, &memory_space::write
<uint32_t>>>
348 CMD_w4(lsnes_cmds
, "write-dword");
349 //Just straight writing the constant would cause a warning.
350 command::byname_factory
<write_command
<uint64_t, -9223372036854775807LL-1, 0xFFFFFFFFFFFFFFFFULL
,
351 &memory_space::write
<uint64_t>>> CMD_w8(lsnes_cmds
, "write-qword");
352 command::byname_factory
<writef_command
<float, &memory_space::write
<float>>> CMD_wf4(lsnes_cmds
,
354 command::byname_factory
<writef_command
<double, &memory_space::write
<double>>> CMD_wf8(lsnes_cmds
,