Lua: memory.readregion / memory.writeregion

This commit is contained in:
Ilari Liusvaara 2012-09-29 08:08:40 +03:00
parent 1e1cd1026b
commit 4ca6e1df02
5 changed files with 350 additions and 31 deletions

View file

@ -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
*

View file

@ -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

View file

@ -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.

View file

@ -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);

View file

@ -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");