diff --git a/lua.lyx b/lua.lyx
index 939c57e6..405072a3 100644
--- a/lua.lyx
+++ b/lua.lyx
@@ -3326,51 +3326,66 @@ Reads the specified address
(if 's' variant is used, do undergo
\end_layout
\begin_layout Subsection
-memory.read{,s}{byte,{,h,d,q}word}: Read memory
+memory.{,s}read_sg: Scatter/Gather read memory
\end_layout
\begin_layout Itemize
-Syntax: none memory.readbyte([string vma, ]number address)
+Syntax: none memory.read_sg(string/boolean/number...)
\end_layout
\begin_layout Itemize
-Syntax: none memory.readword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readhword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readdword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readqword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readsbyte([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readsword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readshword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readsdword([string vma, ]number address)
-\end_layout
-
-\begin_layout Itemize
-Syntax: none memory.readsqword([string vma, ]number address)
+Syntax: none memory.sread_sg(string/boolean/number...)
\end_layout
\begin_layout Standard
-Reads the specified address
+Perform (2s complement signed if using memory.sread_sg) scatter/gather read
+ of memory.
+ Each argument can be string, boolean or number:
+\end_layout
+
+\begin_layout Itemize
+String: Set VMA addresses are relative to (e.g.
+ 'WRAM').
+\end_layout
+
+\begin_layout Itemize
+boolean: If true, increment relative address by 1, if false, decrement by
+ 1.
+ The new address is read as next higher byte.
+\end_layout
+
+\begin_layout Itemize
+integer: Set the relative address to specified value and read the address
+ as next higher byte.
+\end_layout
+
+\begin_layout Subsection
+memory.write_sg: Scatter/Gather write memory
+\end_layout
+
+\begin_layout Itemize
+Syntax: none memory.write_sg(number value, string/boolean/number...)
+\end_layout
+
+\begin_layout Standard
+Perform scatter/gather write of value on memory.
+ Each argument can be string, boolean or number:
+\end_layout
+
+\begin_layout Itemize
+String: Set VMA addresses are relative to (e.g.
+ 'WRAM').
+\end_layout
+
+\begin_layout Itemize
+boolean: If true, increment relative address by 1, if false, decrement by
+ 1.
+ The new address is read as next higher byte.
+\end_layout
+
+\begin_layout Itemize
+integer: Set the relative address to specified value and read the address
+ as next higher byte.
\end_layout
\begin_layout Subsection
diff --git a/lua.pdf b/lua.pdf
index f35ba884..c797beae 100644
Binary files a/lua.pdf and b/lua.pdf differ
diff --git a/src/lua/memory.cpp b/src/lua/memory.cpp
index 610e9918..17e901cc 100644
--- a/src/lua/memory.cpp
+++ b/src/lua/memory.cpp
@@ -394,6 +394,55 @@ namespace
return 1;
});
+ template int memory_scattergather(lua_state& L, const std::string& fname)
+ {
+ uint64_t val = 0;
+ int ptr = 1;
+ unsigned shift = 0;
+ uint64_t addr = 0;
+ uint64_t vmabase = 0;
+ if(write)
+ val = L.get_numeric_argument(ptr++, fname.c_str());
+ while(L.type(ptr) != LUA_TNIL && L.type(ptr) != LUA_TNONE) {
+ if(L.type(ptr) == LUA_TBOOLEAN) {
+ if(L.toboolean(ptr++))
+ addr++;
+ else
+ addr--;
+ } else if(L.type(ptr) == LUA_TSTRING) {
+ vmabase = get_vmabase(L, L.get_string(ptr++, fname.c_str()));
+ continue;
+ } else
+ addr = L.get_numeric_argument(ptr++, fname.c_str());
+ if(write)
+ lsnes_memory.write(addr + vmabase, val >> shift);
+ else
+ val = val + ((uint64_t)lsnes_memory.read(addr + vmabase) << shift);
+ shift += 8;
+ }
+ if(!write) {
+ int64_t sval = val;
+ if(val >= (1ULL << (shift - 1))) sval -= (1ULL << shift);
+ if(sign) L.pushnumber(sval); else L.pushnumber(val);
+ }
+ return write ? 0 : 1;
+ }
+
+ function_ptr_luafun scattergather1(lua_func_misc, "memory.read_sg", [](lua_state& L, const std::string& fname)
+ -> int {
+ return memory_scattergather(L, fname);
+ });
+
+ function_ptr_luafun scattergather2(lua_func_misc, "memory.sread_sg", [](lua_state& L,
+ const std::string& fname) -> int {
+ return memory_scattergather(L, fname);
+ });
+
+ function_ptr_luafun scattergather3(lua_func_misc, "memory.write_sg", [](lua_state& L,
+ const std::string& fname) -> int {
+ return memory_scattergather(L, fname);
+ });
+
lua_read_memory> rub("memory.readbyte");
lua_read_memory> rsb("memory.readsbyte");
lua_read_memory> ruw("memory.readword");