Lua: memory.readregion / memory.writeregion
This commit is contained in:
parent
1e1cd1026b
commit
4ca6e1df02
5 changed files with 350 additions and 31 deletions
|
@ -78,6 +78,19 @@ std::vector<struct memory_region> get_regions() throw(std::bad_alloc);
|
|||
*/
|
||||
uint8_t memory_read_byte(uint64_t addr) throw();
|
||||
|
||||
/**
|
||||
* \brief Read bytes from memory
|
||||
*
|
||||
* This function read table of bytes from memory.
|
||||
*
|
||||
* \param addr The address to read.
|
||||
* \param size The size to read.
|
||||
* \param data The place to store values read.
|
||||
*
|
||||
* \note This does not cross VMAs.
|
||||
*/
|
||||
void memory_read_bytes(uint64_t addr, uint64_t size, char* data) throw();
|
||||
|
||||
/**
|
||||
* \brief Read word from memory
|
||||
*
|
||||
|
@ -119,6 +132,19 @@ uint64_t memory_read_qword(uint64_t addr) throw();
|
|||
*/
|
||||
bool memory_write_byte(uint64_t addr, uint8_t data) throw();
|
||||
|
||||
/**
|
||||
* \brief Write bytes to memory
|
||||
*
|
||||
* This function writes table of bytes to memory.
|
||||
*
|
||||
* \param addr The address to write.
|
||||
* \param size The size of area to write.
|
||||
* \param data The value to write.
|
||||
*
|
||||
* \note This does not cross VMAs.
|
||||
*/
|
||||
void memory_write_bytes(uint64_t addr, uint64_t size, const char* data) throw();
|
||||
|
||||
/**
|
||||
* \brief Write word to memory
|
||||
*
|
||||
|
|
152
manual.lyx
152
manual.lyx
|
@ -2703,6 +2703,14 @@ Perform hue rotation of color <color> (default bright red), by <step> steps.
|
|||
If <steps> is negative, the rotation will be counterclockwise.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
gui.screenshot(string filename)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Saves a screenshot into specified file.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
table input
|
||||
\end_layout
|
||||
|
@ -2846,7 +2854,7 @@ cal_tolerance: Dead zone tolerance.
|
|||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.keyhook(key, state)
|
||||
input.keyhook(string key, boolean state)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
|
@ -2854,6 +2862,49 @@ Requests that keyhook events to be sent for key (state=true) or not sent
|
|||
(state=false).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.joyget(number controller)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Returns table for current controls for specified controller.
|
||||
The names of fields vary by controller type.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
The buttons have the same name as those are referred to in other contexts
|
||||
in the emulator
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
The analog axes are
|
||||
\begin_inset Quotes eld
|
||||
\end_inset
|
||||
|
||||
xaxis
|
||||
\begin_inset Quotes erd
|
||||
\end_inset
|
||||
|
||||
and
|
||||
\begin_inset Quotes eld
|
||||
\end_inset
|
||||
|
||||
yaxis
|
||||
\begin_inset Quotes erd
|
||||
\end_inset
|
||||
|
||||
.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.joyset(number controller, table controls)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set the the state of specified controller to values specified in specified
|
||||
table.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
Table subtitle
|
||||
\end_layout
|
||||
|
@ -3098,6 +3149,14 @@ movie.readonly()
|
|||
Return true if in readonly mode, false if in readwrite.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
movie.rerecords()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Returns the current value of rerecord count.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
movie.set_readwrite()
|
||||
\end_layout
|
||||
|
@ -3124,6 +3183,14 @@ Read specifed subframe in specified frame and return data as array (100
|
|||
elements, numbered 0-99 currently).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
movie.read_rtc()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Returns the current value of the RTC as a pair (second, subsecond).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
movie.unsafe_rewind([UNSAFEREWIND state])
|
||||
\end_layout
|
||||
|
@ -3387,6 +3454,89 @@ Hash specified number of bytes starting from specified address and return
|
|||
the SHA-256.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
memory.hash_state()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Hash the current system state.
|
||||
Mainly useful for debugging savestates.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
memory.readregion(number base, number size)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Read a region of memory.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Warning: If the region crosses VMA boundary, the results are undefined.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
memory.writeregion(number base, number size, table data)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Write a region of memory.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Warning: If the region crosses VMA boundary, the results are undefined.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
Table subtitle
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Contains functions for manipulating subtitles.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
subtitle.byindex(number index)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Get (basetime, length) pair of specified subtitle index or nothing if index
|
||||
isn't valid.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
subtitle.get(number basetime, number length)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Read the specified subtitle.
|
||||
Returns
|
||||
\begin_inset Quotes eld
|
||||
\end_inset
|
||||
|
||||
|
||||
\begin_inset Quotes erd
|
||||
\end_inset
|
||||
|
||||
if the subtitle does not exist.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
subtitle.set(number basetime, number length, string content)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set the specified subtitle.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
subtitle.deltete(number basetime, number length)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Delete the specified subtitle.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
Table _SYSTEM
|
||||
\end_layout
|
||||
|
|
130
manual.txt
130
manual.txt
|
@ -1351,6 +1351,10 @@ absolute value of <steps>.
|
|||
|
||||
If <steps> is negative, the rotation will be counterclockwise.
|
||||
|
||||
8.3.28 gui.screenshot(string filename)
|
||||
|
||||
Saves a screenshot into specified file.
|
||||
|
||||
8.4 table input
|
||||
|
||||
Input handling. Only available in on_input callback.
|
||||
|
@ -1429,11 +1433,26 @@ table has the following fields:
|
|||
• cal_tolerance: Dead zone tolerance. Only meaningful with axis
|
||||
and pressure types.
|
||||
|
||||
8.4.8 input.keyhook(key, state)
|
||||
8.4.8 input.keyhook(string key, boolean state)
|
||||
|
||||
Requests that keyhook events to be sent for key (state=true) or
|
||||
not sent (state=false).
|
||||
|
||||
8.4.9 input.joyget(number controller)
|
||||
|
||||
Returns table for current controls for specified controller. The
|
||||
names of fields vary by controller type.
|
||||
|
||||
• The buttons have the same name as those are referred to in
|
||||
other contexts in the emulator
|
||||
|
||||
• The analog axes are “xaxis” and “yaxis”.
|
||||
|
||||
8.4.10 input.joyset(number controller, table controls)
|
||||
|
||||
Set the the state of specified controller to values specified in
|
||||
specified table.
|
||||
|
||||
8.5 Table subtitle
|
||||
|
||||
Subtitle handling
|
||||
|
@ -1566,21 +1585,30 @@ Return number of frames in movie.
|
|||
|
||||
Return true if in readonly mode, false if in readwrite.
|
||||
|
||||
8.7.4 movie.set_readwrite()
|
||||
8.7.4 movie.rerecords()
|
||||
|
||||
Returns the current value of rerecord count.
|
||||
|
||||
8.7.5 movie.set_readwrite()
|
||||
|
||||
Set readwrite mode (does not cause on_readwrite callback).
|
||||
|
||||
8.7.5 movie.frame_subframes(number frame)
|
||||
8.7.6 movie.frame_subframes(number frame)
|
||||
|
||||
Count number of subframes in specified frame (frame numbers are
|
||||
1-based) and return that.
|
||||
|
||||
8.7.6 movie.read_subframe(number frame, number subframe)
|
||||
8.7.7 movie.read_subframe(number frame, number subframe)
|
||||
|
||||
Read specifed subframe in specified frame and return data as
|
||||
array (100 elements, numbered 0-99 currently).
|
||||
|
||||
8.7.7 movie.unsafe_rewind([UNSAFEREWIND state])
|
||||
8.7.8 movie.read_rtc()
|
||||
|
||||
Returns the current value of the RTC as a pair (second,
|
||||
subsecond).
|
||||
|
||||
8.7.9 movie.unsafe_rewind([UNSAFEREWIND state])
|
||||
|
||||
Start setting point for unsafe rewind or jump to point of unsafe
|
||||
rewind.
|
||||
|
@ -1725,16 +1753,58 @@ complement) to specified address (as a quadword).
|
|||
Hash specified number of bytes starting from specified address
|
||||
and return the SHA-256.
|
||||
|
||||
8.10 Table _SYSTEM
|
||||
8.9.17 memory.hash_state()
|
||||
|
||||
Hash the current system state. Mainly useful for debugging
|
||||
savestates.
|
||||
|
||||
8.9.18 memory.readregion(number base, number size)
|
||||
|
||||
Read a region of memory.
|
||||
|
||||
• Warning: If the region crosses VMA boundary, the results are
|
||||
undefined.
|
||||
|
||||
8.9.19 memory.writeregion(number base, number size, table data)
|
||||
|
||||
Write a region of memory.
|
||||
|
||||
• Warning: If the region crosses VMA boundary, the results are
|
||||
undefined.
|
||||
|
||||
8.10 Table subtitle
|
||||
|
||||
Contains functions for manipulating subtitles.
|
||||
|
||||
8.10.1 subtitle.byindex(number index)
|
||||
|
||||
Get (basetime, length) pair of specified subtitle index or
|
||||
nothing if index isn't valid.
|
||||
|
||||
8.10.2 subtitle.get(number basetime, number length)
|
||||
|
||||
Read the specified subtitle. Returns “” if the subtitle does not
|
||||
exist.
|
||||
|
||||
8.10.3 subtitle.set(number basetime, number length, string
|
||||
content)
|
||||
|
||||
Set the specified subtitle.
|
||||
|
||||
8.10.4 subtitle.deltete(number basetime, number length)
|
||||
|
||||
Delete the specified subtitle.
|
||||
|
||||
8.11 Table _SYSTEM
|
||||
|
||||
Contains copy of global variables from time of Lua
|
||||
initialization. Non-writeable.
|
||||
|
||||
8.11 Callbacks
|
||||
8.12 Callbacks
|
||||
|
||||
Various callbacks to Lua that can occur.
|
||||
|
||||
8.11.1 Callback: on_paint(bool not_synth)
|
||||
8.12.1 Callback: on_paint(bool not_synth)
|
||||
|
||||
Called when screen is being painted. Any gui.* calls requiring
|
||||
graphic context draw on the screen.
|
||||
|
@ -1742,80 +1812,80 @@ graphic context draw on the screen.
|
|||
not_synth is true if this hook is being called in response to
|
||||
received frame, false otherwise.
|
||||
|
||||
8.11.2 Callback: on_video()
|
||||
8.12.2 Callback: on_video()
|
||||
|
||||
Called when video dump frame is being painted. Any gui.* calls
|
||||
requiring graphic context draw on the video.
|
||||
|
||||
8.11.3 Callback: on_frame_emulated()
|
||||
8.12.3 Callback: on_frame_emulated()
|
||||
|
||||
Called when emulating frame has completed and
|
||||
on_paint()/on_video() calls are about to be issued.
|
||||
|
||||
8.11.4 Callback: on_frame()
|
||||
8.12.4 Callback: on_frame()
|
||||
|
||||
Called on each starting whole frame.
|
||||
|
||||
8.11.5 Callback: on_startup()
|
||||
8.12.5 Callback: on_startup()
|
||||
|
||||
Called when the emulator is starting (lsnes.rc and --run files
|
||||
has been run).
|
||||
|
||||
8.11.6 Callback: on_rewind()
|
||||
8.12.6 Callback: on_rewind()
|
||||
|
||||
Called when rewind movie to beginning has completed.
|
||||
|
||||
8.11.7 Callback: on_pre_load(string name)
|
||||
8.12.7 Callback: on_pre_load(string name)
|
||||
|
||||
Called just before savestate/movie load occurs (note: loads are
|
||||
always delayed, so this occurs even when load was initiated by
|
||||
lua).
|
||||
|
||||
8.11.8 Callback: on_err_load(string name)
|
||||
8.12.8 Callback: on_err_load(string name)
|
||||
|
||||
Called if loadstate goes wrong.
|
||||
|
||||
8.11.9 Callback: on_post_load(string name, boolean was_savestate)
|
||||
8.12.9 Callback: on_post_load(string name, boolean was_savestate)
|
||||
|
||||
Called on successful loadstate. was_savestate gives if this was a
|
||||
savestate or a movie.
|
||||
|
||||
8.11.10 Callback: on_pre_save(string name, boolean is_savestate)
|
||||
8.12.10 Callback: on_pre_save(string name, boolean is_savestate)
|
||||
|
||||
Called just before savestate save occurs (note: movie saves are
|
||||
synchronous and won't trigger these callbacks if called from
|
||||
Lua).
|
||||
|
||||
8.11.11 Callback: on_err_save(string name)
|
||||
8.12.11 Callback: on_err_save(string name)
|
||||
|
||||
Called if savestate goes wrong.
|
||||
|
||||
8.11.12 Callback: on_post_save(string name, boolean is_savestate)
|
||||
8.12.12 Callback: on_post_save(string name, boolean is_savestate)
|
||||
|
||||
Called on successful savaestate. is_savestate gives if this was a
|
||||
savestate or a movie.
|
||||
|
||||
8.11.13 Callback: on_quit()
|
||||
8.12.13 Callback: on_quit()
|
||||
|
||||
Called when emulator is shutting down.
|
||||
|
||||
8.11.14 Callback: on_input(boolean subframe)
|
||||
8.12.14 Callback: on_input(boolean subframe)
|
||||
|
||||
Called when emulator is just sending input to bsnes core.
|
||||
Warning: This is called even in readonly mode, but the results
|
||||
are ignored.
|
||||
|
||||
8.11.15 Callback: on_reset()
|
||||
8.12.15 Callback: on_reset()
|
||||
|
||||
Called when SNES is reset.
|
||||
|
||||
8.11.16 Callback: on_readwrite()
|
||||
8.12.16 Callback: on_readwrite()
|
||||
|
||||
Called when moving into readwrite mode as result of “set-rwmode”
|
||||
command (note: moving to rwmode by Lua won't trigger this, as per
|
||||
recursive entry protection).
|
||||
|
||||
8.11.17 Callback: on_snoop(number port, number controller, number
|
||||
8.12.17 Callback: on_snoop(number port, number controller, number
|
||||
index, number value)
|
||||
|
||||
Called each time bsnes asks for input. The value is the final
|
||||
|
@ -1824,31 +1894,31 @@ autofire have been taken into account). Might be useful when
|
|||
translating movies to format suitable for console verification.
|
||||
Note: There is no way to modify the value to be sent.
|
||||
|
||||
8.11.18 Callback: on_keyhook(string keyname, table state)
|
||||
8.12.18 Callback: on_keyhook(string keyname, table state)
|
||||
|
||||
Sent when key that has keyhook events requested changes state.
|
||||
Keyname is name of the key (group) and state is the state (same
|
||||
kind as table values in input.raw).
|
||||
|
||||
8.11.19 Callback: on_idle()
|
||||
8.12.19 Callback: on_idle()
|
||||
|
||||
Called when requested by set_idle_timeout(), the timeout has
|
||||
expired and emulator is waiting.
|
||||
|
||||
8.11.20 Callback: on_timer()
|
||||
8.12.20 Callback: on_timer()
|
||||
|
||||
Called when requested by set_idle_timeout() and the timeout has
|
||||
expired (regardless if emulator is waiting).
|
||||
|
||||
8.11.21 Callback: on_set_rewind(UNSAFEREWIND r)
|
||||
8.12.21 Callback: on_set_rewind(UNSAFEREWIND r)
|
||||
|
||||
Called when unsafe rewind object has been constructed.
|
||||
|
||||
8.11.22 Callback: on_pre_rewind()
|
||||
8.12.22 Callback: on_pre_rewind()
|
||||
|
||||
Called just before unsafe rewind is about to occur.
|
||||
|
||||
8.11.23 Callback: on_post_rewind()
|
||||
8.12.23 Callback: on_post_rewind()
|
||||
|
||||
Called just after unsafe rewind has occured.
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "core/rom.hpp"
|
||||
#include "core/rrdata.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
@ -275,6 +276,20 @@ uint8_t memory_read_byte(uint64_t addr) throw()
|
|||
return memory_read_generic<uint8_t>(addr);
|
||||
}
|
||||
|
||||
void memory_read_bytes(uint64_t addr, uint64_t size, char* buffer) throw()
|
||||
{
|
||||
struct translated_address laddr = translate_address(addr);
|
||||
size_t ssize = min(static_cast<uint64_t>(size), laddr.memory_size - laddr.rel_addr);
|
||||
if(ssize > 0) {
|
||||
if(laddr.iospace_rw) {
|
||||
for(size_t i = 0; i < ssize; i++)
|
||||
buffer[i] = laddr.iospace_rw(laddr.rel_addr++, 0, false);
|
||||
} else
|
||||
memcpy(buffer, laddr.memory + laddr.rel_addr, ssize);
|
||||
}
|
||||
memset(buffer + ssize, 0, size - ssize);
|
||||
}
|
||||
|
||||
uint16_t memory_read_word(uint64_t addr) throw()
|
||||
{
|
||||
return memory_read_generic<uint16_t>(addr);
|
||||
|
@ -296,6 +311,21 @@ bool memory_write_byte(uint64_t addr, uint8_t data) throw()
|
|||
return memory_write_generic<uint8_t>(addr, data);
|
||||
}
|
||||
|
||||
void memory_write_bytes(uint64_t addr, uint64_t size, const char* buffer) throw()
|
||||
{
|
||||
struct translated_address laddr = translate_address(addr);
|
||||
if(laddr.not_writable)
|
||||
return;
|
||||
size_t ssize = min(static_cast<uint64_t>(size), laddr.memory_size - laddr.rel_addr);
|
||||
if(ssize > 0) {
|
||||
if(laddr.iospace_rw) {
|
||||
for(size_t i = 0; i < ssize; i++)
|
||||
laddr.iospace_rw(laddr.rel_addr++, buffer[i], true);
|
||||
} else
|
||||
memcpy(laddr.memory + laddr.rel_addr, buffer, ssize);
|
||||
}
|
||||
}
|
||||
|
||||
bool memory_write_word(uint64_t addr, uint16_t data) throw()
|
||||
{
|
||||
return memory_write_generic<uint16_t>(addr, data);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "core/memorymanip.hpp"
|
||||
#include "core/rom.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -122,6 +123,48 @@ namespace
|
|||
return 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun readmemoryr("memory.readregion", [](lua_State* LS, const std::string& fname) -> int {
|
||||
std::string hash;
|
||||
uint64_t addr = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
|
||||
uint64_t size = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
|
||||
lua_newtable(LS);
|
||||
char buffer[BLOCKSIZE];
|
||||
uint64_t ctr = 0;
|
||||
while(size > 0) {
|
||||
size_t rsize = min(size, static_cast<size_t>(BLOCKSIZE));
|
||||
memory_read_bytes(addr, rsize, buffer);
|
||||
for(size_t i = 0; i < rsize; i++) {
|
||||
lua_pushnumber(LS, ctr++);
|
||||
lua_pushnumber(LS, static_cast<unsigned char>(buffer[i]));
|
||||
lua_settable(LS, -3);
|
||||
}
|
||||
addr += rsize;
|
||||
size -= rsize;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun writememoryr("memory.writeregion", [](lua_State* LS, const std::string& fname) -> int {
|
||||
std::string hash;
|
||||
uint64_t addr = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
|
||||
uint64_t size = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
|
||||
char buffer[BLOCKSIZE];
|
||||
uint64_t ctr = 0;
|
||||
while(size > 0) {
|
||||
size_t rsize = min(size, static_cast<size_t>(BLOCKSIZE));
|
||||
for(size_t i = 0; i < rsize; i++) {
|
||||
lua_pushnumber(LS, ctr++);
|
||||
lua_gettable(LS, 3);
|
||||
buffer[i] = lua_tointeger(LS, -1);
|
||||
lua_pop(LS, 1);
|
||||
}
|
||||
memory_write_bytes(addr, rsize, buffer);
|
||||
addr += rsize;
|
||||
size -= rsize;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
lua_read_memory<uint8_t, uint8_t, memory_read_byte> rub("memory.readbyte");
|
||||
lua_read_memory<int8_t, uint8_t, memory_read_byte> rsb("memory.readsbyte");
|
||||
lua_read_memory<uint16_t, uint16_t, memory_read_word> ruw("memory.readword");
|
||||
|
|
Loading…
Add table
Reference in a new issue