1 #include "core/command.hpp"
2 #include "core/memorymanip.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/misc.hpp"
5 #include "core/rom.hpp"
6 #include "core/rrdata.hpp"
7 #include "interface/romtype.hpp"
8 #include "library/string.hpp"
9 #include "library/int24.hpp"
10 #include "library/minmax.hpp"
11 #include "library/memorysearch.hpp"
20 memory_space lsnes_memory
;
24 uint8_t lsnes_mmio_iospace_handler(uint64_t offset
, uint8_t data
, bool write
)
26 if(offset
>= 0 && offset
< 8 && !write
) {
28 uint64_t x
= get_movie().get_current_frame();
29 return x
>> (8 * (offset
& 7));
30 } else if(offset
>= 8 && offset
< 16 && !write
) {
32 uint64_t x
= get_movie().get_frame_count();
33 return x
>> (8 * (offset
& 7));
34 } else if(offset
>= 16 && offset
< 24 && !write
) {
36 uint64_t x
= get_movie().get_lag_frames();
37 return x
>> (8 * (offset
& 7));
38 } else if(offset
>= 24 && offset
< 32 && !write
) {
40 uint64_t x
= rrdata
.count();
41 return x
>> (8 * (offset
& 7));
46 class iospace_region
: public memory_region
49 iospace_region(const std::string
& _name
, uint64_t _base
, uint64_t _size
,
50 uint8_t (*_iospace_rw
)(uint64_t offset
, uint8_t data
, bool write
))
55 iospace_rw
= _iospace_rw
;
61 ~iospace_region() throw() {}
62 void read(uint64_t offset
, void* buffer
, size_t rsize
)
64 uint8_t* _buffer
= reinterpret_cast<uint8_t*>(buffer
);
65 for(size_t i
= 0; i
< rsize
; i
++)
66 _buffer
[i
] = iospace_rw(offset
+ i
, 0, false);
68 bool write(uint64_t offset
, const void* buffer
, size_t rsize
)
70 const uint8_t* _buffer
= reinterpret_cast<const uint8_t*>(buffer
);
71 for(size_t i
= 0; i
< rsize
; i
++)
72 iospace_rw(offset
+ i
, _buffer
[i
], true);
73 return offset
+ rsize
<= size
;
75 uint8_t (*iospace_rw
)(uint64_t offset
, uint8_t data
, bool write
);
79 void refresh_cart_mappings() throw(std::bad_alloc
)
83 std::list
<memory_region
*> cur_regions
= lsnes_memory
.get_regions();
84 std::list
<memory_region
*> regions
;
85 memory_region
* tmp
= NULL
;
86 auto vmalist
= our_rom
.rtype
->vma_list();
88 tmp
= new iospace_region("LSNESMMIO", 0xFFFFFFFF00000000ULL
, 32, lsnes_mmio_iospace_handler
);
89 regions
.push_back(tmp
);
91 for(auto i
: vmalist
) {
93 tmp
= new iospace_region(i
.name
, i
.base
, i
.size
, i
.iospace_rw
);
95 tmp
= new memory_region_direct(i
.name
, i
.base
, i
.endian
,
96 reinterpret_cast<uint8_t*>(i
.backing_ram
), i
.size
, i
.readonly
);
97 regions
.push_back(tmp
);
100 lsnes_memory
.set_regions(regions
);
104 for(auto i
: regions
)
108 for(auto i
: cur_regions
)
114 unsigned char hex(char ch
)
127 case 'a': case 'A': return 10;
128 case 'b': case 'B': return 11;
129 case 'c': case 'C': return 12;
130 case 'd': case 'D': return 13;
131 case 'e': case 'E': return 14;
132 case 'f': case 'F': return 15;
134 throw std::runtime_error("Bad hex character");
137 class memorymanip_command
: public command
140 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
141 : command(lsnes_cmd
, cmd
)
145 ~memorymanip_command() throw() {}
146 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
148 regex_results t
= regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args
);
151 has_tail
= (t
[6] != "");
154 has_value
= (secondword
!= "");
156 if(t
= regex("0x(.+)", firstword
)) {
157 if(t
[1].length() > 16)
160 for(unsigned i
= 0; i
< t
[1].length(); i
++)
161 address
= 16 * address
+ hex(t
[1][i
]);
163 address
= parse_value
<uint64_t>(firstword
);
170 valuef
= parse_value
<double>(secondword
);
176 if(t
= regex("0x(.+)", secondword
)) {
177 if(t
[1].length() > 16)
180 for(unsigned i
= 0; i
< t
[1].length(); i
++)
181 value
= 16 * value
+ hex(t
[1][i
]);
182 } else if(regex("-.*", secondword
)) {
183 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
185 value
= parse_value
<uint64_t>(secondword
);
192 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
193 std::string firstword
;
194 std::string secondword
;
203 std::string _command
;
206 template<typename ret
, ret (memory_space::*_rfn
)(uint64_t addr
)>
207 class read_command
: public memorymanip_command
210 read_command(const std::string
& cmd
) throw(std::bad_alloc
)
211 : memorymanip_command(cmd
)
214 ~read_command() throw() {}
215 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
217 if(address_bad
|| has_value
|| has_tail
)
218 throw std::runtime_error("Syntax: " + _command
+ " <address>");
220 std::ostringstream x
;
222 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
223 << (lsnes_memory
.*_rfn
)(address
);
225 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
226 << (int)(lsnes_memory
.*_rfn
)(address
);
227 messages
<< x
.str() << std::endl
;
230 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
231 std::string
get_long_help() throw(std::bad_alloc
)
233 return "Syntax: " + _command
+ " <address>\n"
234 "Reads data from memory.\n";
238 template<typename arg
, int64_t low
, uint64_t high
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
239 class write_command
: public memorymanip_command
242 write_command(const std::string
& cmd
)
243 throw(std::bad_alloc
)
244 : memorymanip_command(cmd
)
247 ~write_command() throw() {}
248 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
250 if(address_bad
|| value_bad
|| has_tail
)
251 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
252 int64_t value2
= static_cast<int64_t>(value
);
253 if(value2
< low
|| (value
> high
&& value2
>= 0))
254 throw std::runtime_error("Value to write out of range");
255 (lsnes_memory
.*_wfn
)(address
, value
& high
);
257 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
258 std::string
get_long_help() throw(std::bad_alloc
)
260 return "Syntax: " + _command
+ " <address> <value>\n"
261 "Writes data to memory.\n";
265 template<typename arg
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
266 class writef_command
: public memorymanip_command
269 writef_command(const std::string
& cmd
)
270 throw(std::bad_alloc
)
271 : memorymanip_command(cmd
)
274 ~writef_command() throw() {}
275 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
277 if(address_bad
|| !has_valuef
|| has_tail
)
278 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
279 (lsnes_memory
.*_wfn
)(address
, valuef
);
281 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
282 std::string
get_long_help() throw(std::bad_alloc
)
284 return "Syntax: " + _command
+ " <address> <value>\n"
285 "Writes data to memory.\n";
289 read_command
<uint8_t, &memory_space::read
<uint8_t>> ru1("read-byte");
290 read_command
<uint16_t, &memory_space::read
<uint16_t>> ru2("read-word");
291 read_command
<ss_uint24_t
, &memory_space::read
<ss_uint24_t
>> ru3("read-hword");
292 read_command
<uint32_t, &memory_space::read
<uint32_t>> ru4("read-dword");
293 read_command
<uint64_t, &memory_space::read
<uint64_t>> ru8("read-qword");
294 read_command
<int8_t, &memory_space::read
<int8_t>> rs1("read-sbyte");
295 read_command
<int16_t, &memory_space::read
<int16_t>> rs2("read-sword");
296 read_command
<ss_int24_t
, &memory_space::read
<ss_int24_t
>> rs3("read-shword");
297 read_command
<int32_t, &memory_space::read
<int32_t>> rs4("read-sdword");
298 read_command
<float, &memory_space::read
<float>> rf4("read-float");
299 read_command
<double, &memory_space::read
<double>> rf8("read-double");
300 write_command
<uint8_t, -128, 0xFF, &memory_space::write
<uint8_t>> w1("write-byte");
301 write_command
<uint16_t, -32768, 0xFFFF, &memory_space::write
<uint16_t>> w2("write-word");
302 write_command
<ss_uint24_t
, -8388608, 0xFFFFFF, &memory_space::write
<ss_uint24_t
>> w3("write-hword");
303 write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
, &memory_space::write
<uint32_t>> w4("write-dword");
304 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
, &memory_space::write
<uint64_t>>
306 writef_command
<float, &memory_space::write
<float>> wf4("write-float");
307 writef_command
<double, &memory_space::write
<double>> wf8("write-double");