diff options
Diffstat (limited to 'src/frontend/mame/luaengine_mem.cpp')
-rw-r--r-- | src/frontend/mame/luaengine_mem.cpp | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/src/frontend/mame/luaengine_mem.cpp b/src/frontend/mame/luaengine_mem.cpp new file mode 100644 index 00000000000..4e5fac3341f --- /dev/null +++ b/src/frontend/mame/luaengine_mem.cpp @@ -0,0 +1,802 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic,Luca Bruno +/*************************************************************************** + + luaengine_input.cpp + + Controls execution of the core MAME system. + +***************************************************************************/ + +#include "emu.h" +#include "luaengine.ipp" + +#include <cstring> + + +namespace { + +//------------------------------------------------- +// region_read - templated region readers for <sign>,<size> +// -> manager:machine():memory().regions[":maincpu"]:read_i8(0xC000) +//------------------------------------------------- + +template <typename T> +T region_read(memory_region ®ion, offs_t address) +{ + T mem_content = 0; + const offs_t lowmask = region.bytewidth() - 1; + for (int i = 0; i < sizeof(T); i++) + { + int addr = (region.endianness() == ENDIANNESS_LITTLE) ? (address + sizeof(T) - 1 - i) : (address + i); + if (addr < region.bytes()) + { + if constexpr (sizeof(T) > 1) + mem_content <<= 8; + if (region.endianness() == ENDIANNESS_BIG) + mem_content |= region.as_u8((BYTE8_XOR_BE(addr) & lowmask) | (addr & ~lowmask)); + else + mem_content |= region.as_u8((BYTE8_XOR_LE(addr) & lowmask) | (addr & ~lowmask)); + } + } + + return mem_content; +} + +//------------------------------------------------- +// region_write - templated region writer for <sign>,<size> +// -> manager:machine():memory().regions[":maincpu"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template <typename T> +void region_write(memory_region ®ion, offs_t address, T val) +{ + const offs_t lowmask = region.bytewidth() - 1; + for (int i = 0; i < sizeof(T); i++) + { + int addr = (region.endianness() == ENDIANNESS_BIG) ? (address + sizeof(T) - 1 - i) : (address + i); + if (addr < region.bytes()) + { + if (region.endianness() == ENDIANNESS_BIG) + region.base()[(BYTE8_XOR_BE(addr) & lowmask) | (addr & ~lowmask)] = val & 0xff; + else + region.base()[(BYTE8_XOR_LE(addr) & lowmask) | (addr & ~lowmask)] = val & 0xff; + if constexpr (sizeof(T) > 1) + val >>= 8; + } + } +} + +//------------------------------------------------- +// share_read - templated share readers for <sign>,<size> +// -> manager:machine():memory().shares[":maincpu"]:read_i8(0xC000) +//------------------------------------------------- + +template <typename T> +T share_read(memory_share &share, offs_t address) +{ + T mem_content = 0; + const offs_t lowmask = share.bytewidth() - 1; + u8 *ptr = (u8 *)share.ptr(); + for (int i = 0; i < sizeof(T); i++) + { + int addr = share.endianness() == ENDIANNESS_LITTLE ? address + sizeof(T) - 1 - i : address + i; + if (addr < share.bytes()) + { + if constexpr (sizeof(T) > 1) + mem_content <<= 8; + if (share.endianness() == ENDIANNESS_BIG) + mem_content |= ptr[(BYTE8_XOR_BE(addr) & lowmask) | (addr & ~lowmask)]; + else + mem_content |= ptr[(BYTE8_XOR_LE(addr) & lowmask) | (addr & ~lowmask)]; + } + } + + return mem_content; +} + +//------------------------------------------------- +// share_write - templated share writer for <sign>,<size> +// -> manager:machine():memory().shares[":maincpu"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template <typename T> +void share_write(memory_share &share, offs_t address, T val) +{ + const offs_t lowmask = share.bytewidth() - 1; + u8 *ptr = (u8 *)share.ptr(); + for (int i = 0; i < sizeof(T); i++) + { + int addr = share.endianness() == ENDIANNESS_BIG ? address + sizeof(T) - 1 - i : address + i; + if (addr < share.bytes()) + { + if (share.endianness() == ENDIANNESS_BIG) + ptr[(BYTE8_XOR_BE(addr) & lowmask) | (addr & ~lowmask)] = val & 0xff; + else + ptr[(BYTE8_XOR_LE(addr) & lowmask) | (addr & ~lowmask)] = val & 0xff; + if constexpr (sizeof(T) > 1) + val >>= 8; + } + } +} + +} // anonymous namespace + + + +//------------------------------------------------- +// sol_lua_push - automatically convert +// map_handler_type to a string +//------------------------------------------------- + +int sol_lua_push(sol::types<map_handler_type>, lua_State *L, map_handler_type &&value) +{ + const char *typestr; + switch(value) + { + case AMH_NONE: + typestr = "none"; + break; + case AMH_RAM: + typestr = "ram"; + break; + case AMH_ROM: + typestr = "rom"; + break; + case AMH_NOP: + typestr = "nop"; + break; + case AMH_UNMAP: + typestr = "unmap"; + break; + case AMH_DEVICE_DELEGATE: + case AMH_DEVICE_DELEGATE_M: + case AMH_DEVICE_DELEGATE_S: + case AMH_DEVICE_DELEGATE_SM: + case AMH_DEVICE_DELEGATE_MO: + case AMH_DEVICE_DELEGATE_SMO: + typestr = "delegate"; + break; + case AMH_PORT: + typestr = "port"; + break; + case AMH_BANK: + typestr = "bank"; + break; + case AMH_DEVICE_SUBMAP: + typestr = "submap"; + break; + default: + typestr = "unknown"; + break; + } + return sol::stack::push(L, typestr); +} + + +//------------------------------------------------- +// sol_lua_push - automatically convert +// endianness_t to a string +//------------------------------------------------- + +int sol_lua_push(sol::types<endianness_t>, lua_State *L, endianness_t &&value) +{ + return sol::stack::push(L, util::endian_to_string_view(value)); +} + + +//------------------------------------------------- +// tap_helper - class for managing address space +// taps +//------------------------------------------------- + +class lua_engine::tap_helper +{ +public: + tap_helper(tap_helper const &) = delete; + tap_helper(tap_helper &&) = delete; + + tap_helper( + lua_engine &host, + address_space &space, + read_or_write mode, + offs_t start, + offs_t end, + std::string &&name, + sol::protected_function &&callback) + : m_callback(host.m_lua_state, std::move(callback)) + , m_space(space) + , m_handler() + , m_name(std::move(name)) + , m_start(start) + , m_end(end) + , m_mode(mode) + , m_installing(0U) + { + reinstall(); + } + + ~tap_helper() + { + remove(); + } + + offs_t start() const noexcept { return m_start; } + offs_t end() const noexcept { return m_end; } + std::string const &name() const noexcept { return m_name; } + + void reinstall() + { + switch (m_space.data_width()) + { + case 8: do_install<u8>(); break; + case 16: do_install<u16>(); break; + case 32: do_install<u32>(); break; + case 64: do_install<u64>(); break; + } + } + + void remove() + { + ++m_installing; + try + { + m_handler.remove(); + } + catch (...) + { + --m_installing; + throw; + } + --m_installing; + } + +private: + template <typename T> + void do_install() + { + if (m_installing) + return; + ++m_installing; + try + { + m_handler.remove(); + + switch (m_mode) + { + case read_or_write::READ: + m_handler = m_space.install_read_tap( + m_start, + m_end, + m_name, + [this] (offs_t offset, T &data, T mem_mask) + { + auto result = invoke_direct(m_callback, offset, data, mem_mask).template get<std::optional<T> >(); + if (result) + data = *result; + }, + &m_handler); + break; + case read_or_write::WRITE: + m_handler = m_space.install_write_tap( + m_start, + m_end, + m_name, + [this] (offs_t offset, T &data, T mem_mask) + { + auto result = invoke_direct(m_callback, offset, data, mem_mask).template get<std::optional<T> >(); + if (result) + data = *result; + }, + &m_handler); + break; + case read_or_write::READWRITE: + // won't ever get here, but compilers complain about unhandled enum value + break; + } + } + catch (...) + { + --m_installing; + throw; + } + --m_installing; + }; + + sol::protected_function m_callback; + address_space &m_space; + memory_passthrough_handler m_handler; + std::string m_name; + offs_t const m_start; + offs_t const m_end; + read_or_write const m_mode; + unsigned m_installing; +}; + + +//------------------------------------------------- +// mem_read - templated memory readers for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_i8(0xC000) +//------------------------------------------------- + +template <typename T> +T lua_engine::addr_space::mem_read(offs_t address) +{ + T mem_content = 0; + switch (sizeof(mem_content) * 8) + { + case 8: + mem_content = space.read_byte(address); + break; + case 16: + if (WORD_ALIGNED(address)) + mem_content = space.read_word(address); + else + mem_content = space.read_word_unaligned(address); + break; + case 32: + if (DWORD_ALIGNED(address)) + mem_content = space.read_dword(address); + else + mem_content = space.read_dword_unaligned(address); + break; + case 64: + if (QWORD_ALIGNED(address)) + mem_content = space.read_qword(address); + else + mem_content = space.read_qword_unaligned(address); + break; + default: + break; + } + + return mem_content; +} + +//------------------------------------------------- +// mem_write - templated memory writer for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template <typename T> +void lua_engine::addr_space::mem_write(offs_t address, T val) +{ + switch (sizeof(val) * 8) + { + case 8: + space.write_byte(address, val); + break; + case 16: + if (WORD_ALIGNED(address)) + space.write_word(address, val); + else + space.write_word_unaligned(address, val); + break; + case 32: + if (DWORD_ALIGNED(address)) + space.write_dword(address, val); + else + space.write_dword_unaligned(address, val); + break; + case 64: + if (QWORD_ALIGNED(address)) + space.write_qword(address, val); + else + space.write_qword_unaligned(address, val); + break; + default: + break; + } +} + +//------------------------------------------------- +// log_mem_read - templated logical memory readers for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_log_i8(0xC000) +//------------------------------------------------- + +template <typename T> +T lua_engine::addr_space::log_mem_read(offs_t address) +{ + address_space *tspace; + if (!dev.translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace)) + return 0; + + T mem_content = 0; + switch (sizeof(mem_content) * 8) + { + case 8: + mem_content = tspace->read_byte(address); + break; + case 16: + if (WORD_ALIGNED(address)) + mem_content = tspace->read_word(address); + else + mem_content = tspace->read_word_unaligned(address); + break; + case 32: + if (DWORD_ALIGNED(address)) + mem_content = tspace->read_dword(address); + else + mem_content = tspace->read_dword_unaligned(address); + break; + case 64: + if (QWORD_ALIGNED(address)) + mem_content = tspace->read_qword(address); + else + mem_content = tspace->read_qword_unaligned(address); + break; + default: + break; + } + + return mem_content; +} + +//------------------------------------------------- +// log_mem_write - templated logical memory writer for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_log_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template <typename T> +void lua_engine::addr_space::log_mem_write(offs_t address, T val) +{ + address_space *tspace; + if (!dev.translate(space.spacenum(), device_memory_interface::TR_WRITE, address, tspace)) + return; + + switch (sizeof(val) * 8) + { + case 8: + tspace->write_byte(address, val); + break; + case 16: + if (WORD_ALIGNED(address)) + tspace->write_word(address, val); + else + tspace->write_word_unaligned(address, val); + break; + case 32: + if (DWORD_ALIGNED(address)) + tspace->write_dword(address, val); + else + tspace->write_dword_unaligned(address, val); + break; + case 64: + if (QWORD_ALIGNED(address)) + tspace->write_qword(address, val); + else + tspace->write_qword_unaligned(address, val); + break; + default: + break; + } +} + +//------------------------------------------------- +// mem_direct_read - templated direct memory readers for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_direct_i8(0xC000) +//------------------------------------------------- + +template <typename T> +T lua_engine::addr_space::direct_mem_read(offs_t address) +{ + T mem_content = 0; + const offs_t lowmask = space.data_width() / 8 - 1; + for (int i = 0; i < sizeof(T); i++) + { + int addr = space.endianness() == ENDIANNESS_LITTLE ? address + sizeof(T) - 1 - i : address + i; + u8 *base = (u8 *)space.get_read_ptr(addr & ~lowmask); + if (base) + { + if constexpr (sizeof(T) > 1) + mem_content <<= 8; + if (space.endianness() == ENDIANNESS_BIG) + mem_content |= base[BYTE8_XOR_BE(addr) & lowmask]; + else + mem_content |= base[BYTE8_XOR_LE(addr) & lowmask]; + } + } + + return mem_content; +} + +//------------------------------------------------- +// mem_direct_write - templated memory writer for <sign>,<size> +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_direct_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template <typename T> +void lua_engine::addr_space::direct_mem_write(offs_t address, T val) +{ + const offs_t lowmask = space.data_width() / 8 - 1; + for (int i = 0; i < sizeof(T); i++) + { + int addr = space.endianness() == ENDIANNESS_BIG ? address + sizeof(T) - 1 - i : address + i; + u8 *base = (u8 *)space.get_read_ptr(addr & ~lowmask); + if (base) + { + if (space.endianness() == ENDIANNESS_BIG) + base[BYTE8_XOR_BE(addr) & lowmask] = val & 0xff; + else + base[BYTE8_XOR_LE(addr) & lowmask] = val & 0xff; + if constexpr (sizeof(T) > 1) + val >>= 8; + } + } +} + +//------------------------------------------------- +// initialize_memory - register memory user types +//------------------------------------------------- + +void lua_engine::initialize_memory(sol::table &emu) +{ + + auto addr_space_type = sol().registry().new_usertype<addr_space>("addr_space", sol::no_constructor); + addr_space_type.set_function(sol::meta_function::to_string, + [] (addr_space const &sp) + { + device_t &d(sp.dev.device()); + return util::string_format("%s(%s):%s", d.shortname(), d.tag(), sp.space.name()); + }); + addr_space_type.set_function("read_i8", &addr_space::mem_read<s8>); + addr_space_type.set_function("read_u8", &addr_space::mem_read<u8>); + addr_space_type.set_function("read_i16", &addr_space::mem_read<s16>); + addr_space_type.set_function("read_u16", &addr_space::mem_read<u16>); + addr_space_type.set_function("read_i32", &addr_space::mem_read<s32>); + addr_space_type.set_function("read_u32", &addr_space::mem_read<u32>); + addr_space_type.set_function("read_i64", &addr_space::mem_read<s64>); + addr_space_type.set_function("read_u64", &addr_space::mem_read<u64>); + addr_space_type.set_function("write_i8", &addr_space::mem_write<s8>); + addr_space_type.set_function("write_u8", &addr_space::mem_write<u8>); + addr_space_type.set_function("write_i16", &addr_space::mem_write<s16>); + addr_space_type.set_function("write_u16", &addr_space::mem_write<u16>); + addr_space_type.set_function("write_i32", &addr_space::mem_write<s32>); + addr_space_type.set_function("write_u32", &addr_space::mem_write<u32>); + addr_space_type.set_function("write_i64", &addr_space::mem_write<s64>); + addr_space_type.set_function("write_u64", &addr_space::mem_write<u64>); + addr_space_type.set_function("readv_i8", &addr_space::log_mem_read<s8>); + addr_space_type.set_function("readv_u8", &addr_space::log_mem_read<u8>); + addr_space_type.set_function("readv_i16", &addr_space::log_mem_read<s16>); + addr_space_type.set_function("readv_u16", &addr_space::log_mem_read<u16>); + addr_space_type.set_function("readv_i32", &addr_space::log_mem_read<s32>); + addr_space_type.set_function("readv_u32", &addr_space::log_mem_read<u32>); + addr_space_type.set_function("readv_i64", &addr_space::log_mem_read<s64>); + addr_space_type.set_function("readv_u64", &addr_space::log_mem_read<u64>); + addr_space_type.set_function("writev_i8", &addr_space::log_mem_write<s8>); + addr_space_type.set_function("writev_u8", &addr_space::log_mem_write<u8>); + addr_space_type.set_function("writev_i16", &addr_space::log_mem_write<s16>); + addr_space_type.set_function("writev_u16", &addr_space::log_mem_write<u16>); + addr_space_type.set_function("writev_i32", &addr_space::log_mem_write<s32>); + addr_space_type.set_function("writev_u32", &addr_space::log_mem_write<u32>); + addr_space_type.set_function("writev_i64", &addr_space::log_mem_write<s64>); + addr_space_type.set_function("writev_u64", &addr_space::log_mem_write<u64>); + addr_space_type.set_function("read_direct_i8", &addr_space::direct_mem_read<s8>); + addr_space_type.set_function("read_direct_u8", &addr_space::direct_mem_read<u8>); + addr_space_type.set_function("read_direct_i16", &addr_space::direct_mem_read<s16>); + addr_space_type.set_function("read_direct_u16", &addr_space::direct_mem_read<u16>); + addr_space_type.set_function("read_direct_i32", &addr_space::direct_mem_read<s32>); + addr_space_type.set_function("read_direct_u32", &addr_space::direct_mem_read<u32>); + addr_space_type.set_function("read_direct_i64", &addr_space::direct_mem_read<s64>); + addr_space_type.set_function("read_direct_u64", &addr_space::direct_mem_read<u64>); + addr_space_type.set_function("write_direct_i8", &addr_space::direct_mem_write<s8>); + addr_space_type.set_function("write_direct_u8", &addr_space::direct_mem_write<u8>); + addr_space_type.set_function("write_direct_i16", &addr_space::direct_mem_write<s16>); + addr_space_type.set_function("write_direct_u16", &addr_space::direct_mem_write<u16>); + addr_space_type.set_function("write_direct_i32", &addr_space::direct_mem_write<s32>); + addr_space_type.set_function("write_direct_u32", &addr_space::direct_mem_write<u32>); + addr_space_type.set_function("write_direct_i64", &addr_space::direct_mem_write<s64>); + addr_space_type.set_function("write_direct_u64", &addr_space::direct_mem_write<u64>); + addr_space_type.set_function("read_range", + [] (addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) -> sol::object + { + u64 step = 1; + if (opt_step.is<u64>()) + { + step = opt_step.as<u64>(); + if ((step < 1) || (step > last - first)) + { + luaL_error(s, "Invalid step"); + return sol::lua_nil; + } + } + + offs_t space_size = sp.space.addrmask(); + if ((first > space_size) || (last > space_size) || (last < first)) + { + luaL_error(s, "Invalid offset"); + return sol::lua_nil; + } + + luaL_Buffer buff; + int byte_count = width / 8 * (last - first + 1) / step; + switch (width) + { + case 8: + { + u8 *dest = (u8 *)luaL_buffinitsize(s, &buff, byte_count); + for ( ; first <= last; first += step) + *dest++ = sp.mem_read<u8>(first); + break; + } + case 16: + { + u16 *dest = (u16 *)luaL_buffinitsize(s, &buff, byte_count); + for ( ; first <= last; first += step) + *dest++ = sp.mem_read<u16>(first); + break; + } + case 32: + { + u32 *dest = (u32 *)luaL_buffinitsize(s, &buff, byte_count); + for( ; first <= last; first += step) + *dest++ = sp.mem_read<u32>(first); + break; + } + case 64: + { + u64 *dest = (u64 *)luaL_buffinitsize(s, &buff, byte_count); + for( ; first <= last; first += step) + *dest++ = sp.mem_read<u64>(first); + break; + } + default: + luaL_error(s, "Invalid width. Must be 8/16/32/64"); + return sol::lua_nil; + } + luaL_pushresultsize(&buff, byte_count); + return sol::make_reference(s, sol::stack_reference(s, -1)); + }); + addr_space_type.set_function("add_change_notifier", + [this] (addr_space &sp, sol::protected_function &&cb) + { + return sp.space.add_change_notifier( + [this, callback = std::move(cb)] (read_or_write mode) + { + char const *modestr = ""; + switch (mode) + { + case read_or_write::READ: modestr = "r"; break; + case read_or_write::WRITE: modestr = "w"; break; + case read_or_write::READWRITE: modestr = "rw"; break; + } + auto status = invoke(callback, modestr); + if (!status.valid()) + { + sol::error err = status; + osd_printf_error("[LUA ERROR] in address space change notifier: %s\n", err.what()); + } + }); + }); + addr_space_type.set_function("install_read_tap", + [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + { + return std::make_unique<tap_helper>(*this, sp.space, read_or_write::READ, start, end, std::move(name), std::move(cb)); + }); + addr_space_type.set_function("install_write_tap", + [this] (addr_space &sp, offs_t start, offs_t end, std::string &&name, sol::protected_function &&cb) + { + return std::make_unique<tap_helper>(*this, sp.space, read_or_write::WRITE, start, end, std::move(name), std::move(cb)); + }); + addr_space_type["name"] = sol::property([] (addr_space &sp) { return sp.space.name(); }); + addr_space_type["shift"] = sol::property([] (addr_space &sp) { return sp.space.addr_shift(); }); + addr_space_type["index"] = sol::property([] (addr_space &sp) { return sp.space.spacenum(); }); + addr_space_type["address_mask"] = sol::property([] (addr_space &sp) { return sp.space.addrmask(); }); + addr_space_type["data_width"] = sol::property([] (addr_space &sp) { return sp.space.data_width(); }); + addr_space_type["endianness"] = sol::property([] (addr_space &sp) { return sp.space.endianness(); }); + addr_space_type["map"] = sol::property([] (addr_space &sp) { return sp.space.map(); }); + + + auto tap_type = sol().registry().new_usertype<tap_helper>("mempassthrough", sol::no_constructor); + tap_type.set_function("reinstall", &tap_helper::reinstall); + tap_type.set_function("remove", &tap_helper::remove); + tap_type["addrstart"] = sol::property(&tap_helper::start); + tap_type["addrend"] = sol::property(&tap_helper::end); + tap_type["name"] = sol::property(&tap_helper::name); + + + auto addrmap_type = sol().registry().new_usertype<address_map>("addrmap", sol::no_constructor); + addrmap_type["spacenum"] = sol::readonly(&address_map::m_spacenum); + addrmap_type["device"] = sol::readonly(&address_map::m_device); + addrmap_type["unmap_value"] = sol::readonly(&address_map::m_unmapval); + addrmap_type["global_mask"] = sol::readonly(&address_map::m_globalmask); + addrmap_type["entries"] = sol::property([] (address_map &m) { return simple_list_wrapper<address_map_entry>(m.m_entrylist); }); + + + auto mapentry_type = sol().registry().new_usertype<address_map_entry>("mapentry", sol::no_constructor); + mapentry_type["address_start"] = sol::readonly(&address_map_entry::m_addrstart); + mapentry_type["address_end"] = sol::readonly(&address_map_entry::m_addrend); + mapentry_type["address_mirror"] = sol::readonly(&address_map_entry::m_addrmirror); + mapentry_type["address_mask"] = sol::readonly(&address_map_entry::m_addrmask); + mapentry_type["mask"] = sol::readonly(&address_map_entry::m_mask); + mapentry_type["cswidth"] = sol::readonly(&address_map_entry::m_cswidth); + mapentry_type["read"] = sol::readonly(&address_map_entry::m_read); + mapentry_type["write"] = sol::readonly(&address_map_entry::m_write); + mapentry_type["share"] = sol::readonly(&address_map_entry::m_share); + mapentry_type["region"] = sol::readonly(&address_map_entry::m_region); + mapentry_type["region_offset"] = sol::readonly(&address_map_entry::m_rgnoffs); + + + auto handler_data_type = sol().registry().new_usertype<map_handler_data>("handlerdata", sol::no_constructor); + handler_data_type["handlertype"] = sol::property([] (map_handler_data const &hd) { return hd.m_type; }); // can't use member pointer or won't be converted to string + handler_data_type["bits"] = sol::readonly(&map_handler_data::m_bits); + handler_data_type["name"] = sol::readonly(&map_handler_data::m_name); + handler_data_type["tag"] = sol::readonly(&map_handler_data::m_tag); + + + auto memory_type = sol().registry().new_usertype<memory_manager>("memory", sol::no_constructor); + memory_type["banks"] = sol::property([] (memory_manager &mm) { return standard_tag_object_ptr_map<memory_bank>(mm.banks()); }); + memory_type["regions"] = sol::property([] (memory_manager &mm) { return standard_tag_object_ptr_map<memory_region>(mm.regions()); }); + memory_type["shares"] = sol::property([] (memory_manager &mm) { return standard_tag_object_ptr_map<memory_share>(mm.shares()); }); + + + auto bank_type = sol().registry().new_usertype<memory_bank>("membank", sol::no_constructor); + bank_type["tag"] = sol::property(&memory_bank::tag); + bank_type["entry"] = sol::property(&memory_bank::entry, &memory_bank::set_entry); + + + auto region_type = sol().registry().new_usertype<memory_region>("region", sol::no_constructor); + region_type.set_function( + "read", + [] (memory_region ®ion, sol::this_state s, offs_t offset, offs_t length) + { + // TODO: should this do something special if the offset isn't a multiple of the byte width? + buffer_helper buf(s); + const offs_t limit = std::min<offs_t>(region.bytes(), offset + length); + const offs_t copyable = (limit > offset) ? (limit - offset) : 0; + auto space = buf.prepare(copyable); + if (copyable) + std::memcpy(space.get(), ®ion.as_u8(offset), copyable); + space.add(copyable); + buf.push(); + return sol::make_reference(s, sol::stack_reference(s, -1)); + }); + region_type.set_function("read_i8", ®ion_read<s8>); + region_type.set_function("read_u8", ®ion_read<u8>); + region_type.set_function("read_i16", ®ion_read<s16>); + region_type.set_function("read_u16", ®ion_read<u16>); + region_type.set_function("read_i32", ®ion_read<s32>); + region_type.set_function("read_u32", ®ion_read<u32>); + region_type.set_function("read_i64", ®ion_read<s64>); + region_type.set_function("read_u64", ®ion_read<u64>); + region_type.set_function("write_i8", ®ion_write<s8>); + region_type.set_function("write_u8", ®ion_write<u8>); + region_type.set_function("write_i16", ®ion_write<s16>); + region_type.set_function("write_u16", ®ion_write<u16>); + region_type.set_function("write_i32", ®ion_write<s32>); + region_type.set_function("write_u32", ®ion_write<u32>); + region_type.set_function("write_i64", ®ion_write<s64>); + region_type.set_function("write_u64", ®ion_write<u64>); + region_type["tag"] = sol::property(&memory_region::name); + region_type["size"] = sol::property(&memory_region::bytes); + region_type["length"] = sol::property([] (memory_region &r) { return r.bytes() / r.bytewidth(); }); + region_type["endianness"] = sol::property(&memory_region::endianness); + region_type["bitwidth"] = sol::property(&memory_region::bitwidth); + region_type["bytewidth"] = sol::property(&memory_region::bytewidth); + + + auto share_type = sol().registry().new_usertype<memory_share>("share", sol::no_constructor); + share_type.set_function("read_i8", &share_read<s8>); + share_type.set_function("read_u8", &share_read<u8>); + share_type.set_function("read_i16", &share_read<s16>); + share_type.set_function("read_u16", &share_read<u16>); + share_type.set_function("read_i32", &share_read<s32>); + share_type.set_function("read_u32", &share_read<u32>); + share_type.set_function("read_i64", &share_read<s64>); + share_type.set_function("read_u64", &share_read<u64>); + share_type.set_function("write_i8", &share_write<s8>); + share_type.set_function("write_u8", &share_write<u8>); + share_type.set_function("write_i16", &share_write<s16>); + share_type.set_function("write_u16", &share_write<u16>); + share_type.set_function("write_i32", &share_write<s32>); + share_type.set_function("write_u32", &share_write<u32>); + share_type.set_function("write_i64", &share_write<s64>); + share_type.set_function("write_u64", &share_write<u64>); + share_type["tag"] = sol::property(&memory_share::name); + share_type["size"] = sol::property(&memory_share::bytes); + share_type["length"] = sol::property([] (memory_share &s) { return s.bytes() / s.bytewidth(); }); + share_type["endianness"] = sol::property(&memory_share::endianness); + share_type["bitwidth"] = sol::property(&memory_share::bitwidth); + share_type["bytewidth"] = sol::property(&memory_share::bytewidth); + +} |