From b524aa701af544f4b673bb810a67719230a6858a Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 16 Nov 2020 23:11:43 +1100 Subject: frontend: split lua_engine user type registrations across a few files to make it a bit more manageable --- scripts/src/mame/frontend.lua | 4 + src/frontend/mame/luaengine.cpp | 1223 ++------------------------------ src/frontend/mame/luaengine.h | 28 +- src/frontend/mame/luaengine.ipp | 124 ++++ src/frontend/mame/luaengine_input.cpp | 441 ++++++++++++ src/frontend/mame/luaengine_mem.cpp | 603 ++++++++++++++++ src/frontend/mame/luaengine_render.cpp | 108 +++ 7 files changed, 1330 insertions(+), 1201 deletions(-) create mode 100644 src/frontend/mame/luaengine.ipp create mode 100644 src/frontend/mame/luaengine_input.cpp create mode 100644 src/frontend/mame/luaengine_mem.cpp create mode 100644 src/frontend/mame/luaengine_render.cpp diff --git a/scripts/src/mame/frontend.lua b/scripts/src/mame/frontend.lua index 9e4a367c9c0..3fe8911b9e2 100644 --- a/scripts/src/mame/frontend.lua +++ b/scripts/src/mame/frontend.lua @@ -72,6 +72,10 @@ files { MAME_DIR .. "src/frontend/mame/language.h", MAME_DIR .. "src/frontend/mame/luaengine.cpp", MAME_DIR .. "src/frontend/mame/luaengine.h", + MAME_DIR .. "src/frontend/mame/luaengine.ipp", + MAME_DIR .. "src/frontend/mame/luaengine_input.cpp", + MAME_DIR .. "src/frontend/mame/luaengine_mem.cpp", + MAME_DIR .. "src/frontend/mame/luaengine_render.cpp", MAME_DIR .. "src/frontend/mame/mame.cpp", MAME_DIR .. "src/frontend/mame/mame.h", MAME_DIR .. "src/frontend/mame/mameopts.cpp", diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 5138e7d4f61..feee802c2e1 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -8,24 +8,25 @@ ***************************************************************************/ -#include #include "emu.h" +#include "luaengine.ipp" + #include "mame.h" -#include "debugger.h" +#include "pluginopts.h" +#include "ui/pluginopt.h" +#include "ui/ui.h" + #include "debug/debugcon.h" #include "debug/debugcpu.h" #include "debug/points.h" #include "debug/textbuf.h" +#include "debugger.h" #include "drivenum.h" #include "emuopts.h" -#include "ui/ui.h" -#include "ui/pluginopt.h" -#include "luaengine.h" +#include "inputdev.h" #include "natkeyboard.h" -#include "uiinput.h" -#include "pluginopts.h" #include "softlist.h" -#include "inputdev.h" +#include "uiinput.h" #include #include @@ -51,43 +52,6 @@ extern "C" { namespace sol { - class buffer - { - public: - // sol does lua_settop(0), save userdata buffer in registry if necessary - buffer(int size, lua_State *L) - { - ptr = luaL_buffinitsize(L, &buff, size); - len = size; - if(buff.b != buff.initb) - { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); - } - } - ~buffer() - { - lua_State *L = buff.L; - if(lua_getfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp") != LUA_TNIL) - { - lua_pushnil(L); - lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); - } - else - lua_pop(L, -1); - - luaL_pushresultsize(&buff, len); - } - void set_len(int size) { len = size; } - int get_len() { return len; } - char *get_ptr() { return ptr; } - private: - luaL_Buffer buff; - int len; - char *ptr; - }; - template<> - struct is_container : std::false_type {}; // don't convert core_optons to a table directly sol::buffer *sol_lua_get(sol::types, lua_State *L, int index, sol::stack::record &tracking) { return new sol::buffer(stack::get(L, index), L); @@ -187,73 +151,6 @@ int sol_lua_push(sol::types, lua_State *L, map_handler_type && return sol::stack::push(L, typestr); } -namespace -{ - // ======================> enum_parser - template - class enum_parser - { - public: - constexpr enum_parser(std::initializer_list> values) - { - if (values.size() != SIZE) - throw false && "size template argument incorrectly specified"; - std::copy(values.begin(), values.end(), m_map.begin()); - } - - T operator()(const char *text) const - { - auto iter = std::find_if( - m_map.begin() + 1, - m_map.end(), - [text](const auto &x) { return !strcmp(text, x.first); }); - if (iter == m_map.end()) - iter = m_map.begin(); - return iter->second; - } - - T operator()(const std::string &text) const - { - return (*this)(text.c_str()); - } - - private: - std::array, SIZE> m_map; - }; -}; - - -static const enum_parser s_seq_type_parser = -{ - { "standard", SEQ_TYPE_STANDARD }, - { "increment", SEQ_TYPE_INCREMENT }, - { "decrement", SEQ_TYPE_DECREMENT }, -}; - - -static const enum_parser s_movie_recording_format_parser = -{ - { "avi", movie_recording::format::AVI }, - { "mng", movie_recording::format::MNG } -}; - - -static const enum_parser s_read_or_write_parser = -{ - { "r", read_or_write::READ }, - { "w", read_or_write::WRITE }, - { "rw", read_or_write::READWRITE }, - { "wr", read_or_write::READWRITE } -}; - - -static const enum_parser s_text_justify_parser = -{ - { "left", ui::text_layout::LEFT }, - { "right", ui::text_layout::RIGHT }, - { "center", ui::text_layout::CENTER }, -}; - //------------------------------------------------- // process_snapshot_filename - processes a snapshot @@ -272,315 +169,6 @@ static std::string process_snapshot_filename(running_machine &machine, const cha } -//------------------------------------------------- -// mem_read - templated memory readers for , -// -> manager:machine().devices[":maincpu"].spaces["program"]:read_i8(0xC000) -//------------------------------------------------- - -template -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 , -// -> manager:machine().devices[":maincpu"].spaces["program"]:write_u16(0xC000, 0xF00D) -//------------------------------------------------- - -template -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 , -// -> manager:machine().devices[":maincpu"].spaces["program"]:read_log_i8(0xC000) -//------------------------------------------------- - -template -T lua_engine::addr_space::log_mem_read(offs_t address) -{ - T mem_content = 0; - if(!dev.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - return 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; -} - -//------------------------------------------------- -// log_mem_write - templated logical memory writer for , -// -> manager:machine().devices[":maincpu"].spaces["program"]:write_log_u16(0xC000, 0xF00D) -//------------------------------------------------- - -template -void lua_engine::addr_space::log_mem_write(offs_t address, T val) -{ - if(!dev.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) - return; - - 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; - } -} - -//------------------------------------------------- -// mem_direct_read - templated direct memory readers for , -// -> manager:machine().devices[":maincpu"].spaces["program"]:read_direct_i8(0xC000) -//------------------------------------------------- - -template -T lua_engine::addr_space::direct_mem_read(offs_t address) -{ - T mem_content = 0; - 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; - uint8_t *base = (uint8_t *)space.get_read_ptr(addr & ~lowmask); - if(!base) - continue; - 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 , -// -> manager:machine().devices[":maincpu"].spaces["program"]:write_direct_u16(0xC000, 0xF00D) -//------------------------------------------------- - -template -void lua_engine::addr_space::direct_mem_write(offs_t address, T val) -{ - 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; - uint8_t *base = (uint8_t *)space.get_read_ptr(addr & ~lowmask); - if(!base) - continue; - if(space.endianness() == ENDIANNESS_BIG) - base[BYTE8_XOR_BE(addr) & lowmask] = val & 0xff; - else - base[BYTE8_XOR_LE(addr) & lowmask] = val & 0xff; - val >>= 8; - } -} - -//------------------------------------------------- -// region_read - templated region readers for , -// -> manager:machine():memory().regions[":maincpu"]:read_i8(0xC000) -//------------------------------------------------- - -template -T lua_engine::region_read(memory_region ®ion, offs_t address) -{ - T mem_content = 0; - 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()) - continue; - 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 , -// -> manager:machine():memory().regions[":maincpu"]:write_u16(0xC000, 0xF00D) -//------------------------------------------------- - -template -void lua_engine::region_write(memory_region ®ion, offs_t address, T val) -{ - 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()) - continue; - 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; - val >>= 8; - } -} - -//------------------------------------------------- -// share_read - templated share readers for , -// -> manager:machine():memory().shares[":maincpu"]:read_i8(0xC000) -//------------------------------------------------- - -template -T lua_engine::share_read(memory_share &share, offs_t address) -{ - T mem_content = 0; - offs_t lowmask = share.bytewidth() - 1; - uint8_t* ptr = (uint8_t*)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()) - continue; - 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 , -// -> manager:machine():memory().shares[":maincpu"]:write_u16(0xC000, 0xF00D) -//------------------------------------------------- - -template -void lua_engine::share_write(memory_share &share, offs_t address, T val) -{ - offs_t lowmask = share.bytewidth() - 1; - uint8_t* ptr = (uint8_t*)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()) - continue; - 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; - val >>= 8; - } -} - //------------------------------------------------- // lua_engine - constructor //------------------------------------------------- @@ -817,6 +405,30 @@ void lua_engine::attach_notifiers() void lua_engine::initialize() { + static const enum_parser s_movie_recording_format_parser = + { + { "avi", movie_recording::format::AVI }, + { "mng", movie_recording::format::MNG } + }; + + + static const enum_parser s_read_or_write_parser = + { + { "r", read_or_write::READ }, + { "w", read_or_write::WRITE }, + { "rw", read_or_write::READWRITE }, + { "wr", read_or_write::READWRITE } + }; + + + static const enum_parser s_text_justify_parser = + { + { "left", ui::text_layout::LEFT }, + { "right", ui::text_layout::RIGHT }, + { "center", ui::text_layout::CENTER }, + }; + + /* emu library * * emu.app_name() - return application name @@ -1733,415 +1345,6 @@ void lua_engine::initialize() })); -/* addr_space library - * - * manager:machine().devices[device_tag].spaces[space] - * - * read/write by signedness u/i and bit-width 8/16/32/64: - * space:read_*(addr) - * space:write_*(addr, val) - * space:read_log_*(addr) - * space:write_log_*(addr, val) - * space:read_direct_*(addr) - * space:write_direct_*(addr, val) - * space:read_range(first_addr, last_addr, width, [opt] step) - read range of addresses and - * return as a binary string - * - * space.name - address space name - * space.shift - address bus shift, bitshift required for a bytewise address - * to map onto this space's address resolution (addressing granularity). - * positive value means leftshift, negative means rightshift. - * space.index - * space.address_mask - * space.data_width - * space.endianness - * - * space.map[] - table of address map entries (k=index, v=address_map_entry) - */ - - auto addr_space_type = sol().registry().new_usertype("addr_space", sol::call_constructor, sol::constructors>()); - addr_space_type.set("read_i8", &addr_space::mem_read); - addr_space_type.set("read_u8", &addr_space::mem_read); - addr_space_type.set("read_i16", &addr_space::mem_read); - addr_space_type.set("read_u16", &addr_space::mem_read); - addr_space_type.set("read_i32", &addr_space::mem_read); - addr_space_type.set("read_u32", &addr_space::mem_read); - addr_space_type.set("read_i64", &addr_space::mem_read); - addr_space_type.set("read_u64", &addr_space::mem_read); - addr_space_type.set("write_i8", &addr_space::mem_write); - addr_space_type.set("write_u8", &addr_space::mem_write); - addr_space_type.set("write_i16", &addr_space::mem_write); - addr_space_type.set("write_u16", &addr_space::mem_write); - addr_space_type.set("write_i32", &addr_space::mem_write); - addr_space_type.set("write_u32", &addr_space::mem_write); - addr_space_type.set("write_i64", &addr_space::mem_write); - addr_space_type.set("write_u64", &addr_space::mem_write); - addr_space_type.set("read_log_i8", &addr_space::log_mem_read); - addr_space_type.set("read_log_u8", &addr_space::log_mem_read); - addr_space_type.set("read_log_i16", &addr_space::log_mem_read); - addr_space_type.set("read_log_u16", &addr_space::log_mem_read); - addr_space_type.set("read_log_i32", &addr_space::log_mem_read); - addr_space_type.set("read_log_u32", &addr_space::log_mem_read); - addr_space_type.set("read_log_i64", &addr_space::log_mem_read); - addr_space_type.set("read_log_u64", &addr_space::log_mem_read); - addr_space_type.set("write_log_i8", &addr_space::log_mem_write); - addr_space_type.set("write_log_u8", &addr_space::log_mem_write); - addr_space_type.set("write_log_i16", &addr_space::log_mem_write); - addr_space_type.set("write_log_u16", &addr_space::log_mem_write); - addr_space_type.set("write_log_i32", &addr_space::log_mem_write); - addr_space_type.set("write_log_u32", &addr_space::log_mem_write); - addr_space_type.set("write_log_i64", &addr_space::log_mem_write); - addr_space_type.set("write_log_u64", &addr_space::log_mem_write); - addr_space_type.set("read_direct_i8", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_u8", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_i16", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_u16", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_i32", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_u32", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_i64", &addr_space::direct_mem_read); - addr_space_type.set("read_direct_u64", &addr_space::direct_mem_read); - addr_space_type.set("write_direct_i8", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_u8", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_i16", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_u16", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_i32", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_u32", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_i64", &addr_space::direct_mem_write); - addr_space_type.set("write_direct_u64", &addr_space::direct_mem_write); - addr_space_type.set("read_range", [](addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) { - lua_State *L = s; - luaL_Buffer buff; - offs_t space_size = sp.space.addrmask(); - u64 step = 1; - if (opt_step.is()) - { - step = opt_step.as(); - if (step < 1 || step > last - first) - { - luaL_error(L, "Invalid step"); - return sol::make_reference(L, nullptr); - } - } - if (first > space_size || last > space_size || last < first) - { - luaL_error(L, "Invalid offset"); - return sol::make_reference(L, nullptr); - } - int byte_count = width / 8 * (last - first + 1) / step; - switch (width) - { - case 8: - { - u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read(first); - break; - } - case 16: - { - u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read(first); - break; - } - case 32: - { - u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read(first); - break; - } - case 64: - { - u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count); - for(; first <= last; first += step) - *dest++ = sp.mem_read(first); - break; - } - default: - luaL_error(L, "Invalid width. Must be 8/16/32/64"); - return sol::make_reference(L, nullptr); - } - luaL_pushresultsize(&buff, byte_count); - return sol::make_reference(L, sol::stack_reference(L, -1)); - }); - addr_space_type.set("name", sol::property([](addr_space &sp) { return sp.space.name(); })); - addr_space_type.set("shift", sol::property([](addr_space &sp) { return sp.space.addr_shift(); })); - addr_space_type.set("index", sol::property([](addr_space &sp) { return sp.space.spacenum(); })); - addr_space_type.set("address_mask", sol::property([](addr_space &sp) { return sp.space.addrmask(); })); - addr_space_type.set("data_width", sol::property([](addr_space &sp) { return sp.space.data_width(); })); - addr_space_type.set("endianness", sol::property([](addr_space &sp) { - std::string endianness; - switch (sp.space.endianness()) - { - case endianness_t::ENDIANNESS_BIG: - endianness = "big"; - break; - case endianness_t::ENDIANNESS_LITTLE: - endianness = "little"; - break; - } - return endianness; - })); - - -/* address_map_entry library - * - * manager:machine().devices[device_tag].spaces[space].map[entry_index] - * - * mapentry.offset - address start - * mapentry.endoff - address end - * mapentry.readtype - * mapentry.writetype - */ - addr_space_type.set("map", sol::property([this](addr_space &sp) { - address_space &space = sp.space; - sol::table map = sol().create_table(); - for (address_map_entry &entry : space.map()->m_entrylist) - { - sol::table mapentry = sol().create_table(); - mapentry["offset"] = entry.m_addrstart & space.addrmask(); - mapentry["endoff"] = entry.m_addrend & space.addrmask(); - mapentry["readtype"] = entry.m_read.m_type; - mapentry["writetype"] = entry.m_write.m_type; - map.add(mapentry); - } - return map; - })); - - -/* ioport_manager library - * - * manager:machine():ioport() - * - * ioport:count_players() - get count of player controllers - * ioport:type_group(type, player) - * ioport:type_seq(type, player, seqtype) - get input sequence for ioport type/player - * - * ioport.ports[] - ioports table (k=tag, v=ioport_port) - */ - - auto ioport_manager_type = sol().registry().new_usertype("ioport", "new", sol::no_constructor); - ioport_manager_type.set("count_players", &ioport_manager::count_players); - ioport_manager_type.set("natkeyboard", &ioport_manager::natkeyboard); - ioport_manager_type.set("type_group", [](ioport_manager &im, ioport_type type, int player) { - return im.type_group(type, player); - }); - ioport_manager_type.set("ports", sol::property([this](ioport_manager &im) { - sol::table port_table = sol().create_table(); - for (auto &port : im.ports()) - port_table[port.second->tag()] = port.second.get(); - return port_table; - })); - ioport_manager_type.set("type_seq", [](ioport_manager &m, ioport_type type, int player, input_seq_type seqtype) { - return m.type_seq(type, player, seqtype); - }); - - -/* natural_keyboard library - * - * manager:machine():ioport():natkeyboard() - * - * natkeyboard:paste() - paste clipboard data - * natkeyboard:post() - post data to natural keyboard - * natkeyboard:post_coded() - post data to natural keyboard - * - * natkeyboard.empty - is the natural keyboard buffer empty? - * natkeyboard.in_use - is the natural keyboard in use? - */ - - auto natkeyboard_type = sol().registry().new_usertype("natkeyboard", "new", sol::no_constructor); - natkeyboard_type.set("empty", sol::property(&natural_keyboard::empty)); - natkeyboard_type.set("in_use", sol::property(&natural_keyboard::in_use, &natural_keyboard::set_in_use)); - natkeyboard_type.set("paste", &natural_keyboard::paste); - natkeyboard_type.set("post", [](natural_keyboard &nat, const std::string &text) { nat.post_utf8(text); }); - natkeyboard_type.set("post_coded", [](natural_keyboard &nat, const std::string &text) { nat.post_coded(text); }); - - -/* ioport_port library - * - * manager:machine():ioport().ports[port_tag] - * - * port:tag() - get port tag - * port:active() - get port status - * port:live() - get port ioport_port_live (TODO: not usable from lua as of now) - * port:read() - get port value - * port:write(val, mask) - set port to value & mask (output fields only, for other fields use field:set_value(val)) - * port:field(mask) - get ioport_field for port and mask - * - * port.fields[] - get ioport_field table (k=name, v=ioport_field) - */ - - auto ioport_port_type = sol().registry().new_usertype("ioport_port", "new", sol::no_constructor); - ioport_port_type.set("tag", &ioport_port::tag); - ioport_port_type.set("active", &ioport_port::active); - ioport_port_type.set("live", &ioport_port::live); - ioport_port_type.set("read", &ioport_port::read); - ioport_port_type.set("write", &ioport_port::write); - ioport_port_type.set("field", &ioport_port::field); - ioport_port_type.set("fields", sol::property([this](ioport_port &p){ - sol::table f_table = sol().create_table(); - // parse twice for custom and default names, default has priority - for(ioport_field &field : p.fields()) - { - if (field.type_class() != INPUT_CLASS_INTERNAL) - f_table[field.name()] = &field; - } - for(ioport_field &field : p.fields()) - { - if (field.type_class() != INPUT_CLASS_INTERNAL) - { - if(field.specific_name()) - f_table[field.specific_name()] = &field; - else - f_table[field.manager().type_name(field.type(), field.player())] = &field; - } - } - return f_table; - })); - - -/* ioport_field library - * - * manager:machine():ioport().ports[port_tag].fields[field_name] - * - * field:set_value(value) - * field:set_input_seq(seq_type, seq) - * field:input_seq(seq_type) - * field:set_default_input_seq(seq_type, seq) - * field:default_input_seq(seq_type) - * field:keyboard_codes(which) - * - * field.device - get associated device_t - * field.port - get associated ioport_port - * field.live - get ioport_field_live - * field.name - * field.default_name - * field.player - * field.mask - * field.defvalue - * field.sensitivity - * field.way - amount of available directions - * field.type_class - * field.is_analog - * field.is_digital_joystick - * field.enabled - * field.optional - * field.cocktail - * field.toggle - whether field is a toggle - * field.rotated - * field.analog_reverse - * field.analog_reset - * field.analog_wraps - * field.analog_invert - * field.impulse - * field.type - * field.crosshair_scale - * field.crosshair_offset - * field.user_value - * - * field.settings[] - ioport_setting table (k=value, v=name) - */ - - auto ioport_field_type = sol().registry().new_usertype("ioport_field", "new", sol::no_constructor); - ioport_field_type.set("set_value", &ioport_field::set_value); - ioport_field_type.set("set_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) { - input_seq_type seq_type = s_seq_type_parser(seq_type_string); - ioport_field::user_settings settings; - f.get_user_settings(settings); - settings.seq[seq_type] = seq; - f.set_user_settings(settings); - }); - ioport_field_type.set("input_seq", [](ioport_field &f, const std::string &seq_type_string) { - input_seq_type seq_type = s_seq_type_parser(seq_type_string); - return f.seq(seq_type); - }); - ioport_field_type.set("set_default_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) { - input_seq_type seq_type = s_seq_type_parser(seq_type_string); - f.set_defseq(seq_type, seq); - }); - ioport_field_type.set("default_input_seq", [](ioport_field &f, const std::string &seq_type_string) { - input_seq_type seq_type = s_seq_type_parser(seq_type_string); - return f.defseq(seq_type); - }); - ioport_field_type.set("keyboard_codes", [this](ioport_field &f, int which) { - sol::table result = sol().create_table(); - int index = 1; - for (char32_t code : f.keyboard_codes(which)) - result[index++] = code; - return result; - }); - ioport_field_type.set("device", sol::property(&ioport_field::device)); - ioport_field_type.set("port", sol::property(&ioport_field::port)); - ioport_field_type.set("name", sol::property(&ioport_field::name)); - ioport_field_type.set("default_name", sol::property([](ioport_field &f) { - return f.specific_name() ? f.specific_name() : f.manager().type_name(f.type(), f.player()); - })); - ioport_field_type.set("player", sol::property(&ioport_field::player, &ioport_field::set_player)); - ioport_field_type.set("mask", sol::property(&ioport_field::mask)); - ioport_field_type.set("defvalue", sol::property(&ioport_field::defvalue)); - ioport_field_type.set("sensitivity", sol::property(&ioport_field::sensitivity)); - ioport_field_type.set("way", sol::property(&ioport_field::way)); - ioport_field_type.set("type_class", sol::property([](ioport_field &f) { - switch (f.type_class()) - { - case INPUT_CLASS_KEYBOARD: return "keyboard"; - case INPUT_CLASS_CONTROLLER: return "controller"; - case INPUT_CLASS_CONFIG: return "config"; - case INPUT_CLASS_DIPSWITCH: return "dipswitch"; - case INPUT_CLASS_MISC: return "misc"; - default: break; - } - throw false; - })); - ioport_field_type.set("is_analog", sol::property(&ioport_field::is_analog)); - ioport_field_type.set("is_digital_joystick", sol::property(&ioport_field::is_digital_joystick)); - ioport_field_type.set("enabled", sol::property(&ioport_field::enabled)); - ioport_field_type.set("optional", sol::property(&ioport_field::optional)); - ioport_field_type.set("cocktail", sol::property(&ioport_field::cocktail)); - ioport_field_type.set("toggle", sol::property(&ioport_field::toggle)); - ioport_field_type.set("rotated", sol::property(&ioport_field::rotated)); - ioport_field_type.set("analog_reverse", sol::property(&ioport_field::analog_reverse)); - ioport_field_type.set("analog_reset", sol::property(&ioport_field::analog_reset)); - ioport_field_type.set("analog_wraps", sol::property(&ioport_field::analog_wraps)); - ioport_field_type.set("analog_invert", sol::property(&ioport_field::analog_invert)); - ioport_field_type.set("impulse", sol::property(&ioport_field::impulse)); - ioport_field_type.set("type", sol::property(&ioport_field::type)); - ioport_field_type.set("live", sol::property(&ioport_field::live)); - ioport_field_type.set("crosshair_scale", sol::property(&ioport_field::crosshair_scale, &ioport_field::set_crosshair_scale)); - ioport_field_type.set("crosshair_offset", sol::property(&ioport_field::crosshair_offset, &ioport_field::set_crosshair_offset)); - ioport_field_type.set("user_value", sol::property( - [](ioport_field &f) { - ioport_field::user_settings settings; - f.get_user_settings(settings); - return settings.value; - }, - [](ioport_field &f, ioport_value val) { - ioport_field::user_settings settings; - f.get_user_settings(settings); - settings.value = val; - f.set_user_settings(settings); - })); - ioport_field_type.set("settings", sol::property([this](ioport_field &f) { - sol::table result = sol().create_table(); - for (ioport_setting &setting : f.settings()) - if (setting.enabled()) - result[setting.value()] = setting.name(); - return result; - })); - - -/* ioport_field_live library - * - * manager:machine():ioport().ports[port_tag].fields[field_name].live - * - * live.name - */ - - sol().registry().new_usertype("ioport_field_live", "new", sol::no_constructor, - "name", &ioport_field_live::name); - - /* parameters_manager library * * manager:machine():parameters() @@ -2256,267 +1459,7 @@ void lua_engine::initialize() sound_type.set("attenuation", sol::property(&sound_manager::attenuation, &sound_manager::set_attenuation)); -/* input_manager library - * - * manager:machine():input() - * - * input:code_from_token(token) - get input_code for KEYCODE_* string token - * input:code_pressed(code) - get pressed state for input_code - * input:code_to_token(code) - get KEYCODE_* string token for code - * input:code_name(code) - get code friendly name - * input:seq_from_tokens(tokens) - get input_seq for multiple space separated KEYCODE_* string tokens - * input:seq_pressed(seq) - get pressed state for input_seq - * input:seq_to_tokens(seq) - get KEYCODE_* string tokens for seq - * input:seq_name(seq) - get seq friendly name - * input:seq_clean(seq) - clean the seq and remove invalid elements - * input:seq_poll_start(class, [opt] start_seq) - start polling for input_item_class passed as string - * (switch/abs[olute]/rel[ative]/max[imum]) - * input:seq_poll() - poll once, returns true if input was fetched - * input:seq_poll_final() - get final input_seq - * input.device_classes - returns device classes - */ - - auto input_type = sol().registry().new_usertype("input", "new", sol::no_constructor); - input_type.set("code_from_token", [](input_manager &input, const char *token) { return input.code_from_token(token); }); - input_type.set("code_pressed", [](input_manager &input, const input_code &code) { return input.code_pressed(code); }); - input_type.set("code_to_token", [](input_manager &input, const input_code &code) { return input.code_to_token(code); }); - input_type.set("code_name", [](input_manager &input, const input_code &code) { return input.code_name(code); }); - input_type.set("seq_from_tokens", [](input_manager &input, const char *tokens) { input_seq seq; input.seq_from_tokens(seq, tokens); return seq; }); - input_type.set("seq_pressed", [](input_manager &input, const input_seq &seq) { return input.seq_pressed(seq); }); - input_type.set("seq_to_tokens", [](input_manager &input, const input_seq &seq) { return input.seq_to_tokens(seq); }); - input_type.set("seq_name", [](input_manager &input, const input_seq &seq) { return input.seq_name(seq); }); - input_type.set("seq_clean", [](input_manager &input, const input_seq &seq) { return input.seq_clean(seq); }); - input_type.set("seq_poll_start", [this](input_manager &input, const char *cls_string, sol::object seq) { - if (!m_seq_poll) - m_seq_poll.reset(new input_sequence_poller(input)); - - input_item_class cls; - if (!strcmp(cls_string, "switch")) - cls = ITEM_CLASS_SWITCH; - else if (!strcmp(cls_string, "absolute") || !strcmp(cls_string, "abs")) - cls = ITEM_CLASS_ABSOLUTE; - else if (!strcmp(cls_string, "relative") || !strcmp(cls_string, "rel")) - cls = ITEM_CLASS_RELATIVE; - else if (!strcmp(cls_string, "maximum") || !strcmp(cls_string, "max")) - cls = ITEM_CLASS_MAXIMUM; - else - cls = ITEM_CLASS_INVALID; - - if (seq.is>()) - m_seq_poll->start(cls, seq.as>()); - else - m_seq_poll->start(cls); - }); - input_type.set("seq_poll", [this](input_manager &input) -> sol::object { - if (!m_seq_poll) - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), m_seq_poll->poll()); - }); - input_type.set("seq_poll_final", [this](input_manager &input) -> sol::object { - if (!m_seq_poll) - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), m_seq_poll->valid() ? m_seq_poll->sequence() : input_seq()); - }); - input_type.set("seq_poll_modified", [this](input_manager &input) -> sol::object { - if (!m_seq_poll) - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), m_seq_poll->modified()); - }); - input_type.set("seq_poll_valid", [this](input_manager &input) -> sol::object { - if (!m_seq_poll) - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), m_seq_poll->valid()); - }); - input_type.set("seq_poll_sequence", [this](input_manager &input) -> sol::object { - if (!m_seq_poll) - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), m_seq_poll->sequence()); - }); - input_type.set("device_classes", sol::property([this](input_manager &input) { - sol::table result = sol().create_table(); - for (input_device_class devclass_id = DEVICE_CLASS_FIRST_VALID; devclass_id <= DEVICE_CLASS_LAST_VALID; devclass_id++) - { - input_class &devclass = input.device_class(devclass_id); - result[devclass.name()] = &devclass; - } - return result; - })); - - -/* input_class library - * - * manager:machine():input().device_classes[devclass] - * - * devclass.name - * devclass.enabled - * devclass.multi - * devclass.devices[] - */ - - auto input_class_type = sol().registry().new_usertype("input_class", "new", sol::no_constructor); - input_class_type.set("name", sol::property(&input_class::name)); - input_class_type.set("enabled", sol::property(&input_class::enabled, &input_class::enable)); - input_class_type.set("multi", sol::property(&input_class::multi, &input_class::set_multi)); - input_class_type.set("devices", sol::property([this](input_class &devclass) { - sol::table result = sol().create_table(); - int index = 1; - for (int devindex = 0; devindex <= devclass.maxindex(); devindex++) - { - input_device *dev = devclass.device(devindex); - if (dev) - result[index++] = dev; - } - return result; - })); - - -/* input_device library - * - * manager:machine():input().device_classes[devclass].devices[index] - * device.name - * device.id - * device.devindex - * device.items[] - */ - - auto input_device_type = sol().registry().new_usertype("input_device", "new", sol::no_constructor); - input_device_type.set("name", sol::property(&input_device::name)); - input_device_type.set("id", sol::property(&input_device::id)); - input_device_type.set("devindex", sol::property(&input_device::devindex)); - input_device_type.set("items", sol::property([this](input_device &dev) { - sol::table result = sol().create_table(); - for (input_item_id id = ITEM_ID_FIRST_VALID; id < dev.maxitem(); id++) - { - input_device_item *item = dev.item(id); - if (item) - result[id] = dev.item(id); - } - return result; - })); - - -/* input_device_item library - * - * manager:machine():input().device_classes[devclass].devices[index].items[item_id] - * item.name - * item.token - * item:code() - */ - - auto input_device_item_type = sol().registry().new_usertype("input_device_item", "new", sol::no_constructor); - input_device_item_type.set("name", sol::property(&input_device_item::name)); - input_device_item_type.set("token", sol::property(&input_device_item::token)); - input_device_item_type.set("code", [](input_device_item &item) { - return input_code(item.device().devclass(), item.device().devindex(), item.itemclass(), ITEM_MODIFIER_NONE, item.itemid()); - }); - - -/* ui_input_manager library - * - * manager:machine():uiinput() - * - * uiinput:find_mouse() - return x, y, button state, ui render target - * uiinput:pressed(key) - get pressed state for ui key - * uiinput.presses_enabled - enable/disable ui key presses - */ - - auto uiinput_type = sol().registry().new_usertype("uiinput", "new", sol::no_constructor); - uiinput_type.set("find_mouse", [](ui_input_manager &ui) { - int32_t x, y; - bool button; - render_target *rt = ui.find_mouse(&x, &y, &button); - return std::tuple(x, y, button, rt); - }); - uiinput_type.set("pressed", &ui_input_manager::pressed); - uiinput_type.set("presses_enabled", sol::property(&ui_input_manager::presses_enabled, &ui_input_manager::set_presses_enabled)); - - -/* render_target library - * - * manager:machine():render().targets[target_index] - * manager:machine():render():ui_target() - * - * target:view_bounds() - get x0, x1, y0, y1 bounds for target - * target:width() - get target width - * target:height() - get target height - * target:pixel_aspect() - get target aspect - * target:hidden() - is target hidden - * target:is_ui_target() - is ui render target - * target:index() - target index - * target:view_name([opt] index) - current target layout view name - * - * target.max_update_rate - - * target.view - current target layout view - * target.orientation - current target orientation - * target.screen_overlay - enable overlays - * target.zoom - enable zoom - */ - - auto target_type = sol().registry().new_usertype("target", "new", sol::no_constructor); - target_type.set("view_bounds", [](render_target &rt) { - const render_bounds b = rt.current_view().bounds(); - return std::tuple(b.x0, b.x1, b.y0, b.y1); - }); - target_type.set("width", &render_target::width); - target_type.set("height", &render_target::height); - target_type.set("pixel_aspect", &render_target::pixel_aspect); - target_type.set("hidden", &render_target::hidden); - target_type.set("is_ui_target", &render_target::is_ui_target); - target_type.set("index", &render_target::index); - target_type.set("view_name", &render_target::view_name); - target_type.set("max_update_rate", sol::property(&render_target::max_update_rate, &render_target::set_max_update_rate)); - target_type.set("view", sol::property(&render_target::view, &render_target::set_view)); - target_type.set("orientation", sol::property(&render_target::orientation, &render_target::set_orientation)); - target_type.set("screen_overlay", sol::property(&render_target::screen_overlay_enabled, &render_target::set_screen_overlay_enabled)); - target_type.set("zoom", sol::property(&render_target::zoom_to_screen, &render_target::set_zoom_to_screen)); - - -/* render_container library - * - * manager:machine():render():ui_container() - * - * container:orientation() - * container:xscale() - * container:yscale() - * container:xoffset() - * container:yoffset() - * container:is_empty() - */ - - auto render_container_type = sol().registry().new_usertype("render_container", "new", sol::no_constructor); - render_container_type.set("orientation", &render_container::orientation); - render_container_type.set("xscale", &render_container::xscale); - render_container_type.set("yscale", &render_container::yscale); - render_container_type.set("xoffset", &render_container::xoffset); - render_container_type.set("yoffset", &render_container::yoffset); - render_container_type.set("is_empty", &render_container::is_empty); - - -/* render_manager library - * - * manager:machine():render() - * - * render:max_update_rate() - - * render:ui_target() - render_target for ui drawing - * render:ui_container() - render_container for ui drawing - * - * render.targets[] - render_target table - */ - - auto render_type = sol().registry().new_usertype("render", "new", sol::no_constructor); - render_type.set("max_update_rate", &render_manager::max_update_rate); - render_type.set("ui_target", &render_manager::ui_target); - render_type.set("ui_container", &render_manager::ui_container); - render_type.set("targets", sol::property([this](render_manager &r) { - sol::table target_table = sol().create_table(); - int tc = 0; - for(render_target &curr_rt : r.targets()) - target_table[tc++] = &curr_rt; - return target_table; - })); - - -/* screen_device library +/* screen_device library * * manager:machine().screens[screen_tag] * @@ -2755,98 +1698,6 @@ void lua_engine::initialize() rom_entry_type.set("flags", &rom_entry::get_flags); -/* memory_manager library - * - * manager:machine():memory() - * - * memory.banks[] - table of memory banks (k=tag, v=memory_bank) - * memory.regions[] - table of memory regions (k=tag, v=memory_region) - * memory.shares[] - table of memory shares (k=tag, v=memory_share) - */ - - auto memory_type = sol().registry().new_usertype("memory", "new", sol::no_constructor); - memory_type.set("banks", sol::property([this](memory_manager &mm) { - sol::table table = sol().create_table(); - for (auto &bank : mm.banks()) - table[bank.second->tag()] = bank.second.get(); - return table; - })); - memory_type.set("regions", sol::property([this](memory_manager &mm) { - sol::table table = sol().create_table(); - for (auto ®ion : mm.regions()) - table[region.second->name()] = region.second.get(); - return table; - })); - memory_type.set("shares", sol::property([this](memory_manager &mm) { - sol::table table = sol().create_table(); - for (auto &share : mm.shares()) - table[share.first] = share.second.get(); - return table; - })); - - -/* memory_region library - * - * manager:machine():memory().regions[region_tag] - * - * read/write by signedness u/i and bit-width 8/16/32/64: - * region:read_*(addr) - * region:write_*(addr, val) - * - * region.size - */ - - auto region_type = sol().registry().new_usertype("region", "new", sol::no_constructor); - region_type.set("read_i8", ®ion_read); - region_type.set("read_u8", ®ion_read); - region_type.set("read_i16", ®ion_read); - region_type.set("read_u16", ®ion_read); - region_type.set("read_i32", ®ion_read); - region_type.set("read_u32", ®ion_read); - region_type.set("read_i64", ®ion_read); - region_type.set("read_u64", ®ion_read); - region_type.set("write_i8", ®ion_write); - region_type.set("write_u8", ®ion_write); - region_type.set("write_i16", ®ion_write); - region_type.set("write_u16", ®ion_write); - region_type.set("write_i32", ®ion_write); - region_type.set("write_u32", ®ion_write); - region_type.set("write_i64", ®ion_write); - region_type.set("write_u64", ®ion_write); - region_type.set("size", sol::property(&memory_region::bytes)); - - -/* memory_share library - * - * manager:machine():memory().shares[share_tag] - * - * read/write by signedness u/i and bit-width 8/16/32/64: - * share:read_*(addr) - * share:write_*(addr, val) - * - * region.size -*/ - - auto share_type = sol().registry().new_usertype("share", "new", sol::no_constructor); - share_type.set("read_i8", &share_read); - share_type.set("read_u8", &share_read); - share_type.set("read_i16", &share_read); - share_type.set("read_u16", &share_read); - share_type.set("read_i32", &share_read); - share_type.set("read_u32", &share_read); - share_type.set("read_i64", &share_read); - share_type.set("read_u64", &share_read); - share_type.set("write_i8", &share_write); - share_type.set("write_u8", &share_write); - share_type.set("write_i16", &share_write); - share_type.set("write_u16", &share_write); - share_type.set("write_i32", &share_write); - share_type.set("write_u32", &share_write); - share_type.set("write_i64", &share_write); - share_type.set("write_u64", &share_write); - share_type.set("size", sol::property(&memory_share::bytes)); - - /* output_manager library * * manager:machine():outputs() @@ -2960,6 +1811,12 @@ void lua_engine::initialize() "ui", &mame_machine_manager::ui); sol()["manager"] = std::ref(*mame_machine_manager::instance()); sol()["mame_manager"] = std::ref(*mame_machine_manager::instance()); + + + // set up other user types + initialize_input(); + initialize_memory(); + initialize_render(); } //------------------------------------------------- diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index a158b496bdd..ed871d53287 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -15,8 +15,11 @@ #include "iptseqpoll.h" #include +#include #include #include +#include +#include #if defined(__GNUC__) && (__GNUC__ > 6) #pragma GCC diagnostic ignored "-Wnoexcept-type" @@ -110,6 +113,8 @@ public: sol::state_view &sol() const { return *m_sol_state; } private: + template class enum_parser; + // internal state lua_State *m_lua_state; std::unique_ptr m_sol_state; @@ -133,24 +138,7 @@ private: bool execute_function(const char *id); sol::object call_plugin(const std::string &name, sol::object in); - struct addr_space { - addr_space(address_space &space, device_memory_interface &dev) : - space(space), dev(dev) {} - template T mem_read(offs_t address); - template void mem_write(offs_t address, T val); - template T log_mem_read(offs_t address); - template void log_mem_write(offs_t address, T val); - template T direct_mem_read(offs_t address); - template void direct_mem_write(offs_t address, T val); - - address_space &space; - device_memory_interface &dev; - }; - - template static T share_read(memory_share &share, offs_t address); - template static void share_write(memory_share &share, offs_t address, T val); - template static T region_read(memory_region ®ion, offs_t address); - template static void region_write(memory_region ®ion, offs_t address, T val); + struct addr_space; struct save_item { void *base; @@ -176,6 +164,10 @@ private: template sol::protected_function_result invoke(TFunc &&func, TArgs&&... args); + + void initialize_input(); + void initialize_memory(); + void initialize_render(); }; #endif // MAME_FRONTEND_MAME_LUAENGINE_H diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp new file mode 100644 index 00000000000..cb6824dd262 --- /dev/null +++ b/src/frontend/mame/luaengine.ipp @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + luaengine.ipp + + Controls execution of the core MAME system. + +***************************************************************************/ +#ifndef MAME_FRONTEND_MAME_LUAENGINE_IPP +#define MAME_FRONTEND_MAME_LUAENGINE_IPP + +#include "luaengine.h" + +#include "options.h" + +#include + + +namespace sol { + +class buffer +{ +public: + // sol does lua_settop(0), save userdata buffer in registry if necessary + buffer(int size, lua_State *L) + { + ptr = luaL_buffinitsize(L, &buff, size); + len = size; + if(buff.b != buff.initb) + { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); + } + } + ~buffer() + { + lua_State *L = buff.L; + if(lua_getfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp") != LUA_TNIL) + { + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, "sol::buffer_temp"); + } + else + lua_pop(L, -1); + + luaL_pushresultsize(&buff, len); + } + + void set_len(int size) { len = size; } + int get_len() { return len; } + char *get_ptr() { return ptr; } + +private: + luaL_Buffer buff; + int len; + char *ptr; +}; + + +// don't convert core_optons to a table directly +template<> struct is_container : std::false_type { }; + +sol::buffer *sol_lua_get(sol::types, lua_State *L, int index, sol::stack::record &tracking); +int sol_lua_push(sol::types, lua_State *L, buffer *value); + +} // namespace sol + + +int sol_lua_push(sol::types, lua_State *L, osd_file::error &&value); +template +bool sol_lua_check(sol::types, lua_State *L, int index, Handler &&handler, sol::stack::record &tracking); + +int sol_lua_push(sol::types, lua_State *L, map_handler_type &&value); + + +struct lua_engine::addr_space +{ + addr_space(address_space &s, device_memory_interface &d) : space(s), dev(d) { } + + template T mem_read(offs_t address); + template void mem_write(offs_t address, T val); + template T log_mem_read(offs_t address); + template void log_mem_write(offs_t address, T val); + template T direct_mem_read(offs_t address); + template void direct_mem_write(offs_t address, T val); + + address_space &space; + device_memory_interface &dev; +}; + + +template +class lua_engine::enum_parser +{ +public: + constexpr enum_parser(std::initializer_list> values) + { + if (values.size() != SIZE) + throw false && "size template argument incorrectly specified"; + std::copy(values.begin(), values.end(), m_map.begin()); + } + + T operator()(const char *text) const + { + auto iter = std::find_if( + m_map.begin() + 1, + m_map.end(), + [text](const auto &x) { return !strcmp(text, x.first); }); + if (iter == m_map.end()) + iter = m_map.begin(); + return iter->second; + } + + T operator()(const std::string &text) const + { + return (*this)(text.c_str()); + } + +private: + std::array, SIZE> m_map; +}; + +#endif // MAME_FRONTEND_MAME_LUAENGINE_IPP diff --git a/src/frontend/mame/luaengine_input.cpp b/src/frontend/mame/luaengine_input.cpp new file mode 100644 index 00000000000..f954038b70f --- /dev/null +++ b/src/frontend/mame/luaengine_input.cpp @@ -0,0 +1,441 @@ +// 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 "inputdev.h" +#include "natkeyboard.h" +#include "render.h" +#include "uiinput.h" + + +//------------------------------------------------- +// initialize_input - register input user types +//------------------------------------------------- + +void lua_engine::initialize_input() +{ + + static const enum_parser s_seq_type_parser = + { + { "standard", SEQ_TYPE_STANDARD }, + { "increment", SEQ_TYPE_INCREMENT }, + { "decrement", SEQ_TYPE_DECREMENT }, + }; + + +/* ioport_manager library + * + * manager:machine():ioport() + * + * ioport:count_players() - get count of player controllers + * ioport:type_group(type, player) + * ioport:type_seq(type, player, seqtype) - get input sequence for ioport type/player + * + * ioport.ports[] - ioports table (k=tag, v=ioport_port) + */ + + auto ioport_manager_type = sol().registry().new_usertype("ioport", "new", sol::no_constructor); + ioport_manager_type.set("count_players", &ioport_manager::count_players); + ioport_manager_type.set("natkeyboard", &ioport_manager::natkeyboard); + ioport_manager_type.set("type_group", [](ioport_manager &im, ioport_type type, int player) { + return im.type_group(type, player); + }); + ioport_manager_type.set("ports", sol::property([this](ioport_manager &im) { + sol::table port_table = sol().create_table(); + for (auto &port : im.ports()) + port_table[port.second->tag()] = port.second.get(); + return port_table; + })); + ioport_manager_type.set("type_seq", [](ioport_manager &m, ioport_type type, int player, input_seq_type seqtype) { + return m.type_seq(type, player, seqtype); + }); + + +/* natural_keyboard library + * + * manager:machine():ioport():natkeyboard() + * + * natkeyboard:paste() - paste clipboard data + * natkeyboard:post() - post data to natural keyboard + * natkeyboard:post_coded() - post data to natural keyboard + * + * natkeyboard.empty - is the natural keyboard buffer empty? + * natkeyboard.in_use - is the natural keyboard in use? + */ + + auto natkeyboard_type = sol().registry().new_usertype("natkeyboard", "new", sol::no_constructor); + natkeyboard_type.set("empty", sol::property(&natural_keyboard::empty)); + natkeyboard_type.set("in_use", sol::property(&natural_keyboard::in_use, &natural_keyboard::set_in_use)); + natkeyboard_type.set("paste", &natural_keyboard::paste); + natkeyboard_type.set("post", [](natural_keyboard &nat, const std::string &text) { nat.post_utf8(text); }); + natkeyboard_type.set("post_coded", [](natural_keyboard &nat, const std::string &text) { nat.post_coded(text); }); + + +/* ioport_port library + * + * manager:machine():ioport().ports[port_tag] + * + * port:tag() - get port tag + * port:active() - get port status + * port:live() - get port ioport_port_live (TODO: not usable from lua as of now) + * port:read() - get port value + * port:write(val, mask) - set port to value & mask (output fields only, for other fields use field:set_value(val)) + * port:field(mask) - get ioport_field for port and mask + * + * port.fields[] - get ioport_field table (k=name, v=ioport_field) + */ + + auto ioport_port_type = sol().registry().new_usertype("ioport_port", "new", sol::no_constructor); + ioport_port_type.set("tag", &ioport_port::tag); + ioport_port_type.set("active", &ioport_port::active); + ioport_port_type.set("live", &ioport_port::live); + ioport_port_type.set("read", &ioport_port::read); + ioport_port_type.set("write", &ioport_port::write); + ioport_port_type.set("field", &ioport_port::field); + ioport_port_type.set("fields", sol::property([this](ioport_port &p){ + sol::table f_table = sol().create_table(); + // parse twice for custom and default names, default has priority + for(ioport_field &field : p.fields()) + { + if (field.type_class() != INPUT_CLASS_INTERNAL) + f_table[field.name()] = &field; + } + for(ioport_field &field : p.fields()) + { + if (field.type_class() != INPUT_CLASS_INTERNAL) + { + if(field.specific_name()) + f_table[field.specific_name()] = &field; + else + f_table[field.manager().type_name(field.type(), field.player())] = &field; + } + } + return f_table; + })); + + +/* ioport_field library + * + * manager:machine():ioport().ports[port_tag].fields[field_name] + * + * field:set_value(value) + * field:set_input_seq(seq_type, seq) + * field:input_seq(seq_type) + * field:set_default_input_seq(seq_type, seq) + * field:default_input_seq(seq_type) + * field:keyboard_codes(which) + * + * field.device - get associated device_t + * field.port - get associated ioport_port + * field.live - get ioport_field_live + * field.name + * field.default_name + * field.player + * field.mask + * field.defvalue + * field.sensitivity + * field.way - amount of available directions + * field.type_class + * field.is_analog + * field.is_digital_joystick + * field.enabled + * field.optional + * field.cocktail + * field.toggle - whether field is a toggle + * field.rotated + * field.analog_reverse + * field.analog_reset + * field.analog_wraps + * field.analog_invert + * field.impulse + * field.type + * field.crosshair_scale + * field.crosshair_offset + * field.user_value + * + * field.settings[] - ioport_setting table (k=value, v=name) + */ + + auto ioport_field_type = sol().registry().new_usertype("ioport_field", "new", sol::no_constructor); + ioport_field_type.set("set_value", &ioport_field::set_value); + ioport_field_type.set("set_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) { + input_seq_type seq_type = s_seq_type_parser(seq_type_string); + ioport_field::user_settings settings; + f.get_user_settings(settings); + settings.seq[seq_type] = seq; + f.set_user_settings(settings); + }); + ioport_field_type.set("input_seq", [](ioport_field &f, const std::string &seq_type_string) { + input_seq_type seq_type = s_seq_type_parser(seq_type_string); + return f.seq(seq_type); + }); + ioport_field_type.set("set_default_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) { + input_seq_type seq_type = s_seq_type_parser(seq_type_string); + f.set_defseq(seq_type, seq); + }); + ioport_field_type.set("default_input_seq", [](ioport_field &f, const std::string &seq_type_string) { + input_seq_type seq_type = s_seq_type_parser(seq_type_string); + return f.defseq(seq_type); + }); + ioport_field_type.set("keyboard_codes", [this](ioport_field &f, int which) { + sol::table result = sol().create_table(); + int index = 1; + for (char32_t code : f.keyboard_codes(which)) + result[index++] = code; + return result; + }); + ioport_field_type.set("device", sol::property(&ioport_field::device)); + ioport_field_type.set("port", sol::property(&ioport_field::port)); + ioport_field_type.set("name", sol::property(&ioport_field::name)); + ioport_field_type.set("default_name", sol::property([](ioport_field &f) { + return f.specific_name() ? f.specific_name() : f.manager().type_name(f.type(), f.player()); + })); + ioport_field_type.set("player", sol::property(&ioport_field::player, &ioport_field::set_player)); + ioport_field_type.set("mask", sol::property(&ioport_field::mask)); + ioport_field_type.set("defvalue", sol::property(&ioport_field::defvalue)); + ioport_field_type.set("sensitivity", sol::property(&ioport_field::sensitivity)); + ioport_field_type.set("way", sol::property(&ioport_field::way)); + ioport_field_type.set("type_class", sol::property([](ioport_field &f) { + switch (f.type_class()) + { + case INPUT_CLASS_KEYBOARD: return "keyboard"; + case INPUT_CLASS_CONTROLLER: return "controller"; + case INPUT_CLASS_CONFIG: return "config"; + case INPUT_CLASS_DIPSWITCH: return "dipswitch"; + case INPUT_CLASS_MISC: return "misc"; + default: break; + } + throw false; + })); + ioport_field_type.set("is_analog", sol::property(&ioport_field::is_analog)); + ioport_field_type.set("is_digital_joystick", sol::property(&ioport_field::is_digital_joystick)); + ioport_field_type.set("enabled", sol::property(&ioport_field::enabled)); + ioport_field_type.set("optional", sol::property(&ioport_field::optional)); + ioport_field_type.set("cocktail", sol::property(&ioport_field::cocktail)); + ioport_field_type.set("toggle", sol::property(&ioport_field::toggle)); + ioport_field_type.set("rotated", sol::property(&ioport_field::rotated)); + ioport_field_type.set("analog_reverse", sol::property(&ioport_field::analog_reverse)); + ioport_field_type.set("analog_reset", sol::property(&ioport_field::analog_reset)); + ioport_field_type.set("analog_wraps", sol::property(&ioport_field::analog_wraps)); + ioport_field_type.set("analog_invert", sol::property(&ioport_field::analog_invert)); + ioport_field_type.set("impulse", sol::property(&ioport_field::impulse)); + ioport_field_type.set("type", sol::property(&ioport_field::type)); + ioport_field_type.set("live", sol::property(&ioport_field::live)); + ioport_field_type.set("crosshair_scale", sol::property(&ioport_field::crosshair_scale, &ioport_field::set_crosshair_scale)); + ioport_field_type.set("crosshair_offset", sol::property(&ioport_field::crosshair_offset, &ioport_field::set_crosshair_offset)); + ioport_field_type.set("user_value", sol::property( + [](ioport_field &f) { + ioport_field::user_settings settings; + f.get_user_settings(settings); + return settings.value; + }, + [](ioport_field &f, ioport_value val) { + ioport_field::user_settings settings; + f.get_user_settings(settings); + settings.value = val; + f.set_user_settings(settings); + })); + ioport_field_type.set("settings", sol::property([this](ioport_field &f) { + sol::table result = sol().create_table(); + for (ioport_setting &setting : f.settings()) + if (setting.enabled()) + result[setting.value()] = setting.name(); + return result; + })); + + +/* ioport_field_live library + * + * manager:machine():ioport().ports[port_tag].fields[field_name].live + * + * live.name + */ + + sol().registry().new_usertype("ioport_field_live", "new", sol::no_constructor, + "name", &ioport_field_live::name); + + +/* input_manager library + * + * manager:machine():input() + * + * input:code_from_token(token) - get input_code for KEYCODE_* string token + * input:code_pressed(code) - get pressed state for input_code + * input:code_to_token(code) - get KEYCODE_* string token for code + * input:code_name(code) - get code friendly name + * input:seq_from_tokens(tokens) - get input_seq for multiple space separated KEYCODE_* string tokens + * input:seq_pressed(seq) - get pressed state for input_seq + * input:seq_to_tokens(seq) - get KEYCODE_* string tokens for seq + * input:seq_name(seq) - get seq friendly name + * input:seq_clean(seq) - clean the seq and remove invalid elements + * input:seq_poll_start(class, [opt] start_seq) - start polling for input_item_class passed as string + * (switch/abs[olute]/rel[ative]/max[imum]) + * input:seq_poll() - poll once, returns true if input was fetched + * input:seq_poll_final() - get final input_seq + * input.device_classes - returns device classes + */ + + auto input_type = sol().registry().new_usertype("input", "new", sol::no_constructor); + input_type.set("code_from_token", [](input_manager &input, const char *token) { return input.code_from_token(token); }); + input_type.set("code_pressed", [](input_manager &input, const input_code &code) { return input.code_pressed(code); }); + input_type.set("code_to_token", [](input_manager &input, const input_code &code) { return input.code_to_token(code); }); + input_type.set("code_name", [](input_manager &input, const input_code &code) { return input.code_name(code); }); + input_type.set("seq_from_tokens", [](input_manager &input, const char *tokens) { input_seq seq; input.seq_from_tokens(seq, tokens); return seq; }); + input_type.set("seq_pressed", [](input_manager &input, const input_seq &seq) { return input.seq_pressed(seq); }); + input_type.set("seq_to_tokens", [](input_manager &input, const input_seq &seq) { return input.seq_to_tokens(seq); }); + input_type.set("seq_name", [](input_manager &input, const input_seq &seq) { return input.seq_name(seq); }); + input_type.set("seq_clean", [](input_manager &input, const input_seq &seq) { return input.seq_clean(seq); }); + input_type.set("seq_poll_start", [this](input_manager &input, const char *cls_string, sol::object seq) { + if (!m_seq_poll) + m_seq_poll.reset(new input_sequence_poller(input)); + + input_item_class cls; + if (!strcmp(cls_string, "switch")) + cls = ITEM_CLASS_SWITCH; + else if (!strcmp(cls_string, "absolute") || !strcmp(cls_string, "abs")) + cls = ITEM_CLASS_ABSOLUTE; + else if (!strcmp(cls_string, "relative") || !strcmp(cls_string, "rel")) + cls = ITEM_CLASS_RELATIVE; + else if (!strcmp(cls_string, "maximum") || !strcmp(cls_string, "max")) + cls = ITEM_CLASS_MAXIMUM; + else + cls = ITEM_CLASS_INVALID; + + if (seq.is>()) + m_seq_poll->start(cls, seq.as>()); + else + m_seq_poll->start(cls); + }); + input_type.set("seq_poll", [this](input_manager &input) -> sol::object { + if (!m_seq_poll) + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), m_seq_poll->poll()); + }); + input_type.set("seq_poll_final", [this](input_manager &input) -> sol::object { + if (!m_seq_poll) + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), m_seq_poll->valid() ? m_seq_poll->sequence() : input_seq()); + }); + input_type.set("seq_poll_modified", [this](input_manager &input) -> sol::object { + if (!m_seq_poll) + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), m_seq_poll->modified()); + }); + input_type.set("seq_poll_valid", [this](input_manager &input) -> sol::object { + if (!m_seq_poll) + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), m_seq_poll->valid()); + }); + input_type.set("seq_poll_sequence", [this](input_manager &input) -> sol::object { + if (!m_seq_poll) + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), m_seq_poll->sequence()); + }); + input_type.set("device_classes", sol::property([this](input_manager &input) { + sol::table result = sol().create_table(); + for (input_device_class devclass_id = DEVICE_CLASS_FIRST_VALID; devclass_id <= DEVICE_CLASS_LAST_VALID; devclass_id++) + { + input_class &devclass = input.device_class(devclass_id); + result[devclass.name()] = &devclass; + } + return result; + })); + + +/* input_class library + * + * manager:machine():input().device_classes[devclass] + * + * devclass.name + * devclass.enabled + * devclass.multi + * devclass.devices[] + */ + + auto input_class_type = sol().registry().new_usertype("input_class", "new", sol::no_constructor); + input_class_type.set("name", sol::property(&input_class::name)); + input_class_type.set("enabled", sol::property(&input_class::enabled, &input_class::enable)); + input_class_type.set("multi", sol::property(&input_class::multi, &input_class::set_multi)); + input_class_type.set("devices", sol::property([this](input_class &devclass) { + sol::table result = sol().create_table(); + int index = 1; + for (int devindex = 0; devindex <= devclass.maxindex(); devindex++) + { + input_device *dev = devclass.device(devindex); + if (dev) + result[index++] = dev; + } + return result; + })); + + +/* input_device library + * + * manager:machine():input().device_classes[devclass].devices[index] + * device.name + * device.id + * device.devindex + * device.items[] + */ + + auto input_device_type = sol().registry().new_usertype("input_device", "new", sol::no_constructor); + input_device_type.set("name", sol::property(&input_device::name)); + input_device_type.set("id", sol::property(&input_device::id)); + input_device_type.set("devindex", sol::property(&input_device::devindex)); + input_device_type.set("items", sol::property([this](input_device &dev) { + sol::table result = sol().create_table(); + for (input_item_id id = ITEM_ID_FIRST_VALID; id < dev.maxitem(); id++) + { + input_device_item *item = dev.item(id); + if (item) + result[id] = dev.item(id); + } + return result; + })); + + +/* input_device_item library + * + * manager:machine():input().device_classes[devclass].devices[index].items[item_id] + * item.name + * item.token + * item:code() + */ + + auto input_device_item_type = sol().registry().new_usertype("input_device_item", "new", sol::no_constructor); + input_device_item_type.set("name", sol::property(&input_device_item::name)); + input_device_item_type.set("token", sol::property(&input_device_item::token)); + input_device_item_type.set("code", [](input_device_item &item) { + return input_code(item.device().devclass(), item.device().devindex(), item.itemclass(), ITEM_MODIFIER_NONE, item.itemid()); + }); + + +/* ui_input_manager library + * + * manager:machine():uiinput() + * + * uiinput:find_mouse() - return x, y, button state, ui render target + * uiinput:pressed(key) - get pressed state for ui key + * uiinput.presses_enabled - enable/disable ui key presses + */ + + auto uiinput_type = sol().registry().new_usertype("uiinput", "new", sol::no_constructor); + uiinput_type.set("find_mouse", [](ui_input_manager &ui) { + int32_t x, y; + bool button; + render_target *rt = ui.find_mouse(&x, &y, &button); + return std::tuple(x, y, button, rt); + }); + uiinput_type.set("pressed", &ui_input_manager::pressed); + uiinput_type.set("presses_enabled", sol::property(&ui_input_manager::presses_enabled, &ui_input_manager::set_presses_enabled)); + +} diff --git a/src/frontend/mame/luaengine_mem.cpp b/src/frontend/mame/luaengine_mem.cpp new file mode 100644 index 00000000000..d34043a1a55 --- /dev/null +++ b/src/frontend/mame/luaengine_mem.cpp @@ -0,0 +1,603 @@ +// 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" + + +namespace { + +//------------------------------------------------- +// region_read - templated region readers for , +// -> manager:machine():memory().regions[":maincpu"]:read_i8(0xC000) +//------------------------------------------------- + +template +T region_read(memory_region ®ion, offs_t address) +{ + T mem_content = 0; + 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()) + { + 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 , +// -> manager:machine():memory().regions[":maincpu"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template +void region_write(memory_region ®ion, offs_t address, T val) +{ + 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; + val >>= 8; + } + } +} + +//------------------------------------------------- +// share_read - templated share readers for , +// -> manager:machine():memory().shares[":maincpu"]:read_i8(0xC000) +//------------------------------------------------- + +template +T share_read(memory_share &share, offs_t address) +{ + T mem_content = 0; + offs_t lowmask = share.bytewidth() - 1; + uint8_t *ptr = (uint8_t *)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()) + { + 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 , +// -> manager:machine():memory().shares[":maincpu"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template +void share_write(memory_share &share, offs_t address, T val) +{ + offs_t lowmask = share.bytewidth() - 1; + uint8_t *ptr = (uint8_t *)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; + val >>= 8; + } + } +} + +} // anonymous namespace + + + +//------------------------------------------------- +// mem_read - templated memory readers for , +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_i8(0xC000) +//------------------------------------------------- + +template +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 , +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template +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 , +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_log_i8(0xC000) +//------------------------------------------------- + +template +T lua_engine::addr_space::log_mem_read(offs_t address) +{ + if (!dev.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + return 0; + + 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; +} + +//------------------------------------------------- +// log_mem_write - templated logical memory writer for , +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_log_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template +void lua_engine::addr_space::log_mem_write(offs_t address, T val) +{ + if (!dev.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) + return; + + 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; + } +} + +//------------------------------------------------- +// mem_direct_read - templated direct memory readers for , +// -> manager:machine().devices[":maincpu"].spaces["program"]:read_direct_i8(0xC000) +//------------------------------------------------- + +template +T lua_engine::addr_space::direct_mem_read(offs_t address) +{ + T mem_content = 0; + 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; + uint8_t *base = (uint8_t *)space.get_read_ptr(addr & ~lowmask); + if (base) + { + 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 , +// -> manager:machine().devices[":maincpu"].spaces["program"]:write_direct_u16(0xC000, 0xF00D) +//------------------------------------------------- + +template +void lua_engine::addr_space::direct_mem_write(offs_t address, T val) +{ + 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; + uint8_t *base = (uint8_t *)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; + val >>= 8; + } + } +} + +//------------------------------------------------- +// initialize_memory - register memory user types +//------------------------------------------------- + +void lua_engine::initialize_memory() +{ + +/* addr_space library + * + * manager:machine().devices[device_tag].spaces[space] + * + * read/write by signedness u/i and bit-width 8/16/32/64: + * space:read_*(addr) + * space:write_*(addr, val) + * space:read_log_*(addr) + * space:write_log_*(addr, val) + * space:read_direct_*(addr) + * space:write_direct_*(addr, val) + * space:read_range(first_addr, last_addr, width, [opt] step) - read range of addresses and + * return as a binary string + * + * space.name - address space name + * space.shift - address bus shift, bitshift required for a bytewise address + * to map onto this space's address resolution (addressing granularity). + * positive value means leftshift, negative means rightshift. + * space.index + * space.address_mask + * space.data_width + * space.endianness + * + * space.map[] - table of address map entries (k=index, v=address_map_entry) + */ + + auto addr_space_type = sol().registry().new_usertype("addr_space", sol::call_constructor, sol::constructors>()); + addr_space_type.set("read_i8", &addr_space::mem_read); + addr_space_type.set("read_u8", &addr_space::mem_read); + addr_space_type.set("read_i16", &addr_space::mem_read); + addr_space_type.set("read_u16", &addr_space::mem_read); + addr_space_type.set("read_i32", &addr_space::mem_read); + addr_space_type.set("read_u32", &addr_space::mem_read); + addr_space_type.set("read_i64", &addr_space::mem_read); + addr_space_type.set("read_u64", &addr_space::mem_read); + addr_space_type.set("write_i8", &addr_space::mem_write); + addr_space_type.set("write_u8", &addr_space::mem_write); + addr_space_type.set("write_i16", &addr_space::mem_write); + addr_space_type.set("write_u16", &addr_space::mem_write); + addr_space_type.set("write_i32", &addr_space::mem_write); + addr_space_type.set("write_u32", &addr_space::mem_write); + addr_space_type.set("write_i64", &addr_space::mem_write); + addr_space_type.set("write_u64", &addr_space::mem_write); + addr_space_type.set("read_log_i8", &addr_space::log_mem_read); + addr_space_type.set("read_log_u8", &addr_space::log_mem_read); + addr_space_type.set("read_log_i16", &addr_space::log_mem_read); + addr_space_type.set("read_log_u16", &addr_space::log_mem_read); + addr_space_type.set("read_log_i32", &addr_space::log_mem_read); + addr_space_type.set("read_log_u32", &addr_space::log_mem_read); + addr_space_type.set("read_log_i64", &addr_space::log_mem_read); + addr_space_type.set("read_log_u64", &addr_space::log_mem_read); + addr_space_type.set("write_log_i8", &addr_space::log_mem_write); + addr_space_type.set("write_log_u8", &addr_space::log_mem_write); + addr_space_type.set("write_log_i16", &addr_space::log_mem_write); + addr_space_type.set("write_log_u16", &addr_space::log_mem_write); + addr_space_type.set("write_log_i32", &addr_space::log_mem_write); + addr_space_type.set("write_log_u32", &addr_space::log_mem_write); + addr_space_type.set("write_log_i64", &addr_space::log_mem_write); + addr_space_type.set("write_log_u64", &addr_space::log_mem_write); + addr_space_type.set("read_direct_i8", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_u8", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_i16", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_u16", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_i32", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_u32", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_i64", &addr_space::direct_mem_read); + addr_space_type.set("read_direct_u64", &addr_space::direct_mem_read); + addr_space_type.set("write_direct_i8", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_u8", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_i16", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_u16", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_i32", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_u32", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_i64", &addr_space::direct_mem_write); + addr_space_type.set("write_direct_u64", &addr_space::direct_mem_write); + addr_space_type.set("read_range", [](addr_space &sp, sol::this_state s, u64 first, u64 last, int width, sol::object opt_step) { + lua_State *L = s; + luaL_Buffer buff; + offs_t space_size = sp.space.addrmask(); + u64 step = 1; + if (opt_step.is()) + { + step = opt_step.as(); + if (step < 1 || step > last - first) + { + luaL_error(L, "Invalid step"); + return sol::make_reference(L, nullptr); + } + } + if (first > space_size || last > space_size || last < first) + { + luaL_error(L, "Invalid offset"); + return sol::make_reference(L, nullptr); + } + int byte_count = width / 8 * (last - first + 1) / step; + switch (width) + { + case 8: + { + u8 *dest = (u8 *)luaL_buffinitsize(L, &buff, byte_count); + for(; first <= last; first += step) + *dest++ = sp.mem_read(first); + break; + } + case 16: + { + u16 *dest = (u16 *)luaL_buffinitsize(L, &buff, byte_count); + for(; first <= last; first += step) + *dest++ = sp.mem_read(first); + break; + } + case 32: + { + u32 *dest = (u32 *)luaL_buffinitsize(L, &buff, byte_count); + for(; first <= last; first += step) + *dest++ = sp.mem_read(first); + break; + } + case 64: + { + u64 *dest = (u64 *)luaL_buffinitsize(L, &buff, byte_count); + for(; first <= last; first += step) + *dest++ = sp.mem_read(first); + break; + } + default: + luaL_error(L, "Invalid width. Must be 8/16/32/64"); + return sol::make_reference(L, nullptr); + } + luaL_pushresultsize(&buff, byte_count); + return sol::make_reference(L, sol::stack_reference(L, -1)); + }); + addr_space_type.set("name", sol::property([](addr_space &sp) { return sp.space.name(); })); + addr_space_type.set("shift", sol::property([](addr_space &sp) { return sp.space.addr_shift(); })); + addr_space_type.set("index", sol::property([](addr_space &sp) { return sp.space.spacenum(); })); + addr_space_type.set("address_mask", sol::property([](addr_space &sp) { return sp.space.addrmask(); })); + addr_space_type.set("data_width", sol::property([](addr_space &sp) { return sp.space.data_width(); })); + addr_space_type.set("endianness", sol::property([](addr_space &sp) { + std::string endianness; + switch (sp.space.endianness()) + { + case endianness_t::ENDIANNESS_BIG: + endianness = "big"; + break; + case endianness_t::ENDIANNESS_LITTLE: + endianness = "little"; + break; + } + return endianness; + })); + + +/* address_map_entry library + * + * manager:machine().devices[device_tag].spaces[space].map[entry_index] + * + * mapentry.offset - address start + * mapentry.endoff - address end + * mapentry.readtype + * mapentry.writetype + */ + addr_space_type.set("map", sol::property([this](addr_space &sp) { + address_space &space = sp.space; + sol::table map = sol().create_table(); + for (address_map_entry &entry : space.map()->m_entrylist) + { + sol::table mapentry = sol().create_table(); + mapentry["offset"] = entry.m_addrstart & space.addrmask(); + mapentry["endoff"] = entry.m_addrend & space.addrmask(); + mapentry["readtype"] = entry.m_read.m_type; + mapentry["writetype"] = entry.m_write.m_type; + map.add(mapentry); + } + return map; + })); + + +/* memory_manager library + * + * manager:machine():memory() + * + * memory.banks[] - table of memory banks (k=tag, v=memory_bank) + * memory.regions[] - table of memory regions (k=tag, v=memory_region) + * memory.shares[] - table of memory shares (k=tag, v=memory_share) + */ + + auto memory_type = sol().registry().new_usertype("memory", "new", sol::no_constructor); + memory_type.set("banks", sol::property([this](memory_manager &mm) { + sol::table table = sol().create_table(); + for (auto &bank : mm.banks()) + table[bank.second->tag()] = bank.second.get(); + return table; + })); + memory_type.set("regions", sol::property([this](memory_manager &mm) { + sol::table table = sol().create_table(); + for (auto ®ion : mm.regions()) + table[region.second->name()] = region.second.get(); + return table; + })); + memory_type.set("shares", sol::property([this](memory_manager &mm) { + sol::table table = sol().create_table(); + for (auto &share : mm.shares()) + table[share.first] = share.second.get(); + return table; + })); + + +/* memory_region library + * + * manager:machine():memory().regions[region_tag] + * + * read/write by signedness u/i and bit-width 8/16/32/64: + * region:read_*(addr) + * region:write_*(addr, val) + * + * region.size + */ + + auto region_type = sol().registry().new_usertype("region", "new", sol::no_constructor); + region_type.set("read_i8", ®ion_read); + region_type.set("read_u8", ®ion_read); + region_type.set("read_i16", ®ion_read); + region_type.set("read_u16", ®ion_read); + region_type.set("read_i32", ®ion_read); + region_type.set("read_u32", ®ion_read); + region_type.set("read_i64", ®ion_read); + region_type.set("read_u64", ®ion_read); + region_type.set("write_i8", ®ion_write); + region_type.set("write_u8", ®ion_write); + region_type.set("write_i16", ®ion_write); + region_type.set("write_u16", ®ion_write); + region_type.set("write_i32", ®ion_write); + region_type.set("write_u32", ®ion_write); + region_type.set("write_i64", ®ion_write); + region_type.set("write_u64", ®ion_write); + region_type.set("size", sol::property(&memory_region::bytes)); + + +/* memory_share library + * + * manager:machine():memory().shares[share_tag] + * + * read/write by signedness u/i and bit-width 8/16/32/64: + * share:read_*(addr) + * share:write_*(addr, val) + * + * region.size +*/ + + auto share_type = sol().registry().new_usertype("share", "new", sol::no_constructor); + share_type.set("read_i8", &share_read); + share_type.set("read_u8", &share_read); + share_type.set("read_i16", &share_read); + share_type.set("read_u16", &share_read); + share_type.set("read_i32", &share_read); + share_type.set("read_u32", &share_read); + share_type.set("read_i64", &share_read); + share_type.set("read_u64", &share_read); + share_type.set("write_i8", &share_write); + share_type.set("write_u8", &share_write); + share_type.set("write_i16", &share_write); + share_type.set("write_u16", &share_write); + share_type.set("write_i32", &share_write); + share_type.set("write_u32", &share_write); + share_type.set("write_i64", &share_write); + share_type.set("write_u64", &share_write); + share_type.set("size", sol::property(&memory_share::bytes)); + +} diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp new file mode 100644 index 00000000000..01fdbe9add9 --- /dev/null +++ b/src/frontend/mame/luaengine_render.cpp @@ -0,0 +1,108 @@ +// 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 "render.h" + + +//------------------------------------------------- +// initialize_render - register render user types +//------------------------------------------------- + +void lua_engine::initialize_render() +{ + +/* render_target library + * + * manager:machine():render().targets[target_index] + * manager:machine():render():ui_target() + * + * target:view_bounds() - get x0, x1, y0, y1 bounds for target + * target:width() - get target width + * target:height() - get target height + * target:pixel_aspect() - get target aspect + * target:hidden() - is target hidden + * target:is_ui_target() - is ui render target + * target:index() - target index + * target:view_name([opt] index) - current target layout view name + * + * target.max_update_rate - + * target.view - current target layout view + * target.orientation - current target orientation + * target.screen_overlay - enable overlays + * target.zoom - enable zoom + */ + + auto target_type = sol().registry().new_usertype("target", "new", sol::no_constructor); + target_type.set("view_bounds", [](render_target &rt) { + const render_bounds b = rt.current_view().bounds(); + return std::tuple(b.x0, b.x1, b.y0, b.y1); + }); + target_type.set("width", &render_target::width); + target_type.set("height", &render_target::height); + target_type.set("pixel_aspect", &render_target::pixel_aspect); + target_type.set("hidden", &render_target::hidden); + target_type.set("is_ui_target", &render_target::is_ui_target); + target_type.set("index", &render_target::index); + target_type.set("view_name", &render_target::view_name); + target_type.set("max_update_rate", sol::property(&render_target::max_update_rate, &render_target::set_max_update_rate)); + target_type.set("view", sol::property(&render_target::view, &render_target::set_view)); + target_type.set("orientation", sol::property(&render_target::orientation, &render_target::set_orientation)); + target_type.set("screen_overlay", sol::property(&render_target::screen_overlay_enabled, &render_target::set_screen_overlay_enabled)); + target_type.set("zoom", sol::property(&render_target::zoom_to_screen, &render_target::set_zoom_to_screen)); + + +/* render_container library + * + * manager:machine():render():ui_container() + * + * container:orientation() + * container:xscale() + * container:yscale() + * container:xoffset() + * container:yoffset() + * container:is_empty() + */ + + auto render_container_type = sol().registry().new_usertype("render_container", "new", sol::no_constructor); + render_container_type.set("orientation", &render_container::orientation); + render_container_type.set("xscale", &render_container::xscale); + render_container_type.set("yscale", &render_container::yscale); + render_container_type.set("xoffset", &render_container::xoffset); + render_container_type.set("yoffset", &render_container::yoffset); + render_container_type.set("is_empty", &render_container::is_empty); + + +/* render_manager library + * + * manager:machine():render() + * + * render:max_update_rate() - + * render:ui_target() - render_target for ui drawing + * render:ui_container() - render_container for ui drawing + * + * render.targets[] - render_target table + */ + + auto render_type = sol().registry().new_usertype("render", "new", sol::no_constructor); + render_type.set("max_update_rate", &render_manager::max_update_rate); + render_type.set("ui_target", &render_manager::ui_target); + render_type.set("ui_container", &render_manager::ui_container); + render_type.set("targets", sol::property([this](render_manager &r) { + sol::table target_table = sol().create_table(); + int tc = 0; + for(render_target &curr_rt : r.targets()) + target_table[tc++] = &curr_rt; + return target_table; + })); + +} -- cgit v1.2.3