2 #include "core/command.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/misc.hpp"
6 #include "core/rom.hpp"
7 #include "core/rrdata.hpp"
8 #include "interface/romtype.hpp"
9 #include "library/string.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
)
81 if(!our_rom
|| !our_rom
->rtype
)
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
.native_endian
? 0 : -1,
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 memory_search
* isrch
;
116 std::string
tokenize1(const std::string
& command
, const std::string
& syntax
);
117 std::pair
<std::string
, std::string
> tokenize2(const std::string
& command
, const std::string
& syntax
);
118 std::pair
<std::string
, std::string
> tokenize12(const std::string
& command
, const std::string
& syntax
);
120 unsigned char hex(char ch
)
133 case 'a': case 'A': return 10;
134 case 'b': case 'B': return 11;
135 case 'c': case 'C': return 12;
136 case 'd': case 'D': return 13;
137 case 'e': case 'E': return 14;
138 case 'f': case 'F': return 15;
140 throw std::runtime_error("Bad hex character");
143 class memorymanip_command
: public command
146 memorymanip_command(const std::string
& cmd
) throw(std::bad_alloc
)
147 : command(lsnes_cmd
, cmd
)
151 ~memorymanip_command() throw() {}
152 void invoke(const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
)
154 regex_results t
= regex("(([^ \t]+)([ \t]+([^ \t]+)([ \t]+([^ \t].*)?)?)?)?", args
);
157 has_tail
= (t
[6] != "");
160 has_value
= (secondword
!= "");
162 if(t
= regex("0x(.+)", firstword
)) {
163 if(t
[1].length() > 16)
166 for(unsigned i
= 0; i
< t
[1].length(); i
++)
167 address
= 16 * address
+ hex(t
[1][i
]);
169 address
= parse_value
<uint64_t>(firstword
);
175 if(t
= regex("0x(.+)", secondword
)) {
176 if(t
[1].length() > 16)
179 for(unsigned i
= 0; i
< t
[1].length(); i
++)
180 value
= 16 * value
+ hex(t
[1][i
]);
181 } else if(regex("-.*", secondword
)) {
182 value
= static_cast<uint64_t>(parse_value
<int64_t>(secondword
));
184 value
= parse_value
<uint64_t>(secondword
);
191 virtual void invoke2() throw(std::bad_alloc
, std::runtime_error
) = 0;
192 std::string firstword
;
193 std::string secondword
;
200 std::string _command
;
203 template<typename ret
, ret (memory_space::*_rfn
)(uint64_t addr
)>
204 class read_command
: public memorymanip_command
207 read_command(const std::string
& cmd
) throw(std::bad_alloc
)
208 : memorymanip_command(cmd
)
211 ~read_command() throw() {}
212 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
214 if(address_bad
|| has_value
|| has_tail
)
215 throw std::runtime_error("Syntax: " + _command
+ " <address>");
217 std::ostringstream x
;
218 x
<< "0x" << std::hex
<< address
<< " -> " << std::dec
219 << (lsnes_memory
.*_rfn
)(address
);
220 messages
<< x
.str() << std::endl
;
223 std::string
get_short_help() throw(std::bad_alloc
) { return "Read memory"; }
224 std::string
get_long_help() throw(std::bad_alloc
)
226 return "Syntax: " + _command
+ " <address>\n"
227 "Reads data from memory.\n";
231 template<typename arg
, int64_t low
, uint64_t high
, bool (memory_space::*_wfn
)(uint64_t addr
, arg a
)>
232 class write_command
: public memorymanip_command
235 write_command(const std::string
& cmd
)
236 throw(std::bad_alloc
)
237 : memorymanip_command(cmd
)
240 ~write_command() throw() {}
241 void invoke2() throw(std::bad_alloc
, std::runtime_error
)
243 if(address_bad
|| value_bad
|| has_tail
)
244 throw std::runtime_error("Syntax: " + _command
+ " <address> <value>");
245 int64_t value2
= static_cast<int64_t>(value
);
246 if(value2
< low
|| (value
> high
&& value2
>= 0))
247 throw std::runtime_error("Value to write out of range");
248 (lsnes_memory
.*_wfn
)(address
, value
& high
);
250 std::string
get_short_help() throw(std::bad_alloc
) { return "Write memory"; }
251 std::string
get_long_help() throw(std::bad_alloc
)
253 return "Syntax: " + _command
+ " <address> <value>\n"
254 "Writes data to memory.\n";
258 read_command
<uint8_t, &memory_space::read
<uint8_t>> ru1("read-byte");
259 read_command
<uint16_t, &memory_space::read
<uint16_t>> ru2("read-word");
260 read_command
<uint32_t, &memory_space::read
<uint32_t>> ru4("read-dword");
261 read_command
<uint64_t, &memory_space::read
<uint64_t>> ru8("read-qword");
262 read_command
<int8_t, &memory_space::read
<int8_t>> rs1("read-sbyte");
263 read_command
<int16_t, &memory_space::read
<int16_t>> rs2("read-sword");
264 read_command
<int32_t, &memory_space::read
<int32_t>> rs4("read-sdword");
265 read_command
<int64_t, &memory_space::read
<int64_t>> rs8("read-sqword");
266 write_command
<uint8_t, -128, 0xFF, &memory_space::write
<uint8_t>> w1("write-byte");
267 write_command
<uint16_t, -32768, 0xFFFF, &memory_space::write
<uint16_t>> w2("write-word");
268 write_command
<uint32_t, -2147483648LL, 0xFFFFFFFFULL
, &memory_space::write
<uint32_t>> w4("write-dword");
269 write_command
<uint64_t, -9223372036854775808LL, 0xFFFFFFFFFFFFFFFFULL
, &memory_space::write
<uint64_t>>