diff options
Diffstat (limited to 'src/emu')
182 files changed, 11895 insertions, 9158 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index 8a6294e7279..81e91457e71 100644 --- a/src/emu/addrmap.cpp +++ b/src/emu/addrmap.cpp @@ -42,6 +42,9 @@ address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t , m_share(nullptr) , m_region(nullptr) , m_rgnoffs(0) + , m_before_time(device) + , m_before_delay(device) + , m_after_delay(device) , m_rproto8(device) , m_rproto16(device) , m_rproto32(device) diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h index 69e4a9ab8b7..7d350c14afd 100644 --- a/src/emu/addrmap.h +++ b/src/emu/addrmap.h @@ -71,13 +71,6 @@ class address_map_entry { friend class address_map; - template <typename T, typename Ret, typename... Params> - using is_addrmap_method = std::bool_constant<std::is_constructible_v<address_map_constructor, Ret (T::*)(Params...), const char *, T *> >; - - template <typename T, typename Ret, typename... Params> - static std::enable_if_t<is_addrmap_method<T, Ret, Params...>::value, address_map_constructor> make_delegate(Ret (T::*func)(Params...), const char *name, T *obj) - { return address_map_constructor(func, name, obj); } - template <typename T, bool Reqd> static device_t &find_device(const device_finder<T, Reqd> &finder) { const std::pair<device_t &, const char *> target(finder.finder_target()); @@ -212,109 +205,157 @@ public: // view initialization void view(memory_view &mv); + + // wait-states, implicit base -> delegate converter + template <typename T> + address_map_entry &before_time(u64 (T::*ws)(offs_t, u64), const char *name) + { m_before_time = ws_time_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; } + + template <typename T> + address_map_entry &before_delay(u32 (T::*ws)(offs_t), const char *name) + { m_before_delay = ws_delay_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; } + + template <typename T> + address_map_entry &after_delay(u32 (T::*ws)(offs_t), const char *name) + { m_after_delay = ws_delay_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; } + + // wait-states, device tag -> delegate converter + template <typename T> + address_map_entry &before_time(const char *tag, u64 (T::*ws)(offs_t, u64), const char *name) + { m_before_time = ws_time_delegate(m_devbase, tag, ws, name); return *this; } + + template <typename T> + address_map_entry &before_delay(const char *tag, u32 (T::*ws)(offs_t), const char *name) + { m_before_delay = ws_delay_delegate(m_devbase, tag, ws, name); return *this; } + + template <typename T> + address_map_entry &after_delay(const char *tag, u32 (T::*ws)(offs_t), const char *name) + { m_after_delay = ws_delay_delegate(m_devbase, tag, ws, name); return *this; } + + // wait-states, device reference -> delegate converter + template <typename T, typename U> + address_map_entry &before_time(T &obj, u64 (U::*ws)(offs_t, u64), const char *name) + { m_before_time = ws_time_delegate(obj, ws, name); return *this; } + + template <typename T, typename U> + address_map_entry &before_delay(T &obj, u32 (U::*ws)(offs_t), const char *name) + { m_before_delay = ws_delay_delegate(obj, ws, name); return *this; } + + template <typename T, typename U> + address_map_entry &after_delay(T &obj, u32 (U::*ws)(offs_t), const char *name) + { m_after_delay = ws_delay_delegate(obj, ws, name); return *this; } + + // wait-states, lambda -> delegate converter + template <typename T> + address_map_entry &before_time(T &&ws, const char *name) + { m_before_time = ws_time_delegate(m_devbase, std::forward<T>(ws), name); return *this; } + + template <typename T> + address_map_entry &before_delay(T &&ws, const char *name) + { m_before_delay = ws_delay_delegate(m_devbase, std::forward<T>(ws), name); return *this; } + + template <typename T> + address_map_entry &after_delay(T &&ws, const char *name) + { m_after_delay = ws_delay_delegate(m_devbase, std::forward<T>(ws), name); return *this; } + + // implicit base -> delegate converter template <typename T, typename Ret, typename... Params> address_map_entry &r(Ret (T::*read)(Params...), const char *read_name) - { return r(emu::detail::make_delegate(*make_pointer<T>(m_devbase), read, read_name)); } + { return r(emu::rw_delegate(*make_pointer<T>(m_devbase), read, read_name)); } template <typename T, typename Ret, typename... Params> address_map_entry &w(Ret (T::*write)(Params...), const char *write_name) - { return w(emu::detail::make_delegate(*make_pointer<T>(m_devbase), write, write_name)); } + { return w(emu::rw_delegate(*make_pointer<T>(m_devbase), write, write_name)); } template <typename T, typename RetR, typename... ParamsR, typename U, typename RetW, typename... ParamsW> address_map_entry &rw(RetR (T::*read)(ParamsR...), const char *read_name, RetW (U::*write)(ParamsW...), const char *write_name) - { return r(emu::detail::make_delegate(*make_pointer<T>(m_devbase), read, read_name)).w(emu::detail::make_delegate(*make_pointer<U>(m_devbase), write, write_name)); } + { return r(emu::rw_delegate(*make_pointer<T>(m_devbase), read, read_name)).w(emu::rw_delegate(*make_pointer<U>(m_devbase), write, write_name)); } template <typename T, typename Ret, typename... Params> address_map_entry &m(Ret (T::*map)(Params...), const char *map_name) - { return m(&m_devbase, make_delegate(map, map_name, make_pointer<T>(m_devbase))); } + { return m(&m_devbase, address_map_constructor(map, map_name, make_pointer<T>(m_devbase))); } // device tag -> delegate converter template <typename T, typename Ret, typename... Params> address_map_entry &r(const char *tag, Ret (T::*read)(Params...), const char *read_name) - { return r(emu::detail::make_delegate(m_devbase, tag, read, read_name)); } + { return r(emu::rw_delegate(m_devbase, tag, read, read_name)); } template <typename T, typename Ret, typename... Params> address_map_entry &w(const char *tag, Ret (T::*write)(Params...), const char *write_name) - { return w(emu::detail::make_delegate(m_devbase, tag, write, write_name)); } + { return w(emu::rw_delegate(m_devbase, tag, write, write_name)); } template <typename T, typename RetR, typename... ParamsR, typename U, typename RetW, typename... ParamsW> address_map_entry &rw(const char *tag, RetR (T::*read)(ParamsR...), const char *read_name, RetW (U::*write)(ParamsW...), const char *write_name) - { return r(emu::detail::make_delegate(m_devbase, tag, read, read_name)).w(emu::detail::make_delegate(m_devbase, tag, write, write_name)); } + { return r(emu::rw_delegate(m_devbase, tag, read, read_name)).w(emu::rw_delegate(m_devbase, tag, write, write_name)); } template <typename T, typename Ret, typename... Params> address_map_entry &m(const char *tag, Ret (T::*map)(Params...), const char *map_name) - { return m(tag, make_delegate(map, map_name, static_cast<T *>(nullptr))); } + { return m(tag, address_map_constructor(map, map_name, static_cast<T *>(nullptr))); } // device reference -> delegate converter template <typename T, typename U, typename Ret, typename... Params> address_map_entry &r(T &obj, Ret (U::*read)(Params...), const char *read_name) - { return r(emu::detail::make_delegate(*make_pointer<U>(obj), read, read_name)); } + { return r(emu::rw_delegate(*make_pointer<U>(obj), read, read_name)); } template <typename T, typename U, typename Ret, typename... Params> address_map_entry &w(T &obj, Ret (U::*write)(Params...), const char *write_name) - { return w(emu::detail::make_delegate(*make_pointer<U>(obj), write, write_name)); } + { return w(emu::rw_delegate(*make_pointer<U>(obj), write, write_name)); } template <typename T, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW> address_map_entry &rw(T &obj, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name) - { return r(emu::detail::make_delegate(*make_pointer<U>(obj), read, read_name)).w(emu::detail::make_delegate(make_pointer<V>(obj), write, write_name)); } + { return r(emu::rw_delegate(*make_pointer<U>(obj), read, read_name)).w(emu::rw_delegate(make_pointer<V>(obj), write, write_name)); } template <typename T, typename U, typename Ret, typename... Params> address_map_entry &m(T &obj, Ret (U::*map)(Params...), const char *map_name) - { return m(make_pointer<device_t>(obj), make_delegate(map, map_name, make_pointer<U>(obj))); } + { return m(make_pointer<device_t>(obj), address_map_constructor(map, map_name, make_pointer<U>(obj))); } // device finder -> delegate converter template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &r(device_finder<T, Reqd> &finder, Ret (U::*read)(Params...), const char *read_name) { - device_t &device(find_device(finder)); - return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name)); + return r(emu::rw_delegate(finder, read, read_name)); } template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &r(const device_finder<T, Reqd> &finder, Ret (U::*read)(Params...), const char *read_name) { - device_t &device(find_device(finder)); - return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name)); + return r(emu::rw_delegate(finder, read, read_name)); } template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &w(device_finder<T, Reqd> &finder, Ret (U::*write)(Params...), const char *write_name) { - device_t &device(find_device(finder)); - return w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name)); + return w(emu::rw_delegate(finder, write, write_name)); } template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &w(const device_finder<T, Reqd> &finder, Ret (U::*write)(Params...), const char *write_name) { - device_t &device(find_device(finder)); - return w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name)); + return w(emu::rw_delegate(finder, write, write_name)); } template <typename T, bool Reqd, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW> address_map_entry &rw(device_finder<T, Reqd> &finder, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name) { - device_t &device(find_device(finder)); - return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name)) - .w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name)); + return r(emu::rw_delegate(finder, read, read_name)) + .w(emu::rw_delegate(finder, write, write_name)); } template <typename T, bool Reqd, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW> address_map_entry &rw(const device_finder<T, Reqd> &finder, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name) { - device_t &device(find_device(finder)); - return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name)) - .w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name)); + return r(emu::rw_delegate(finder, read, read_name)) + .w(emu::rw_delegate(finder, write, write_name)); } template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &m(device_finder<T, Reqd> &finder, Ret (U::*map)(Params...), const char *map_name) { device_t &device(find_device(finder)); - return m(&device, make_delegate(map, map_name, make_pointer<U>(device))); + return m(&device, address_map_constructor(map, map_name, make_pointer<U>(device))); } template <typename T, bool Reqd, typename U, typename Ret, typename... Params> address_map_entry &m(const device_finder<T, Reqd> &finder, Ret (U::*map)(Params...), const char *map_name) { device_t &device(find_device(finder)); - return m(&device, make_delegate(map, map_name, make_pointer<U>(device))); + return m(&device, address_map_constructor(map, map_name, make_pointer<U>(device))); } @@ -374,6 +415,9 @@ public: const char * m_share; // tag of a shared memory block const char * m_region; // tag of region containing the memory backing this entry offs_t m_rgnoffs; // offset within the region + ws_time_delegate m_before_time; // before-time wait-state + ws_delay_delegate m_before_delay; // before-delay wait-state + ws_delay_delegate m_after_delay; // after-delay wait-state // handlers read8_delegate m_rproto8; // 8-bit read proto-delegate diff --git a/src/emu/attotime.cpp b/src/emu/attotime.cpp index a1ba4d9ed61..030c3193551 100644 --- a/src/emu/attotime.cpp +++ b/src/emu/attotime.cpp @@ -119,11 +119,11 @@ const char *attotime::as_string(int precision) const // special case: never if (*this == never) - sprintf(buffer, "%-*s", precision, "(never)"); + snprintf(buffer, 30, "%-*s", precision, "(never)"); // case 1: we want no precision; seconds only else if (precision == 0) - sprintf(buffer, "%d", m_seconds); + snprintf(buffer, 30, "%d", m_seconds); // case 2: we want 9 or fewer digits of precision else if (precision <= 9) @@ -135,7 +135,7 @@ const char *attotime::as_string(int precision) const upper /= 10; temp++; } - sprintf(buffer, "%d.%0*d", m_seconds, precision, upper); + snprintf(buffer, 30, "%d.%0*d", m_seconds, precision, upper); } // case 3: more than 9 digits of precision @@ -149,7 +149,7 @@ const char *attotime::as_string(int precision) const lower /= 10; temp++; } - sprintf(buffer, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower); + snprintf(buffer, 30, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower); } return buffer; } diff --git a/src/emu/attotime.h b/src/emu/attotime.h index e056ee90034..39fcf6e5310 100644 --- a/src/emu/attotime.h +++ b/src/emu/attotime.h @@ -38,9 +38,10 @@ #include "emucore.h" #include "xtal.h" +#include "eminline.h" + #include <cmath> -#undef min -#undef max + //************************************************************************** // CONSTANTS @@ -180,7 +181,7 @@ public: //************************************************************************** /** handle addition between two attotimes */ -inline attotime operator+(const attotime &left, const attotime &right) noexcept +inline constexpr attotime operator+(const attotime &left, const attotime &right) noexcept { attotime result; @@ -230,7 +231,7 @@ inline attotime &attotime::operator+=(const attotime &right) noexcept /** handle subtraction between two attotimes */ -inline attotime operator-(const attotime &left, const attotime &right) noexcept +inline constexpr attotime operator-(const attotime &left, const attotime &right) noexcept { attotime result; diff --git a/src/emu/bookkeeping.cpp b/src/emu/bookkeeping.cpp index 4ae4c1ecf2b..9f3e414e03f 100644 --- a/src/emu/bookkeeping.cpp +++ b/src/emu/bookkeeping.cpp @@ -11,6 +11,8 @@ #include "emu.h" #include "config.h" +#include "xmlfile.h" + //************************************************************************** // BOOKKEEPING MANAGER diff --git a/src/emu/config.cpp b/src/emu/config.cpp index 792da6f255d..8e9423415ee 100644 --- a/src/emu/config.cpp +++ b/src/emu/config.cpp @@ -13,25 +13,39 @@ #include "drivenum.h" #include "emuopts.h" +#include "fileio.h" #include "xmlfile.h" +#include <system_error> +#include <utility> + #define DEBUG_CONFIG 0 + //************************************************************************** // CONFIGURATION MANAGER //************************************************************************** -//------------------------------------------------- -// configuration_manager - constructor -//------------------------------------------------- +/************************************* + * + * Construction/destruction + * + *************************************/ + +configuration_manager::configuration_manager(running_machine &machine) : + m_machine(machine), + m_typelist() +{ +} -configuration_manager::configuration_manager(running_machine &machine) - : m_machine(machine) +configuration_manager::~configuration_manager() { } + + /************************************* * * Register to be involved in config @@ -39,14 +53,9 @@ configuration_manager::configuration_manager(running_machine &machine) * *************************************/ -void configuration_manager::config_register(const char *nodename, load_delegate load, save_delegate save) +void configuration_manager::config_register(std::string_view name, load_delegate &&load, save_delegate &&save) { - config_element element; - element.name = nodename; - element.load = std::move(load); - element.save = std::move(save); - - m_typelist.emplace_back(std::move(element)); + m_typelist.emplace(name, config_handler{ std::move(load), std::move(save) }); } @@ -60,44 +69,31 @@ void configuration_manager::config_register(const char *nodename, load_delegate bool configuration_manager::load_settings() { // loop over all registrants and call their init function - for (const auto &type : m_typelist) - type.load(config_type::INIT, config_level::DEFAULT, nullptr); + for (auto const &type : m_typelist) + type.second.load(config_type::INIT, config_level::DEFAULT, nullptr); // now load the controller file char const *const controller = machine().options().ctrlr(); if (controller && *controller) { - // open the config file emu_file file(machine().options().ctrlr_path(), OPEN_FLAG_READ); - osd_printf_verbose("Attempting to parse: %s.cfg\n", controller); - std::error_condition const filerr = file.open(std::string(controller) + ".cfg"); - - if (filerr) - throw emu_fatalerror("Could not open controller file %s.cfg (%s:%d %s)", controller, filerr.category().name(), filerr.value(), filerr.message()); - - // load the XML - if (!load_xml(file, config_type::CONTROLLER)) - throw emu_fatalerror("Could not load controller file %s.cfg", controller); + if (!attempt_load(machine().system(), file, std::string(controller) + ".cfg", config_type::CONTROLLER)) + throw emu_fatalerror("Could not load controller configuration file %s.cfg", controller); } // next load the defaults file emu_file file(machine().options().cfg_directory(), OPEN_FLAG_READ); - std::error_condition filerr = file.open("default.cfg"); - osd_printf_verbose("Attempting to parse: default.cfg\n"); - if (!filerr) - load_xml(file, config_type::DEFAULT); + attempt_load(machine().system(), file, "default.cfg", config_type::DEFAULT); - // finally, load the game-specific file - filerr = file.open(machine().basename() + ".cfg"); - osd_printf_verbose("Attempting to parse: %s.cfg\n",machine().basename()); - const bool loaded = !filerr && load_xml(file, config_type::SYSTEM); + // load the system-specific file + bool const loaded = attempt_load(machine().system(), file, machine().basename() + ".cfg", config_type::SYSTEM); // loop over all registrants and call their final function - for (const auto &type : m_typelist) - type.load(config_type::FINAL, config_level::DEFAULT, nullptr); + for (auto const &type : m_typelist) + type.second.load(config_type::FINAL, config_level::DEFAULT, nullptr); // if we didn't find a saved config, return false so the main core knows that it - // is the first time the game is run and it should display the disclaimer. + // is the first time the system has been run return loaded; } @@ -105,8 +101,8 @@ bool configuration_manager::load_settings() void configuration_manager::save_settings() { // loop over all registrants and call their init function - for (const auto &type : m_typelist) - type.save(config_type::INIT, nullptr); + for (auto const &type : m_typelist) + type.second.save(config_type::INIT, nullptr); // save the defaults file emu_file file(machine().options().cfg_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); @@ -120,8 +116,8 @@ void configuration_manager::save_settings() save_xml(file, config_type::SYSTEM); // loop over all registrants and call their final function - for (const auto &type : m_typelist) - type.save(config_type::FINAL, nullptr); + for (auto const &type : m_typelist) + type.second.save(config_type::FINAL, nullptr); } @@ -132,13 +128,39 @@ void configuration_manager::save_settings() * *************************************/ -bool configuration_manager::load_xml(emu_file &file, config_type which_type) +bool configuration_manager::attempt_load(game_driver const &system, emu_file &file, std::string_view name, config_type which_type) +{ + std::error_condition const filerr = file.open(std::string(name)); + if (std::errc::no_such_file_or_directory == filerr) + { + osd_printf_verbose("Configuration file %s not found\n", name); + return false; + } + else if (filerr) + { + osd_printf_warning( + "Error opening configuration file %s (%s:%d %s)\n", + name, + filerr.category().name(), + filerr.value(), + filerr.message()); + return false; + } + else + { + osd_printf_verbose("Attempting to parse: %s\n", name); + return load_xml(system, file, which_type); + } +} + + +bool configuration_manager::load_xml(game_driver const &system, emu_file &file, config_type which_type) { // read the file util::xml::file::ptr const root(util::xml::file::read(file, nullptr)); if (!root) { - osd_printf_verbose("Error parsing XML configuration file %s\n", file.filename()); + osd_printf_warning("Error parsing XML configuration file %s\n", file.filename()); return false; } @@ -146,7 +168,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) util::xml::data_node const *const confignode = root->get_child("mameconfig"); if (!confignode) { - osd_printf_verbose("Could not find root mameconfig element in configuration file %s\n", file.filename()); + osd_printf_warning("Could not find root mameconfig element in configuration file %s\n", file.filename()); return false; } @@ -154,18 +176,18 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) int const version = confignode->get_attribute_int("version", 0); if (version != CONFIG_VERSION) { - osd_printf_verbose("Configuration file %s has unsupported version %d\n", file.filename(), version); + osd_printf_warning("Configuration file %s has unsupported version %d\n", file.filename(), version); return false; } // strip off all the path crap from the source filename - const char *srcfile = strrchr(machine().system().type.source(), '/'); + char const *srcfile = strrchr(system.type.source(), '/'); if (!srcfile) - srcfile = strrchr(machine().system().type.source(), '\\'); + srcfile = strrchr(system.type.source(), '\\'); if (!srcfile) - srcfile = strrchr(machine().system().type.source(), ':'); + srcfile = strrchr(system.type.source(), ':'); if (!srcfile) - srcfile = machine().system().type.source(); + srcfile = system.type.source(); else srcfile++; @@ -174,7 +196,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) for (util::xml::data_node const *systemnode = confignode->get_child("system"); systemnode; systemnode = systemnode->get_next_sibling("system")) { // look up the name of the system here; skip if none - const char *name = systemnode->get_attribute_string("name", ""); + char const *name = systemnode->get_attribute_string("name", ""); // based on the file type, determine whether we have a match config_level level = config_level::DEFAULT; @@ -182,7 +204,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) { case config_type::SYSTEM: // only match on the specific system name - if (strcmp(name, machine().system().name)) + if (strcmp(name, system.name)) { osd_printf_verbose("Ignoring configuration for system %s in system configuration file %s\n", name, file.filename()); continue; @@ -209,7 +231,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) osd_printf_verbose("Applying default configuration from controller configuration file %s\n", file.filename()); level = config_level::DEFAULT; } - else if (!strcmp(name, machine().system().name)) + else if (!strcmp(name, system.name)) { osd_printf_verbose("Applying configuration for system %s from controller configuration file %s\n", name, file.filename()); level = config_level::SYSTEM; @@ -220,7 +242,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) level = config_level::SOURCE; } else if ( - ((clone_of = driver_list::clone(machine().system())) != -1 && !strcmp(name, driver_list::driver(clone_of).name)) || + ((clone_of = driver_list::clone(system)) != -1 && !strcmp(name, driver_list::driver(clone_of).name)) || (clone_of != -1 && ((clone_of = driver_list::clone(clone_of)) != -1) && !strcmp(name, driver_list::driver(clone_of).name))) { osd_printf_verbose("Applying configuration for parent/BIOS %s from controller configuration file %s\n", name, file.filename()); @@ -242,9 +264,15 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type) osd_printf_debug("Entry: %s -- processing\n", name); // loop over all registrants and call their load function - for (const auto &type : m_typelist) - type.load(which_type, level, systemnode->get_child(type.name.c_str())); + for (auto const &type : m_typelist) + type.second.load(which_type, level, systemnode->get_child(type.first.c_str())); count++; + + // save unhandled settings for default and system types + if (config_type::DEFAULT == which_type) + save_unhandled(m_unhandled_default, *systemnode); + else if (config_type::SYSTEM == which_type) + save_unhandled(m_unhandled_system, *systemnode); } // error if this isn't a valid match @@ -279,21 +307,65 @@ bool configuration_manager::save_xml(emu_file &file, config_type which_type) systemnode->set_attribute("name", (which_type == config_type::DEFAULT) ? "default" : machine().system().name); // loop over all registrants and call their save function - for (const auto &type : m_typelist) + util::xml::data_node *curnode = nullptr; + for (auto const &type : m_typelist) { - util::xml::data_node *const curnode = systemnode->add_child(type.name.c_str(), nullptr); + if (!curnode || (type.first != curnode->get_name())) + curnode = systemnode->add_child(type.first.c_str(), nullptr); if (!curnode) return false; - type.save(which_type, curnode); + type.second.save(which_type, curnode); // if nothing was added, just nuke the node if (!curnode->get_value() && !curnode->get_first_child() && !curnode->count_attributes()) + { curnode->delete_node(); + curnode = nullptr; + } } - // flush the file + // restore unhandled settings + if ((config_type::DEFAULT == which_type) && m_unhandled_default) + restore_unhandled(*m_unhandled_default, *systemnode); + else if ((config_type::SYSTEM == which_type) && m_unhandled_system) + restore_unhandled(*m_unhandled_system, *systemnode); + + // write out the file root->write(file); // free and get out of here return true; } + + + +/************************************* + * + * Preserving unhandled settings + * + *************************************/ + +void configuration_manager::save_unhandled( + std::unique_ptr<util::xml::file> &unhandled, + util::xml::data_node const &systemnode) +{ + for (util::xml::data_node const *curnode = systemnode.get_first_child(); curnode; curnode = curnode->get_next_sibling()) + { + auto const handler = m_typelist.lower_bound(curnode->get_name()); + if ((m_typelist.end() == handler) || (handler->first != curnode->get_name())) + { + if (!unhandled) + unhandled = util::xml::file::create(); + curnode->copy_into(*unhandled); + } + } +} + + +void configuration_manager::restore_unhandled( + util::xml::file const &unhandled, + util::xml::data_node &systemnode) +{ + for (util::xml::data_node const *curnode = unhandled.get_first_child(); curnode; curnode = curnode->get_next_sibling()) + curnode->copy_into(systemnode); +} diff --git a/src/emu/config.h b/src/emu/config.h index 2a273ba248f..4d3dd4f3b75 100644 --- a/src/emu/config.h +++ b/src/emu/config.h @@ -13,7 +13,10 @@ #pragma once -#include "xmlfile.h" +#include <map> +#include <memory> +#include <string> +#include <string_view> enum class config_type : int @@ -45,28 +48,35 @@ public: // construction/destruction configuration_manager(running_machine &machine); + ~configuration_manager(); + + void config_register(std::string_view name, load_delegate &&load, save_delegate &&save); - void config_register(const char *nodename, load_delegate load, save_delegate save); bool load_settings(); void save_settings(); - // getters - running_machine &machine() const { return m_machine; } - private: - struct config_element + struct config_handler { - std::string name; // node name - load_delegate load; // load callback - save_delegate save; // save callback + load_delegate load; + save_delegate save; }; - bool load_xml(emu_file &file, config_type which_type); + running_machine &machine() const { return m_machine; } + + bool attempt_load(game_driver const &system, emu_file &file, std::string_view name, config_type which_type); + + bool load_xml(game_driver const &system, emu_file &file, config_type which_type); bool save_xml(emu_file &file, config_type which_type); + void save_unhandled(std::unique_ptr<util::xml::file> &unhandled, util::xml::data_node const &systemnode); + void restore_unhandled(util::xml::file const &unhandled, util::xml::data_node &systemnode); + // internal state - running_machine & m_machine; // reference to our machine - std::vector<config_element> m_typelist; + running_machine &m_machine; + std::multimap<std::string, config_handler> m_typelist; + std::unique_ptr<util::xml::file> m_unhandled_default; + std::unique_ptr<util::xml::file> m_unhandled_system; }; #endif // MAME_EMU_CONFIG_H diff --git a/src/emu/crsshair.cpp b/src/emu/crsshair.cpp index 3c6a6b807f0..d90cc9a7f5e 100644 --- a/src/emu/crsshair.cpp +++ b/src/emu/crsshair.cpp @@ -13,6 +13,7 @@ #include "config.h" #include "emuopts.h" +#include "fileio.h" #include "render.h" #include "rendutil.h" #include "screen.h" diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp index 85ec19d5fb9..616567b398e 100644 --- a/src/emu/debug/debugbuf.cpp +++ b/src/emu/debug/debugbuf.cpp @@ -82,6 +82,8 @@ void debug_disasm_buffer::debug_data_buffer::fill(offs_t lstart, offs_t size) co } } + // FIXME: This buffer tends to hog more memory than necessary for typical disassembly tasks. + // If the PC values supplied are far enough apart, the buffer may suddenly increase in size to a gigabyte or more. if(m_buffer.empty()) { m_lstart = lstart; m_lend = lend; @@ -209,8 +211,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u16 *dest = get_ptr<u16>(lstart); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = m_intf.pc_linear_to_real(lpc); - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_word(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_word(tpc); else *dest++ = 0; } @@ -220,14 +223,13 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() m_do_fill = [this](offs_t lstart, offs_t lend) { auto dis = m_space->device().machine().disable_side_effects(); u8 *dest = get_ptr<u8>(lstart); - u32 steps = 0; for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = m_intf.pc_linear_to_real(lpc); - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_byte(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_byte(tpc); else *dest++ = 0; - steps++; } }; break; @@ -241,8 +243,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u64 *dest = get_ptr<u64>(lstart); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = lpc; - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_qword(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_qword(tpc); else *dest++ = 0; } @@ -255,8 +258,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u32 *dest = get_ptr<u32>(lstart); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = lpc; - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_dword(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_dword(tpc); else *dest++ = 0; } @@ -269,8 +273,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u16 *dest = get_ptr<u16>(lstart); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = lpc; - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_word(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_word(tpc); else *dest++ = 0; } @@ -283,8 +288,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u8 *dest = get_ptr<u8>(lstart); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) { offs_t tpc = lpc; - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_byte(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_byte(tpc); else *dest++ = 0; } @@ -297,8 +303,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods() u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4); for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) { offs_t tpc = lpc; - if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc)) - *dest++ = m_space->read_word(tpc); + address_space *space; + if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space)) + *dest++ = space->read_word(tpc); else *dest++ = 0; } @@ -1390,7 +1397,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) : // pc to string conversion int aw = pspace.logaddr_width(); bool is_octal = pspace.is_octal(); - if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) { + if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL && aw > (m_dintf.page_address_bits() + m_dintf.page2_address_bits())) { int bits1 = m_dintf.page_address_bits(); int bits2 = m_dintf.page2_address_bits(); int bits3 = aw - bits1 - bits2; @@ -1421,7 +1428,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) : }; } - } else if(m_flags & util::disasm_interface::PAGED) { + } else if((m_flags & util::disasm_interface::PAGED) && aw > m_dintf.page_address_bits()) { int bits1 = m_dintf.page_address_bits(); int bits2 = aw - bits1; offs_t sm1 = (1 << bits1) - 1; diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 20431072cff..ad463ace500 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -21,8 +21,10 @@ #include "debugger.h" #include "emuopts.h" +#include "fileio.h" #include "natkeyboard.h" #include "render.h" +#include "screen.h" #include "softlist.h" #include "corestr.h" @@ -30,35 +32,7 @@ #include <algorithm> #include <cctype> #include <fstream> - - - -namespace { - -template <typename T> -inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim) -{ - unsigned parens = 0; - for (std::string_view::size_type i = 0; str.length() > i; ++i) - { - if (str[i] == '(') - { - ++parens; - } - else if (parens) - { - if (str[i] == ')') - --parens; - } - else if (is_delim(str[i])) - { - return i; - } - } - return std::string_view::npos; -} - -} // anonymous namespace +#include <sstream> @@ -79,7 +53,8 @@ const size_t debugger_commands::MAX_GLOBALS = 1000; bool debugger_commands::cheat_address_is_valid(address_space &space, offs_t address) { - return space.device().memory().translate(space.spacenum(), TRANSLATE_READ, address) && (space.get_write_ptr(address) != nullptr); + address_space *tspace; + return space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace) && (tspace->get_write_ptr(address) != nullptr); } @@ -130,14 +105,15 @@ u64 debugger_commands::cheat_system::read_extended(offs_t address) const { address &= space->logaddrmask(); u64 value = space->unmap(); - if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) + address_space *tspace; + if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace)) { switch (width) { - case 1: value = space->read_byte(address); break; - case 2: value = space->read_word_unaligned(address); break; - case 4: value = space->read_dword_unaligned(address); break; - case 8: value = space->read_qword_unaligned(address); break; + case 1: value = tspace->read_byte(address); break; + case 2: value = tspace->read_word_unaligned(address); break; + case 4: value = tspace->read_dword_unaligned(address); break; + case 8: value = tspace->read_qword_unaligned(address); break; } } return sign_extend(byte_swap(value)); @@ -194,7 +170,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu if ((valcount == 1) && (blockcount == 1) && strstr(name, "/globals/")) { char symname[100]; - sprintf(symname, ".%s", strrchr(name, '/') + 1); + snprintf(symname, 100, ".%s", strrchr(name, '/') + 1); m_global_array[itemnum].base = base; m_global_array[itemnum].size = valsize; symtable.add( @@ -231,6 +207,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("gtime", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1)); m_console.register_command("gt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1)); m_console.register_command("gp", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_privilege, this, _1)); + m_console.register_command("gbt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, true, _1)); + m_console.register_command("gbf", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, false, _1)); + m_console.register_command("gni", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_next_instruction, this, _1)); m_console.register_command("next", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1)); m_console.register_command("n", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1)); m_console.register_command("focus", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_focus, this, _1)); @@ -239,6 +218,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("suspend", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_suspend, this, _1)); m_console.register_command("resume", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_resume, this, _1)); m_console.register_command("cpulist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_cpulist, this, _1)); + m_console.register_command("time", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_time, this, _1)); m_console.register_command("comadd", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1)); m_console.register_command("//", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1)); @@ -275,6 +255,13 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("rpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1)); m_console.register_command("rplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rplist, this, _1)); + m_console.register_command("epset", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1)); + m_console.register_command("ep", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1)); + m_console.register_command("epclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epclear, this, _1)); + m_console.register_command("epdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, false, _1)); + m_console.register_command("epenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, true, _1)); + m_console.register_command("eplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_eplist, this, _1)); + m_console.register_command("statesave", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1)); m_console.register_command("ss", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1)); m_console.register_command("stateload", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1)); @@ -442,475 +429,15 @@ void debugger_commands::global_set(global_entry *global, u64 value) -/*************************************************************************** - PARAMETER VALIDATION HELPERS -***************************************************************************/ - -/// \brief Validate parameter as a Boolean value -/// -/// Validates a parameter as a Boolean value. Fixed strings and -/// expressions evaluating to numeric values are recognised. The result -/// is unchanged for an empty string. -/// \param [in] param The parameter string. -/// \param [in,out] result The default value on entry, and the value of -/// the parameter interpreted as a Boolean on success. Unchanged if -/// the parameter is an empty string. -/// \return true if the parameter is a valid Boolean value or an empty -/// string, or false otherwise. -bool debugger_commands::validate_boolean_parameter(const std::string ¶m, bool &result) -{ - // nullptr parameter does nothing and returns no error - if (param.empty()) - return true; - - // evaluate the expression; success if no error - bool const is_true = !core_stricmp(param.c_str(), "true"); - bool const is_false = !core_stricmp(param.c_str(), "false"); - - if (is_true || is_false) - { - result = is_true; - return true; - } - - // try to evaluate as a number - u64 val; - if (!validate_number_parameter(param, val)) - return false; - - result = val != 0; - return true; -} - - -/// \brief Validate parameter as a numeric value -/// -/// Parses the parameter as an expression and evaluates it as a number. -/// \param [in] param The parameter string. -/// \param [out] result The numeric value of the expression on success. -/// Unchanged on failure. -/// \return true if the parameter is a valid expression that evaluates -/// to a numeric value, or false otherwise. -bool debugger_commands::validate_number_parameter(std::string_view param, u64 &result) -{ - // evaluate the expression; success if no error - try - { - result = parsed_expression(m_console.visible_symtable(), param).execute(); - return true; - } - catch (expression_error const &error) - { - // print an error pointing to the character that caused it - m_console.printf("Error in expression: %s\n", param); - m_console.printf(" %*s^", error.offset(), ""); - m_console.printf("%s\n", error.code_string()); - return false; - } -} - - -/// \brief Validate parameter as a device -/// -/// Validates a parameter as a device identifier and retrieves the -/// device on success. A string corresponding to the tag of a device -/// refers to that device; an empty string refers to the current CPU -/// with debugger focus; any other string is parsed as an expression -/// and treated as an index of a device implementing -/// #device_execute_interface and #device_state_interface, and exposing -/// a generic PC base value. -/// \param [in] param The parameter string. -/// \param [out] result A pointer to the device on success, or unchanged -/// on failure. -/// \return true if the parameter refers to a device in the current -/// system, or false otherwise. -bool debugger_commands::validate_device_parameter(std::string_view param, device_t *&result) -{ - // if no parameter, use the visible CPU - if (param.empty()) - { - device_t *const current = m_console.get_visible_cpu(); - if (current) - { - result = current; - return true; - } - else - { - m_console.printf("No valid CPU is currently selected\n"); - return false; - } - } - - // next look for a tag match - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - device_t *device = base.subdevice(strmakelower(relative)); - if (device) - { - result = device; - return true; - } - - // then evaluate as an expression; on an error assume it was a tag - u64 cpunum; - try - { - cpunum = parsed_expression(m_console.visible_symtable(), param).execute(); - } - catch (expression_error &) - { - m_console.printf("Unable to find device '%s'\n", param); - return false; - } - - // attempt to find by numerical index - device = get_cpu_by_index(cpunum); - if (device) - { - result = device; - return true; - } - else - { - // if out of range, complain - m_console.printf("Invalid CPU index %u\n", cpunum); - return false; - } -} - - -/// \brief Validate a parameter as a CPU -/// -/// Validates a parameter as a CPU identifier. Uses the same rules as -/// #validate_device_parameter to identify devices, but additionally -/// checks that the device is a "CPU" for the debugger's purposes. -/// \param [in] The parameter string. -/// \param [out] result The device on success, or unchanged on failure. -/// \return true if the parameter refers to a CPU-like device in the -/// current system, or false otherwise. -bool debugger_commands::validate_cpu_parameter(std::string_view param, device_t *&result) -{ - // first do the standard device thing - device_t *device; - if (!validate_device_parameter(param, device)) - return false; - - // check that it's a "CPU" for the debugger's purposes - device_execute_interface const *execute; - if (device->interface(execute)) - { - result = device; - return true; - } - - m_console.printf("Device %s is not a CPU\n", device->name()); - return false; -} - - -/// \brief Validate a parameter as an address space identifier -/// -/// Validates a parameter as an address space identifier. Uses the same -/// rules as #validate_device_parameter to identify devices. If the -/// default address space number is negative, the first address space -/// exposed by the device will be used as the default. -/// \param [in] The parameter string. -/// \param [in] spacenum The default address space index. If negative, -/// the first address space exposed by the device (i.e. the address -/// space with the lowest index) will be used as the default. -/// \param [out] result The address space on success, or unchanged on -/// failure. -/// \return true if the parameter refers to an address space in the -/// current system, or false otherwise. -bool debugger_commands::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result) -{ - device_t *device; - std::string spacename; - if (param.empty()) - { - // if no parameter, use the visible CPU - device = m_console.get_visible_cpu(); - if (!device) - { - m_console.printf("No valid CPU is currently selected\n"); - return false; - } - } - else - { - // look for a tag match on the whole parameter value - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - device = base.subdevice(strmakelower(relative)); - - // if that failed, treat the last component as an address space - if (!device) - { - auto const delimiter = relative.find_last_of(":^"); - bool const found = std::string_view::npos != delimiter; - if (!found || (':' == relative[delimiter])) - { - spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0)); - relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter); - if (!relative.empty()) - device = base.subdevice(strmakelower(relative)); - else if (m_console.get_visible_cpu()) - device = m_console.get_visible_cpu(); - else - device = &m_machine.root_device(); - } - } - } - - // if still no device found, evaluate as an expression - if (!device) - { - u64 cpunum; - try - { - cpunum = parsed_expression(m_console.visible_symtable(), param).execute(); - } - catch (expression_error const &) - { - // parsing failed - assume it was a tag - m_console.printf("Unable to find device '%s'\n", param); - return false; - } - - // attempt to find by numerical index - device = get_cpu_by_index(cpunum); - if (!device) - { - // if out of range, complain - m_console.printf("Invalid CPU index %u\n", cpunum); - return false; - } - } - - // ensure the device implements the memory interface - device_memory_interface *memory; - if (!device->interface(memory)) - { - m_console.printf("No memory interface found for device %s\n", device->name()); - return false; - } - - // fall back to supplied default space if appropriate - if (spacename.empty() && (0 <= spacenum)) - { - if (memory->has_space(spacenum)) - { - result = &memory->space(spacenum); - return true; - } - else - { - m_console.printf("No matching memory space found for device '%s'\n", device->tag()); - return false; - } - } - - // otherwise find the specified space or fall back to the first populated space - for (int i = 0; memory->max_space_count() > i; ++i) - { - if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename))) - { - result = &memory->space(i); - return true; - } - } - - // report appropriate error message - if (spacename.empty()) - m_console.printf("No memory spaces found for device '%s'\n", device->tag()); - else - m_console.printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag()); - return false; -} - - -/// \brief Validate a parameter as a target address -/// -/// Validates a parameter as an numeric expression to use as an address -/// optionally followed by a colon and a device identifier. If the -/// device identifier is not presnt, the current CPU with debugger focus -/// is assumed. See #validate_device_parameter for information on how -/// device parametersare interpreted. -/// \param [in] The parameter string. -/// \param [in] spacenum The default address space index. If negative, -/// the first address space exposed by the device (i.e. the address -/// space with the lowest index) will be used as the default. -/// \param [out] space The address space on success, or unchanged on -/// failure. -/// \param [out] addr The address on success, or unchanged on failure. -/// \return true if the address is a valid expression evaluating to a -/// number and the address space is found, or false otherwise. -bool debugger_commands::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr) -{ - // check for the device delimiter - std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; }); - std::string_view device; - if (devdelim != std::string::npos) - device = param.substr(devdelim + 1); - - // parse the address first - u64 addrval; - if (!validate_number_parameter(param.substr(0, devdelim), addrval)) - return false; - - // find the address space - if (!validate_device_space_parameter(device, spacenum, space)) - return false; - - // set the address now that we have the space - addr = addrval; - return true; -} - - -/// \brief Validate a parameter as a memory region -/// -/// Validates a parameter as a memory region tag and retrieves the -/// specified memory region. -/// \param [in] The parameter string. -/// \param [out] result The memory region on success, or unchanged on -/// failure. -/// \return true if the parameter refers to a memory region in the -/// current system, or false otherwise. -bool debugger_commands::validate_memory_region_parameter(std::string_view param, memory_region *&result) -{ - auto const ®ions = m_machine.memory().regions(); - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - auto const iter = regions.find(base.subtag(strmakelower(relative))); - if (regions.end() != iter) - { - result = iter->second.get(); - return true; - } - else - { - m_console.printf("No matching memory region found for '%s'\n", param); - return false; - } -} - - -/// \brief Get search base for device or address space parameter -/// -/// Handles prefix prefixes used to indicate that a device tag should be -/// interpreted relative to the selected CPU. Removes the recognised -/// prefixes from the parameter value. -/// \param [in,out] param The parameter string. Recognised prefixes -/// affecting the search base are removed, leaving a tag relative to -/// the base device. -/// \return A reference to the base device that the tag should be -/// interpreted relative to. -device_t &debugger_commands::get_device_search_base(std::string_view ¶m) -{ - if (!param.empty()) - { - // handle ".:" or ".^" prefix for tag relative to current CPU if any - if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1]))) - { - param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1); - device_t *const current = m_console.get_visible_cpu(); - return current ? *current : m_machine.root_device(); - } - - // a sibling path makes most sense relative to current CPU - if ('^' == param[0]) - { - device_t *const current = m_console.get_visible_cpu(); - return current ? *current : m_machine.root_device(); - } - } - - - // default to root device - return m_machine.root_device(); -} - - -/// \brief Get CPU by index -/// -/// Looks up a CPU by the number the debugger assigns it based on its -/// position in the device tree relative to other CPUs. -/// \param [in] cpunum Zero-based index of the CPU to find. -/// \return A pointer to the CPU if found, or \c nullptr if no CPU has -/// the specified index. -device_t *debugger_commands::get_cpu_by_index(u64 cpunum) -{ - unsigned index = 0; - for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device())) - { - // real CPUs should have pcbase - device_state_interface const *state; - if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE)) - { - if (index++ == cpunum) - { - return &exec.device(); - } - } - } - return nullptr; -} - - -/*------------------------------------------------- - debug_command_parameter_expression - validates - an expression parameter --------------------------------------------------*/ - -bool debugger_commands::debug_command_parameter_expression(std::string_view param, parsed_expression &result) -{ - try - { - // parse the expression; success if no error - result.parse(param); - return true; - } - catch (expression_error const &err) - { - // output an error - m_console.printf("Error in expression: %s\n", param); - m_console.printf(" %*s^", err.offset(), ""); - m_console.printf("%s\n", err.code_string()); - return false; - } -} - - -/*------------------------------------------------- - debug_command_parameter_command - validates a - command parameter --------------------------------------------------*/ - -bool debugger_commands::debug_command_parameter_command(const char *param) -{ - /* nullptr parameter does nothing and returns no error */ - if (param == nullptr) - return true; - - /* validate the comment; success if no error */ - CMDERR err = m_console.validate_command(param); - if (err.error_class() == CMDERR::NONE) - return true; - - /* output an error */ - m_console.printf("Error in command: %s\n", param); - m_console.printf(" %*s^", err.error_offset(), ""); - m_console.printf("%s\n", debugger_console::cmderr_to_string(err)); - return 0; -} +//************************************************************************** +// COMMAND IMPLEMENTATIONS +//************************************************************************** /*------------------------------------------------- execute_help - execute the help command -------------------------------------------------*/ -void debugger_commands::execute_help(const std::vector<std::string> ¶ms) +void debugger_commands::execute_help(const std::vector<std::string_view> ¶ms) { if (params.size() == 0) m_console.printf_wrap(80, "%s\n", debug_get_help(std::string_view())); @@ -923,12 +450,12 @@ void debugger_commands::execute_help(const std::vector<std::string> ¶ms) execute_print - execute the print command -------------------------------------------------*/ -void debugger_commands::execute_print(const std::vector<std::string> ¶ms) +void debugger_commands::execute_print(const std::vector<std::string_view> ¶ms) { /* validate the other parameters */ u64 values[MAX_COMMAND_PARAMS]; for (int i = 0; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; /* then print each one */ @@ -942,131 +469,177 @@ void debugger_commands::execute_print(const std::vector<std::string> ¶ms) mini_printf - safe printf to a buffer -------------------------------------------------*/ -int debugger_commands::mini_printf(char *buffer, const char *format, int params, u64 *param) +bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> ¶ms) { - const char *f = format; - char *p = buffer; + std::string_view const format(params[0]); + auto f = format.begin(); + + int param = 1; + u64 number; - /* parse the string looking for % signs */ - for (;;) + // parse the string looking for % signs + while (f != format.end()) { char c = *f++; - if (!c) break; - /* escape sequences */ + // escape sequences if (c == '\\') { + if (f == format.end()) break; c = *f++; - if (!c) break; switch (c) { - case '\\': *p++ = c; break; - case 'n': *p++ = '\n'; break; + case '\\': stream << c; break; + case 'n': stream << '\n'; break; default: break; } continue; } - /* formatting */ + // formatting else if (c == '%') { + bool left_justify = false; + bool zero_fill = false; int width = 0; - int zerofill = 0; + int precision = 0; - /* parse out the width */ - for (;;) + // parse optional left justification flag + if (f != format.end() && *f == '-') { - c = *f++; - if (!c || c < '0' || c > '9') break; - if (c == '0' && width == 0) - zerofill = 1; - width = width * 10 + (c - '0'); + left_justify = true; + f++; + } + + // parse optional zero fill flag + if (f != format.end() && *f == '0') + { + zero_fill = true; + f++; + } + + // parse optional width + while (f != format.end() && isdigit(*f)) + width = width * 10 + (*f++ - '0'); + if (f == format.end()) + break; + + // apply left justification + if (left_justify) + width = -width; + + if ((c = *f++) == '.') + { + // parse optional precision + while (f != format.end() && isdigit(*f)) + precision = precision * 10 + (*f++ - '0'); + + // get the format + if (f != format.end()) + c = *f++; + else + break; } - if (!c) break; - /* get the format */ switch (c) { case '%': - *p++ = c; + stream << c; break; case 'X': + if (param < params.size() && m_console.validate_number_parameter(params[param++], number)) + util::stream_format(stream, zero_fill ? "%0*X" : "%*X", width, number); + else + { + m_console.printf("Not enough parameters for format!\n"); + return false; + } + break; case 'x': - if (params == 0) + if (param < params.size() && m_console.validate_number_parameter(params[param++], number)) + util::stream_format(stream, zero_fill ? "%0*x" : "%*x", width, number); + else { m_console.printf("Not enough parameters for format!\n"); - return 0; + return false; } - if (u32(*param >> 32) != 0) - p += sprintf(p, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, u32(*param >> 32)); - else if (width > 8) - p += sprintf(p, zerofill ? "%0*X" : "%*X", width - 8, 0); - p += sprintf(p, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, u32(*param)); - param++; - params--; break; case 'O': case 'o': - if (params == 0) - { - m_console.printf("Not enough parameters for format!\n"); - return 0; - } - if (u32(*param >> 60) != 0) - { - p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 20) ? 1 : width - 20, u32(*param >> 60)); - p += sprintf(p, "%0*o", 10, u32(BIT(*param, 30, 30))); - } + if (param < params.size() && m_console.validate_number_parameter(params[param++], number)) + util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number); else { - if (width > 20) - p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 20, 0); - if (u32(BIT(*param, 30, 30)) != 0) - p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 10) ? 1 : width - 10, u32(BIT(*param, 30, 30))); - else if (width > 10) - p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 10, 0); + m_console.printf("Not enough parameters for format!\n"); + return false; } - p += sprintf(p, zerofill ? "%0*o" : "%*o", (width < 10) ? width : 10, u32(BIT(*param, 0, 30))); - param++; - params--; break; case 'D': case 'd': - if (params == 0) + if (param < params.size() && m_console.validate_number_parameter(params[param++], number)) + util::stream_format(stream, zero_fill ? "%0*d" : "%*d", width, number); + else { m_console.printf("Not enough parameters for format!\n"); - return 0; + return false; } - p += sprintf(p, zerofill ? "%0*d" : "%*d", width, u32(*param)); - param++; - params--; break; + case 'C': case 'c': - if (params == 0) + if (param < params.size() && m_console.validate_number_parameter(params[param++], number)) + stream << char(number); + else { m_console.printf("Not enough parameters for format!\n"); - return 0; + return false; } - p += sprintf(p, "%c", char(*param)); - param++; - params--; break; + case 's': + { + address_space *space; + if (param < params.size() && m_console.validate_target_address_parameter(params[param++], -1, space, number)) + { + address_space *tspace; + std::string s; + + for (u32 address = u32(number), taddress; space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, taddress = address, tspace); address++) + { + u8 const data = tspace->read_byte(taddress); + + if (!data) + break; + + s += data; + + if (precision == 1) + break; + else if (precision) + precision--; + } + + util::stream_format(stream, "%*s", width, s); + } + else + { + m_console.printf("Not enough parameters for format!\n"); + return false; + } + } + break; } } - /* normal stuff */ + // normal stuff else - *p++ = c; + stream << c; } - /* NULL-terminate and exit */ - *p = 0; - return 1; + return true; } @@ -1076,12 +649,12 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params, -------------------------------------------------*/ template <typename T> -void debugger_commands::execute_index_command(std::vector<std::string> const ¶ms, T &&apply, char const *unused_message) +void debugger_commands::execute_index_command(std::vector<std::string_view> const ¶ms, T &&apply, char const *unused_message) { std::vector<u64> index(params.size()); for (int paramnum = 0; paramnum < params.size(); paramnum++) { - if (!validate_number_parameter(params[paramnum], index[paramnum])) + if (!m_console.validate_number_parameter(params[paramnum], index[paramnum])) return; } @@ -1105,18 +678,12 @@ void debugger_commands::execute_index_command(std::vector<std::string> const &pa execute_printf - execute the printf command -------------------------------------------------*/ -void debugger_commands::execute_printf(const std::vector<std::string> ¶ms) +void debugger_commands::execute_printf(const std::vector<std::string_view> ¶ms) { - /* validate the other parameters */ - u64 values[MAX_COMMAND_PARAMS]; - for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) - return; - /* then do a printf */ - char buffer[1024]; - if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1])) - m_console.printf("%s\n", buffer); + std::ostringstream buffer; + if (mini_printf(buffer, params)) + m_console.printf("%s\n", std::move(buffer).str()); } @@ -1124,18 +691,12 @@ void debugger_commands::execute_printf(const std::vector<std::string> ¶ms) execute_logerror - execute the logerror command -------------------------------------------------*/ -void debugger_commands::execute_logerror(const std::vector<std::string> ¶ms) +void debugger_commands::execute_logerror(const std::vector<std::string_view> ¶ms) { - /* validate the other parameters */ - u64 values[MAX_COMMAND_PARAMS]; - for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) - return; - /* then do a printf */ - char buffer[1024]; - if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1])) - m_machine.logerror("%s", buffer); + std::ostringstream buffer; + if (mini_printf(buffer, params)) + m_machine.logerror("%s", std::move(buffer).str()); } @@ -1143,18 +704,12 @@ void debugger_commands::execute_logerror(const std::vector<std::string> ¶ms) execute_tracelog - execute the tracelog command -------------------------------------------------*/ -void debugger_commands::execute_tracelog(const std::vector<std::string> ¶ms) +void debugger_commands::execute_tracelog(const std::vector<std::string_view> ¶ms) { - /* validate the other parameters */ - u64 values[MAX_COMMAND_PARAMS]; - for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) - return; - /* then do a printf */ - char buffer[1024]; - if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1])) - m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer); + std::ostringstream buffer; + if (mini_printf(buffer, params)) + m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str()); } @@ -1162,11 +717,10 @@ void debugger_commands::execute_tracelog(const std::vector<std::string> ¶ms) execute_tracesym - execute the tracesym command -------------------------------------------------*/ -void debugger_commands::execute_tracesym(const std::vector<std::string> ¶ms) +void debugger_commands::execute_tracesym(const std::vector<std::string_view> ¶ms) { // build a format string appropriate for the parameters and validate them std::stringstream format; - u64 values[MAX_COMMAND_PARAMS]; for (int i = 0; i < params.size(); i++) { // find this symbol @@ -1181,16 +735,16 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> ¶ms) util::stream_format(format, "%s=%s ", params[i], sym->format().empty() ? "%16X" : sym->format()); - - // validate the parameter - if (!validate_number_parameter(params[i], values[i])) - return; } + // build parameters for printf + std::vector<std::string_view> printf_params(params); + printf_params.insert(printf_params.begin(), format.str()); + // then do a printf - char buffer[1024]; - if (mini_printf(buffer, format.str().c_str(), params.size(), values)) - m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer); + std::ostringstream buffer; + if (mini_printf(buffer, printf_params)) + m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str()); } @@ -1198,7 +752,7 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> ¶ms) execute_cls - execute the cls command -------------------------------------------------*/ -void debugger_commands::execute_cls(const std::vector<std::string> ¶ms) +void debugger_commands::execute_cls(const std::vector<std::string_view> ¶ms) { text_buffer_clear(m_console.get_console_textbuf()); } @@ -1208,7 +762,7 @@ void debugger_commands::execute_cls(const std::vector<std::string> ¶ms) execute_quit - execute the quit command -------------------------------------------------*/ -void debugger_commands::execute_quit(const std::vector<std::string> ¶ms) +void debugger_commands::execute_quit(const std::vector<std::string_view> ¶ms) { osd_printf_warning("Exited via the debugger\n"); m_machine.schedule_exit(); @@ -1219,10 +773,10 @@ void debugger_commands::execute_quit(const std::vector<std::string> ¶ms) execute_do - execute the do command -------------------------------------------------*/ -void debugger_commands::execute_do(const std::vector<std::string> ¶ms) +void debugger_commands::execute_do(const std::vector<std::string_view> ¶ms) { u64 dummy; - validate_number_parameter(params[0], dummy); + m_console.validate_number_parameter(params[0], dummy); } @@ -1230,11 +784,11 @@ void debugger_commands::execute_do(const std::vector<std::string> ¶ms) execute_step - execute the step command -------------------------------------------------*/ -void debugger_commands::execute_step(const std::vector<std::string> ¶ms) +void debugger_commands::execute_step(const std::vector<std::string_view> ¶ms) { /* if we have a parameter, use it */ u64 steps = 1; - if (params.size() > 0 && !validate_number_parameter(params[0], steps)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps)) return; m_console.get_visible_cpu()->debug()->single_step(steps); @@ -1245,11 +799,11 @@ void debugger_commands::execute_step(const std::vector<std::string> ¶ms) execute_over - execute the over command -------------------------------------------------*/ -void debugger_commands::execute_over(const std::vector<std::string> ¶ms) +void debugger_commands::execute_over(const std::vector<std::string_view> ¶ms) { /* if we have a parameter, use it */ u64 steps = 1; - if (params.size() > 0 && !validate_number_parameter(params[0], steps)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps)) return; m_console.get_visible_cpu()->debug()->single_step_over(steps); @@ -1260,7 +814,7 @@ void debugger_commands::execute_over(const std::vector<std::string> ¶ms) execute_out - execute the out command -------------------------------------------------*/ -void debugger_commands::execute_out(const std::vector<std::string> ¶ms) +void debugger_commands::execute_out(const std::vector<std::string_view> ¶ms) { m_console.get_visible_cpu()->debug()->single_step_out(); } @@ -1270,12 +824,12 @@ void debugger_commands::execute_out(const std::vector<std::string> ¶ms) execute_go - execute the go command -------------------------------------------------*/ -void debugger_commands::execute_go(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go(const std::vector<std::string_view> ¶ms) { u64 addr = ~0; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], addr)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], addr)) return; m_console.get_visible_cpu()->debug()->go(addr); @@ -1287,7 +841,7 @@ void debugger_commands::execute_go(const std::vector<std::string> ¶ms) command -------------------------------------------------*/ -void debugger_commands::execute_go_vblank(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go_vblank(const std::vector<std::string_view> ¶ms) { m_console.get_visible_cpu()->debug()->go_vblank(); } @@ -1297,12 +851,12 @@ void debugger_commands::execute_go_vblank(const std::vector<std::string> ¶ms execute_go_interrupt - execute the goint command -------------------------------------------------*/ -void debugger_commands::execute_go_interrupt(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go_interrupt(const std::vector<std::string_view> ¶ms) { u64 irqline = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], irqline)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], irqline)) return; m_console.get_visible_cpu()->debug()->go_interrupt(irqline); @@ -1312,16 +866,16 @@ void debugger_commands::execute_go_interrupt(const std::vector<std::string> &par execute_go_exception - execute the goex command -------------------------------------------------*/ -void debugger_commands::execute_go_exception(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go_exception(const std::vector<std::string_view> ¶ms) { u64 exception = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], exception)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], exception)) return; parsed_expression condition(m_console.visible_symtable()); - if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition)) + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) return; m_console.get_visible_cpu()->debug()->go_exception(exception, condition.is_empty() ? "1" : condition.original_string()); @@ -1332,12 +886,12 @@ void debugger_commands::execute_go_exception(const std::vector<std::string> &par execute_go_time - execute the gtime command -------------------------------------------------*/ -void debugger_commands::execute_go_time(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go_time(const std::vector<std::string_view> ¶ms) { u64 milliseconds = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], milliseconds)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], milliseconds)) return; m_console.get_visible_cpu()->debug()->go_milliseconds(milliseconds); @@ -1348,20 +902,76 @@ void debugger_commands::execute_go_time(const std::vector<std::string> ¶ms) /*------------------------------------------------- execute_go_privilege - execute the gp command -------------------------------------------------*/ -void debugger_commands::execute_go_privilege(const std::vector<std::string> ¶ms) +void debugger_commands::execute_go_privilege(const std::vector<std::string_view> ¶ms) { parsed_expression condition(m_console.visible_symtable()); - if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) return; m_console.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string()); } + +/*------------------------------------------------- + execute_go_branch - execute gbt or gbf command +-------------------------------------------------*/ + +void debugger_commands::execute_go_branch(bool sense, const std::vector<std::string_view> ¶ms) +{ + parsed_expression condition(m_console.visible_symtable()); + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) + return; + + m_console.get_visible_cpu()->debug()->go_branch(sense, (condition.is_empty()) ? "1" : condition.original_string()); +} + + +/*------------------------------------------------- + execute_go_next_instruction - execute gni command +-------------------------------------------------*/ + +void debugger_commands::execute_go_next_instruction(const std::vector<std::string_view> ¶ms) +{ + u64 count = 1; + static constexpr u64 MAX_COUNT = 512; + + // if we have a parameter, use it instead */ + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], count)) + return; + if (count == 0) + return; + if (count > MAX_COUNT) + { + m_console.printf("Too many instructions (must be %d or fewer)\n", MAX_COUNT); + return; + } + + device_state_interface *stateintf; + device_t *cpu = m_console.get_visible_cpu(); + if (!cpu->interface(stateintf)) + { + m_console.printf("No state interface available for %s\n", cpu->name()); + return; + } + u32 pc = stateintf->pcbase(); + + debug_disasm_buffer buffer(*cpu); + while (count-- != 0) + { + // disassemble the current instruction and get the length + u32 result = buffer.disassemble_info(pc); + pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK); + } + + cpu->debug()->go(pc); +} + + /*------------------------------------------------- execute_next - execute the next command -------------------------------------------------*/ -void debugger_commands::execute_next(const std::vector<std::string> ¶ms) +void debugger_commands::execute_next(const std::vector<std::string_view> ¶ms) { m_console.get_visible_cpu()->debug()->go_next_device(); } @@ -1371,11 +981,11 @@ void debugger_commands::execute_next(const std::vector<std::string> ¶ms) execute_focus - execute the focus command -------------------------------------------------*/ -void debugger_commands::execute_focus(const std::vector<std::string> ¶ms) +void debugger_commands::execute_focus(const std::vector<std::string_view> ¶ms) { // validate params device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; // first clear the ignore flag on the focused CPU @@ -1393,7 +1003,7 @@ void debugger_commands::execute_focus(const std::vector<std::string> ¶ms) execute_ignore - execute the ignore command -------------------------------------------------*/ -void debugger_commands::execute_ignore(const std::vector<std::string> ¶ms) +void debugger_commands::execute_ignore(const std::vector<std::string_view> ¶ms) { if (params.empty()) { @@ -1425,7 +1035,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> ¶ms) // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; // set the ignore flags @@ -1456,7 +1066,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> ¶ms) execute_observe - execute the observe command -------------------------------------------------*/ -void debugger_commands::execute_observe(const std::vector<std::string> ¶ms) +void debugger_commands::execute_observe(const std::vector<std::string_view> ¶ms) { if (params.empty()) { @@ -1488,7 +1098,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> ¶ms) // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; // clear the ignore flags @@ -1504,7 +1114,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> ¶ms) execute_suspend - suspend execution on cpu -------------------------------------------------*/ -void debugger_commands::execute_suspend(const std::vector<std::string> ¶ms) +void debugger_commands::execute_suspend(const std::vector<std::string_view> ¶ms) { // if there are no parameters, dump the ignore list if (params.empty()) @@ -1534,7 +1144,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> ¶ms) // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; for (int paramnum = 0; paramnum < params.size(); paramnum++) @@ -1563,7 +1173,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> ¶ms) execute_resume - Resume execution on CPU -------------------------------------------------*/ -void debugger_commands::execute_resume(const std::vector<std::string> ¶ms) +void debugger_commands::execute_resume(const std::vector<std::string_view> ¶ms) { // if there are no parameters, dump the ignore list if (params.empty()) @@ -1593,7 +1203,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> ¶ms) // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; for (int paramnum = 0; paramnum < params.size(); paramnum++) @@ -1608,7 +1218,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> ¶ms) // execute_cpulist - list all CPUs //------------------------------------------------- -void debugger_commands::execute_cpulist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_cpulist(const std::vector<std::string_view> ¶ms) { int index = 0; for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device())) @@ -1619,20 +1229,29 @@ void debugger_commands::execute_cpulist(const std::vector<std::string> ¶ms) } } +//------------------------------------------------- +// execute_time - execute the time command +//------------------------------------------------- + +void debugger_commands::execute_time(const std::vector<std::string_view> ¶ms) +{ + m_console.printf("%s\n", m_machine.time().as_string()); +} + /*------------------------------------------------- execute_comment - add a comment to a line -------------------------------------------------*/ -void debugger_commands::execute_comment_add(const std::vector<std::string> ¶ms) +void debugger_commands::execute_comment_add(const std::vector<std::string_view> ¶ms) { // param 1 is the address for the comment u64 address; - if (!validate_number_parameter(params[0], address)) + if (!m_console.validate_number_parameter(params[0], address)) return; // CPU parameter is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // make sure param 2 exists @@ -1643,7 +1262,8 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> ¶ } // Now try adding the comment - cpu->debug()->comment_add(address, params[1].c_str(), 0x00ff0000); + std::string const text(params[1]); + cpu->debug()->comment_add(address, text.c_str(), 0x00ff0000); cpu->machine().debug_view().update_all(DVT_DISASSEMBLY); } @@ -1652,16 +1272,16 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> ¶ execute_comment_del - remove a comment from an addr --------------------------------------------------------*/ -void debugger_commands::execute_comment_del(const std::vector<std::string> ¶ms) +void debugger_commands::execute_comment_del(const std::vector<std::string_view> ¶ms) { // param 1 can either be a command or the address for the comment u64 address; - if (!validate_number_parameter(params[0], address)) + if (!m_console.validate_number_parameter(params[0], address)) return; // CPU parameter is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // If it's a number, it must be an address @@ -1671,25 +1291,25 @@ void debugger_commands::execute_comment_del(const std::vector<std::string> ¶ } /** - * @fn void execute_comment_list(const std::vector<std::string> ¶ms) + * @fn void execute_comment_list(const std::vector<std::string_view> ¶ms) * @brief Print current list of comments in debugger * * */ -void debugger_commands::execute_comment_list(const std::vector<std::string> ¶ms) +void debugger_commands::execute_comment_list(const std::vector<std::string_view> ¶ms) { if (!m_machine.debugger().cpu().comment_load(false)) m_console.printf("Error while parsing XML file\n"); } /** - * @fn void execute_comment_commit(const std::vector<std::string> ¶ms) + * @fn void execute_comment_commit(const std::vector<std::string_view> ¶ms) * @brief Add and Save current list of comments in debugger * */ -void debugger_commands::execute_comment_commit(const std::vector<std::string> ¶ms) +void debugger_commands::execute_comment_commit(const std::vector<std::string_view> ¶ms) { execute_comment_add(params); execute_comment_save(params); @@ -1699,7 +1319,7 @@ void debugger_commands::execute_comment_commit(const std::vector<std::string> &p execute_comment - add a comment to a line -------------------------------------------------*/ -void debugger_commands::execute_comment_save(const std::vector<std::string> ¶ms) +void debugger_commands::execute_comment_save(const std::vector<std::string_view> ¶ms) { if (m_machine.debugger().cpu().comment_save()) m_console.printf("Comment successfully saved\n"); @@ -1709,7 +1329,7 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par // TODO: add color hex editing capabilities for comments, see below for more info /** - * @fn void execute_comment_color(const std::vector<std::string> ¶ms) + * @fn void execute_comment_color(const std::vector<std::string_view> ¶ms) * @brief Modifies comment given at address $xx with given color * Useful for marking comment with a different color scheme (for example by marking start and end of a given function visually). * @param[in] "address,color" First is the comment address in the current context, color can be hexadecimal or shorthanded to common 1bpp RGB names. @@ -1726,12 +1346,12 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par command -------------------------------------------------*/ -void debugger_commands::execute_bpset(const std::vector<std::string> ¶ms) +void debugger_commands::execute_bpset(const std::vector<std::string_view> ¶ms) { // param 1 is the address/CPU u64 address; address_space *space; - if (!validate_target_address_parameter(params[0], AS_PROGRAM, space, address)) + if (!m_console.validate_target_address_parameter(params[0], AS_PROGRAM, space, address)) return; device_execute_interface const *execute; @@ -1750,12 +1370,12 @@ void debugger_commands::execute_bpset(const std::vector<std::string> ¶ms) // param 2 is the condition parsed_expression condition(debug->symtable()); - if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition)) + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) return; // param 3 is the action - const char *action = nullptr; - if (params.size() > 2 && !debug_command_parameter_command(action = params[2].c_str())) + std::string_view action; + if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2])) return; // set the breakpoint @@ -1769,7 +1389,7 @@ void debugger_commands::execute_bpset(const std::vector<std::string> ¶ms) clear command -------------------------------------------------*/ -void debugger_commands::execute_bpclear(const std::vector<std::string> ¶ms) +void debugger_commands::execute_bpclear(const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, clear all { @@ -1798,7 +1418,7 @@ void debugger_commands::execute_bpclear(const std::vector<std::string> ¶ms) disable/enable commands -------------------------------------------------*/ -void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string> ¶ms) +void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, disable/enable all { @@ -1827,7 +1447,7 @@ void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std:: command -------------------------------------------------*/ -void debugger_commands::execute_bplist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_bplist(const std::vector<std::string_view> ¶ms) { int printed = 0; std::string buffer; @@ -1856,7 +1476,7 @@ void debugger_commands::execute_bplist(const std::vector<std::string> ¶ms) if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -1878,13 +1498,13 @@ void debugger_commands::execute_bplist(const std::vector<std::string> ¶ms) command -------------------------------------------------*/ -void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string_view> ¶ms) { u64 address, length; address_space *space; // param 1 is the address/CPU - if (!validate_target_address_parameter(params[0], spacenum, space, address)) + if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address)) return; device_execute_interface const *execute; @@ -1896,31 +1516,35 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin device_debug *const debug = space->device().debug(); // param 2 is the length - if (!validate_number_parameter(params[1], length)) + if (!m_console.validate_number_parameter(params[1], length)) return; // param 3 is the type read_or_write type; - if (!core_stricmp(params[2].c_str(), "r")) - type = read_or_write::READ; - else if (!core_stricmp(params[2].c_str(), "w")) - type = read_or_write::WRITE; - else if (!core_stricmp(params[2].c_str(), "rw") || !core_stricmp(params[2].c_str(), "wr")) - type = read_or_write::READWRITE; - else { - m_console.printf("Invalid watchpoint type: expected r, w, or rw\n"); - return; + using util::streqlower; + using namespace std::literals; + if (streqlower(params[2], "r"sv)) + type = read_or_write::READ; + else if (streqlower(params[2], "w"sv)) + type = read_or_write::WRITE; + else if (streqlower(params[2], "rw"sv) || streqlower(params[2], "wr"sv)) + type = read_or_write::READWRITE; + else + { + m_console.printf("Invalid watchpoint type: expected r, w, or rw\n"); + return; + } } // param 4 is the condition parsed_expression condition(debug->symtable()); - if (params.size() > 3 && !debug_command_parameter_expression(params[3], condition)) + if (params.size() > 3 && !m_console.validate_expression_parameter(params[3], condition)) return; // param 5 is the action - const char *action = nullptr; - if (params.size() > 4 && !debug_command_parameter_command(action = params[4].c_str())) + std::string_view action; + if (params.size() > 4 && !m_console.validate_command_parameter(action = params[4])) return; // set the watchpoint @@ -1934,7 +1558,7 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin clear command -------------------------------------------------*/ -void debugger_commands::execute_wpclear(const std::vector<std::string> ¶ms) +void debugger_commands::execute_wpclear(const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, clear all { @@ -1963,7 +1587,7 @@ void debugger_commands::execute_wpclear(const std::vector<std::string> ¶ms) disable/enable commands -------------------------------------------------*/ -void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string> ¶ms) +void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, disable/enable all { @@ -1992,7 +1616,7 @@ void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std:: command -------------------------------------------------*/ -void debugger_commands::execute_wplist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_wplist(const std::vector<std::string_view> ¶ms) { int printed = 0; std::string buffer; @@ -2033,7 +1657,7 @@ void debugger_commands::execute_wplist(const std::vector<std::string> ¶ms) if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -2055,21 +1679,21 @@ void debugger_commands::execute_wplist(const std::vector<std::string> ¶ms) command -------------------------------------------------*/ -void debugger_commands::execute_rpset(const std::vector<std::string> ¶ms) +void debugger_commands::execute_rpset(const std::vector<std::string_view> ¶ms) { // CPU is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // param 1 is the condition parsed_expression condition(cpu->debug()->symtable()); - if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) return; // param 2 is the action - const char *action = nullptr; - if (params.size() > 1 && !debug_command_parameter_command(action = params[1].c_str())) + std::string_view action; + if (params.size() > 1 && !m_console.validate_command_parameter(action = params[1])) return; // set the registerpoint @@ -2083,7 +1707,7 @@ void debugger_commands::execute_rpset(const std::vector<std::string> ¶ms) clear command -------------------------------------------------*/ -void debugger_commands::execute_rpclear(const std::vector<std::string> ¶ms) +void debugger_commands::execute_rpclear(const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, clear all { @@ -2112,7 +1736,7 @@ void debugger_commands::execute_rpclear(const std::vector<std::string> ¶ms) disable/enable commands -------------------------------------------------*/ -void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string> ¶ms) +void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string_view> ¶ms) { if (params.empty()) // if no parameters, disable/enable all { @@ -2136,12 +1760,154 @@ void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std:: } +//------------------------------------------------- +// execute_epset - execute the exception point +// set command +//------------------------------------------------- + +void debugger_commands::execute_epset(const std::vector<std::string_view> ¶ms) +{ + // CPU is implicit + device_t *cpu; + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) + return; + + // param 1 is the exception type + u64 type; + if (!m_console.validate_number_parameter(params[0], type)) + return; + + // param 2 is the condition + parsed_expression condition(cpu->debug()->symtable()); + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) + return; + + // param 3 is the action + std::string_view action; + if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2])) + return; + + // set the exception point + int epnum = cpu->debug()->exceptionpoint_set(type, (condition.is_empty()) ? nullptr : condition.original_string(), action); + m_console.printf("Exception point %X set\n", epnum); +} + + +//------------------------------------------------- +// execute_epclear - execute the exception point +// clear command +//------------------------------------------------- + +void debugger_commands::execute_epclear(const std::vector<std::string_view> ¶ms) +{ + if (params.empty()) // if no parameters, clear all + { + for (device_t &device : device_enumerator(m_machine.root_device())) + device.debug()->exceptionpoint_clear_all(); + m_console.printf("Cleared all exception points\n"); + } + else // otherwise, clear the specific ones + { + execute_index_command( + params, + [this] (device_t &device, u64 param) -> bool + { + if (!device.debug()->exceptionpoint_clear(param)) + return false; + m_console.printf("Exception point %X cleared\n", param); + return true; + }, + "Invalid exception point number %X\n"); + } +} + + +//------------------------------------------------- +// execute_epdisenable - execute the exception +// point disable/enable commands +//------------------------------------------------- + +void debugger_commands::execute_epdisenable(bool enable, const std::vector<std::string_view> ¶ms) +{ + if (params.empty()) // if no parameters, disable/enable all + { + for (device_t &device : device_enumerator(m_machine.root_device())) + device.debug()->exceptionpoint_enable_all(enable); + m_console.printf(enable ? "Enabled all exception points\n" : "Disabled all exception points\n"); + } + else // otherwise, disable/enable the specific ones + { + execute_index_command( + params, + [this, enable] (device_t &device, u64 param) -> bool + { + if (!device.debug()->exceptionpoint_enable(param, enable)) + return false; + m_console.printf(enable ? "Exception point %X enabled\n" : "Exception point %X disabled\n", param); + return true; + }, + "Invalid exception point number %X\n"); + } +} + + +//------------------------------------------------- +// execute_eplist - execute the exception point +// list command +//------------------------------------------------- + +void debugger_commands::execute_eplist(const std::vector<std::string_view> ¶ms) +{ + int printed = 0; + std::string buffer; + auto const apply = + [this, &printed, &buffer] (device_t &device) + { + if (!device.debug()->exceptionpoint_list().empty()) + { + m_console.printf("Device '%s' exception points:\n", device.tag()); + + // loop over the exception points + for (const auto &epp : device.debug()->exceptionpoint_list()) + { + debug_exceptionpoint &ep = *epp.second; + buffer = string_format("%c%4X : %X", ep.enabled() ? ' ' : 'D', ep.index(), ep.type()); + if (std::string(ep.condition()).compare("1") != 0) + buffer.append(string_format(" if %s", ep.condition())); + if (!ep.action().empty()) + buffer.append(string_format(" do %s", ep.action())); + m_console.printf("%s\n", buffer); + printed++; + } + } + }; + + if (!params.empty()) + { + device_t *cpu; + if (!m_console.validate_cpu_parameter(params[0], cpu)) + return; + apply(*cpu); + if (!printed) + m_console.printf("No exception points currently installed for CPU %s\n", cpu->tag()); + } + else + { + // loop over all CPUs + for (device_t &device : device_enumerator(m_machine.root_device())) + apply(device); + if (!printed) + m_console.printf("No exception points currently installed\n"); + } +} + + /*------------------------------------------------- execute_rplist - execute the registerpoint list command -------------------------------------------------*/ -void debugger_commands::execute_rplist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_rplist(const std::vector<std::string_view> ¶ms) { int printed = 0; std::string buffer; @@ -2156,7 +1922,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> ¶ms) for (const auto &rp : device.debug()->registerpoint_list()) { buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition()); - if (rp.action() && *rp.action()) + if (!rp.action().empty()) buffer.append(string_format(" do %s", rp.action())); m_console.printf("%s\n", buffer); printed++; @@ -2167,7 +1933,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> ¶ms) if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -2188,10 +1954,9 @@ void debugger_commands::execute_rplist(const std::vector<std::string> ¶ms) execute_statesave - execute the statesave command -------------------------------------------------*/ -void debugger_commands::execute_statesave(const std::vector<std::string> ¶ms) +void debugger_commands::execute_statesave(const std::vector<std::string_view> ¶ms) { - const std::string &filename(params[0]); - m_machine.immediate_save(filename.c_str()); + m_machine.immediate_save(params[0]); m_console.printf("State save attempted. Please refer to window message popup for results.\n"); } @@ -2200,10 +1965,9 @@ void debugger_commands::execute_statesave(const std::vector<std::string> ¶ms execute_stateload - execute the stateload command -------------------------------------------------*/ -void debugger_commands::execute_stateload(const std::vector<std::string> ¶ms) +void debugger_commands::execute_stateload(const std::vector<std::string_view> ¶ms) { - const std::string &filename(params[0]); - m_machine.immediate_load(filename.c_str()); + m_machine.immediate_load(params[0]); // clear all PC & memory tracks for (device_t &device : device_enumerator(m_machine.root_device())) @@ -2219,7 +1983,7 @@ void debugger_commands::execute_stateload(const std::vector<std::string> ¶ms execute_rewind - execute the rewind command -------------------------------------------------*/ -void debugger_commands::execute_rewind(const std::vector<std::string> ¶ms) +void debugger_commands::execute_rewind(const std::vector<std::string_view> ¶ms) { bool success = m_machine.rewind_step(); if (success) @@ -2238,15 +2002,15 @@ void debugger_commands::execute_rewind(const std::vector<std::string> ¶ms) execute_save - execute the save command -------------------------------------------------*/ -void debugger_commands::execute_save(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> ¶ms) { u64 offset, endoffset, length; address_space *space; // validate parameters - if (!validate_target_address_parameter(params[1], spacenum, space, offset)) + if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; // determine the addresses to write @@ -2255,7 +2019,8 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string endoffset++; // open the file - FILE *const f = fopen(params[0].c_str(), "wb"); + std::string const filename(params[0]); + FILE *const f = fopen(filename.c_str(), "wb"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2270,8 +2035,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string for (u64 i = offset; i != endoffset; i++) { offs_t curaddr = i; - u64 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ? - space->read_qword(curaddr) : space->unmap(); + address_space *tspace; + u64 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ? + tspace->read_qword(curaddr) : space->unmap(); fwrite(&data, 8, 1, f); } break; @@ -2279,8 +2045,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string for (u64 i = offset; i != endoffset; i++) { offs_t curaddr = i; - u32 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ? - space->read_dword(curaddr) : space->unmap(); + address_space *tspace; + u32 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ? + tspace->read_dword(curaddr) : space->unmap(); fwrite(&data, 4, 1, f); } break; @@ -2288,8 +2055,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string for (u64 i = offset; i != endoffset; i++) { offs_t curaddr = i; - u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ? - space->read_word(curaddr) : space->unmap(); + address_space *tspace; + u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ? + tspace->read_word(curaddr) : space->unmap(); fwrite(&data, 2, 1, f); } break; @@ -2297,8 +2065,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string for (u64 i = offset; i != endoffset; i++) { offs_t curaddr = i; - u8 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ? - space->read_byte(curaddr) : space->unmap(); + address_space *tspace; + u8 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ? + tspace->read_byte(curaddr) : space->unmap(); fwrite(&data, 1, 1, f); } break; @@ -2308,8 +2077,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string for (u64 i = offset; i != endoffset; i+=16) { offs_t curaddr = i; - u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ? - space->read_word(curaddr) : space->unmap(); + address_space *tspace; + u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ? + tspace->read_word(curaddr) : space->unmap(); fwrite(&data, 2, 1, f); } break; @@ -2325,17 +2095,17 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string execute_saveregion - execute the save command on region memory -------------------------------------------------*/ -void debugger_commands::execute_saveregion(const std::vector<std::string> ¶ms) +void debugger_commands::execute_saveregion(const std::vector<std::string_view> ¶ms) { u64 offset, length; memory_region *region; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (!validate_memory_region_parameter(params[3], region)) + if (!m_console.validate_memory_region_parameter(params[3], region)) return; if (offset >= region->bytes()) @@ -2347,7 +2117,8 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> ¶m length = region->bytes() - offset; /* open the file */ - FILE *f = fopen(params[0].c_str(), "wb"); + std::string const filename(params[0]); + FILE *f = fopen(filename.c_str(), "wb"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2364,20 +2135,21 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> ¶m execute_load - execute the load command -------------------------------------------------*/ -void debugger_commands::execute_load(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> ¶ms) { u64 offset, endoffset, length = 0; address_space *space; // validate parameters - if (!validate_target_address_parameter(params[1], spacenum, space, offset)) + if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset)) return; - if (params.size() > 2 && !validate_number_parameter(params[2], length)) + if (params.size() > 2 && !m_console.validate_number_parameter(params[2], length)) return; // open the file std::ifstream f; - f.open(params[0], std::ifstream::in | std::ifstream::binary); + std::string const fname(params[0]); + f.open(fname, std::ifstream::in | std::ifstream::binary); if (f.fail()) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2411,8 +2183,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string offs_t curaddr = i; u64 data; f.read((char *)&data, 8); - if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr)) - space->write_qword(curaddr, data); + address_space *tspace; + if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace)) + tspace->write_qword(curaddr, data); } break; case -2: @@ -2421,8 +2194,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string offs_t curaddr = i; u32 data; f.read((char *)&data, 4); - if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr)) - space->write_dword(curaddr, data); + address_space *tspace; + if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace)) + tspace->write_dword(curaddr, data); } break; case -1: @@ -2431,8 +2205,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string offs_t curaddr = i; u16 data; f.read((char *)&data, 2); - if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr)) - space->write_word(curaddr, data); + address_space *tspace; + if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace)) + tspace->write_word(curaddr, data); } break; case 0: @@ -2441,8 +2216,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string offs_t curaddr = i; u8 data; f.read((char *)&data, 1); - if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr)) - space->write_byte(curaddr, data); + address_space *tspace; + if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace)) + tspace->write_byte(curaddr, data); } break; case 3: @@ -2453,8 +2229,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string offs_t curaddr = i; u16 data; f.read((char *)&data, 2); - if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr)) - space->write_word(curaddr, data); + address_space *tspace; + if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace)) + tspace->write_word(curaddr, data); } break; } @@ -2472,17 +2249,17 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string execute_loadregion - execute the load command on region memory -------------------------------------------------*/ -void debugger_commands::execute_loadregion(const std::vector<std::string> ¶ms) +void debugger_commands::execute_loadregion(const std::vector<std::string_view> ¶ms) { u64 offset, length; memory_region *region; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (!validate_memory_region_parameter(params[3], region)) + if (!m_console.validate_memory_region_parameter(params[3], region)) return; if (offset >= region->bytes()) @@ -2494,7 +2271,8 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> ¶m length = region->bytes() - offset; // open the file - FILE *const f = fopen(params[0].c_str(), "rb"); + std::string filename(params[0]); + FILE *const f = fopen(filename.c_str(), "rb"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2520,28 +2298,28 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> ¶m execute_dump - execute the dump command -------------------------------------------------*/ -void debugger_commands::execute_dump(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> ¶ms) { // validate parameters address_space *space; u64 offset; - if (!validate_target_address_parameter(params[1], spacenum, space, offset)) + if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset)) return; u64 length; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; u64 width = 0; - if (params.size() > 3 && !validate_number_parameter(params[3], width)) + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width)) return; bool ascii = true; - if (params.size() > 4 && !validate_boolean_parameter(params[4], ascii)) + if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii)) return; u64 rowsize = space->byte_to_address(16); - if (params.size() > 5 && !validate_number_parameter(params[5], rowsize)) + if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize)) return; int shift = space->addr_shift(); @@ -2572,7 +2350,8 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string offset = offset & space->addrmask(); // open the file - FILE *const f = fopen(params[0].c_str(), "w"); + std::string filename(params[0]); + FILE *const f = fopen(filename.c_str(), "w"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2602,21 +2381,22 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string if (i + j <= endoffset) { offs_t curaddr = i + j; - if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr)) + address_space *tspace; + if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace)) { switch (width) { case 8: - util::stream_format(output, " %016X", space->read_qword_unaligned(i+j)); + util::stream_format(output, " %016X", tspace->read_qword_unaligned(i+j)); break; case 4: - util::stream_format(output, " %08X", space->read_dword_unaligned(i+j)); + util::stream_format(output, " %08X", tspace->read_dword_unaligned(i+j)); break; case 2: - util::stream_format(output, " %04X", space->read_word_unaligned(i+j)); + util::stream_format(output, " %04X", tspace->read_word_unaligned(i+j)); break; case 1: - util::stream_format(output, " %02X", space->read_byte(i+j)); + util::stream_format(output, " %02X", tspace->read_byte(i+j)); break; } } @@ -2636,22 +2416,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string for (u64 j = 0; j < rowsize && (i + j) <= endoffset; j += delta) { offs_t curaddr = i + j; - if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr)) + address_space *tspace; + if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace)) { u64 data = 0; switch (width) { case 8: - data = space->read_qword_unaligned(i+j); + data = tspace->read_qword_unaligned(i+j); break; case 4: - data = space->read_dword_unaligned(i+j); + data = tspace->read_dword_unaligned(i+j); break; case 2: - data = space->read_word_unaligned(i+j); + data = tspace->read_word_unaligned(i+j); break; case 1: - data = space->read_byte(i+j); + data = tspace->read_byte(i+j); break; } for (unsigned int b = 0; b != width; b++) { @@ -2681,23 +2462,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string // execute_strdump - execute the strdump command //------------------------------------------------- -void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms) { // validate parameters u64 offset; - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; u64 length; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; u64 term = 0; - if (params.size() > 3 && !validate_number_parameter(params[3], term)) + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term)) return; address_space *space; - if (!validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space)) + if (!m_console.validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space)) return; // further validation @@ -2708,7 +2489,8 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str } // open the file - FILE *f = fopen(params[0].c_str(), "w"); + std::string filename(params[0]); + FILE *f = fopen(filename.c_str(), "w"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -2746,28 +2528,29 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str // get the character data u64 data = 0; offs_t curaddr = offset; - if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr)) + address_space *tspace; + if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace)) { switch (width) { case 1: - data = space->read_byte(curaddr); + data = tspace->read_byte(curaddr); break; case 2: - data = space->read_word(curaddr); + data = tspace->read_word(curaddr); if (be) data = swapendian_int16(data); break; case 4: - data = space->read_dword(curaddr); + data = tspace->read_dword(curaddr); if (be) data = swapendian_int32(data); break; case 8: - data = space->read_qword(curaddr); + data = tspace->read_qword(curaddr); if (be) data = swapendian_int64(data); break; @@ -2857,7 +2640,7 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str cheats -------------------------------------------------*/ -void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string> ¶ms) +void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string_view> ¶ms) { address_space *space = m_cheat.space; if (!space && !init) @@ -2874,7 +2657,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str // first argument is sign/size/swap flags if (!params.empty()) { - std::string const &srtpnt = params[0]; + std::string_view const &srtpnt = params[0]; if (!srtpnt.empty()) { width = 1; @@ -2927,7 +2710,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str } // fourth argument is device/space - if (!validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space)) + if (!m_console.validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space)) return; } @@ -2937,9 +2720,9 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str { // validate parameters u64 offset, length; - if (!validate_number_parameter(params[init ? 1 : 0], offset)) + if (!m_console.validate_number_parameter(params[init ? 1 : 0], offset)) return; - if (!validate_number_parameter(params[init ? 2 : 1], length)) + if (!m_console.validate_number_parameter(params[init ? 2 : 1], length)) return; // force region to the specified range @@ -3026,7 +2809,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str execute_cheatnext - execute the search -------------------------------------------------*/ -void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string> ¶ms) +void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string_view> ¶ms) { enum { @@ -3054,36 +2837,40 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s } u64 comp_value = 0; - if (params.size() > 1 && !validate_number_parameter(params[1], comp_value)) + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], comp_value)) return; comp_value = m_cheat.sign_extend(comp_value); // decode condition u8 condition; - if (!core_stricmp(params[0].c_str(), "all")) - condition = CHEAT_ALL; - else if (!core_stricmp(params[0].c_str(), "equal") || !core_stricmp(params[0].c_str(), "eq")) - condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL; - else if (!core_stricmp(params[0].c_str(), "notequal") || !core_stricmp(params[0].c_str(), "ne")) - condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL; - else if (!core_stricmp(params[0].c_str(), "decrease") || !core_stricmp(params[0].c_str(), "de") || params[0] == "-") - condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE; - else if (!core_stricmp(params[0].c_str(), "increase") || !core_stricmp(params[0].c_str(), "in") || params[0] == "+") - condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE; - else if (!core_stricmp(params[0].c_str(), "decreaseorequal") || !core_stricmp(params[0].c_str(), "deeq")) - condition = CHEAT_DECREASE_OR_EQUAL; - else if (!core_stricmp(params[0].c_str(), "increaseorequal") || !core_stricmp(params[0].c_str(), "ineq")) - condition = CHEAT_INCREASE_OR_EQUAL; - else if (!core_stricmp(params[0].c_str(), "smallerof") || !core_stricmp(params[0].c_str(), "lt") || params[0] == "<") - condition = CHEAT_SMALLEROF; - else if (!core_stricmp(params[0].c_str(), "greaterof") || !core_stricmp(params[0].c_str(), "gt") || params[0] == ">") - condition = CHEAT_GREATEROF; - else if (!core_stricmp(params[0].c_str(), "changedby") || !core_stricmp(params[0].c_str(), "ch") || params[0] == "~") - condition = CHEAT_CHANGEDBY; - else { - m_console.printf("Invalid condition type\n"); - return; + using util::streqlower; + using namespace std::literals; + if (streqlower(params[0], "all"sv)) + condition = CHEAT_ALL; + else if (streqlower(params[0], "equal"sv) || streqlower(params[0], "eq"sv)) + condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL; + else if (streqlower(params[0], "notequal"sv) || streqlower(params[0], "ne"sv)) + condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL; + else if (streqlower(params[0], "decrease"sv) || streqlower(params[0], "de"sv) || params[0] == "-"sv) + condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE; + else if (streqlower(params[0], "increase"sv) || streqlower(params[0], "in"sv) || params[0] == "+"sv) + condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE; + else if (streqlower(params[0], "decreaseorequal"sv) || streqlower(params[0], "deeq"sv)) + condition = CHEAT_DECREASE_OR_EQUAL; + else if (streqlower(params[0], "increaseorequal"sv) || streqlower(params[0], "ineq"sv)) + condition = CHEAT_INCREASE_OR_EQUAL; + else if (streqlower(params[0], "smallerof"sv) || streqlower(params[0], "lt"sv) || params[0] == "<"sv) + condition = CHEAT_SMALLEROF; + else if (streqlower(params[0], "greaterof"sv) || streqlower(params[0], "gt"sv) || params[0] == ">"sv) + condition = CHEAT_GREATEROF; + else if (streqlower(params[0], "changedby"sv) || streqlower(params[0], "ch"sv) || params[0] == "~"sv) + condition = CHEAT_CHANGEDBY; + else + { + m_console.printf("Invalid condition type\n"); + return; + } } m_cheat.undo++; @@ -3190,7 +2977,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s } if (active_cheat <= 5) - execute_cheatlist(std::vector<std::string>()); + execute_cheatlist(std::vector<std::string_view>()); m_console.printf("%u cheats found\n", active_cheat); } @@ -3200,7 +2987,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s execute_cheatlist - show a list of active cheat -------------------------------------------------*/ -void debugger_commands::execute_cheatlist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_cheatlist(const std::vector<std::string_view> ¶ms) { address_space *const space = m_cheat.space; if (!space) @@ -3212,7 +2999,8 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> ¶ms FILE *f = nullptr; if (params.size() > 0) { - f = fopen(params[0].c_str(), "w"); + std::string filename(params[0]); + f = fopen(filename.c_str(), "w"); if (!f) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -3317,7 +3105,7 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> ¶ms execute_cheatundo - undo the last search -------------------------------------------------*/ -void debugger_commands::execute_cheatundo(const std::vector<std::string> ¶ms) +void debugger_commands::execute_cheatundo(const std::vector<std::string_view> ¶ms) { if (m_cheat.undo > 0) { @@ -3346,15 +3134,15 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string> ¶ms execute_find - execute the find command -------------------------------------------------*/ -void debugger_commands::execute_find(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> ¶ms) { u64 offset, length; address_space *space; // validate parameters - if (!validate_target_address_parameter(params[0], spacenum, space, offset)) + if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset)) return; - if (!validate_number_parameter(params[1], length)) + if (!m_console.validate_number_parameter(params[1], length)) return; // further validation @@ -3370,11 +3158,11 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string int data_count = 0; for (int i = 2; i < params.size(); i++) { - char const *pdata = params[i].c_str(); - auto const pdatalen = params[i].length() - 1; + std::string_view pdata = params[i]; - if (pdata[0] == '"' && pdata[pdatalen] == '"') // check for a string + if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') // check for a string { + auto const pdatalen = params[i].length() - 1; for (int j = 1; j < pdatalen; j++) { data_to_find[data_count] = pdata[j]; @@ -3385,17 +3173,20 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string { // check for a 'b','w','d',or 'q' prefix data_size[data_count] = cur_data_size; - if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata += 2; } - if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata += 2; } - if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata += 2; } - if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata += 2; } + if (pdata.length() >= 2) + { + if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); } + } // look for a wildcard - if (!strcmp(pdata, "?")) + if (pdata == "?") data_size[data_count++] |= 0x10; // otherwise, validate as a number - else if (!validate_number_parameter(params[i], data_to_find[data_count++])) + else if (!m_console.validate_number_parameter(pdata, data_to_find[data_count++])) return; } } @@ -3413,36 +3204,37 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string for (int j = 0; j < data_count && match; j++) { offs_t address = space->byte_to_address(i + suboffset); + address_space *tspace; switch (data_size[j]) { case 1: address &= space->logaddrmask(); - if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) - match = space->read_byte(address) == u8(data_to_find[j]); + if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace)) + match = tspace->read_byte(address) == u8(data_to_find[j]); else match = false; break; case 2: address &= space->logaddrmask(); - if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) - match = space->read_word_unaligned(address) == u16(data_to_find[j]); + if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace)) + match = tspace->read_word_unaligned(address) == u16(data_to_find[j]); else match = false; break; case 4: address &= space->logaddrmask(); - if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) - match = space->read_dword_unaligned(address) == u32(data_to_find[j]); + if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace)) + match = tspace->read_dword_unaligned(address) == u32(data_to_find[j]); else match = false; break; case 8: address &= space->logaddrmask(); - if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) - match = space->read_qword_unaligned(address) == u64(data_to_find[j]); + if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace)) + match = tspace->read_qword_unaligned(address) == u64(data_to_find[j]); else match = false; break; @@ -3472,15 +3264,15 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string // execute_fill - execute the fill command //------------------------------------------------- -void debugger_commands::execute_fill(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> ¶ms) { u64 offset, length; address_space *space; // validate parameters - if (!validate_target_address_parameter(params[0], spacenum, space, offset)) + if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset)) return; - if (!validate_number_parameter(params[1], length)) + if (!m_console.validate_number_parameter(params[1], length)) return; // further validation @@ -3495,12 +3287,12 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string int data_count = 0; for (int i = 2; i < params.size(); i++) { - const char *pdata = params[i].c_str(); - size_t pdatalen = strlen(pdata) - 1; + std::string_view pdata = params[i]; // check for a string - if (pdata[0] == '"' && pdata[pdatalen] == '"') + if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') { + auto const pdatalen = pdata.length() - 1; for (int j = 1; j < pdatalen; j++) { fill_data[data_count] = pdata[j]; @@ -3513,13 +3305,16 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string { // check for a 'b','w','d',or 'q' prefix fill_data_size[data_count] = cur_data_size; - if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata += 2; } - if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata += 2; } - if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata += 2; } - if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata += 2; } + if (pdata.length() >= 2) + { + if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); } + if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); } + } // validate as a number - if (!validate_number_parameter(pdata, fill_data[data_count++])) + if (!m_console.validate_number_parameter(pdata, fill_data[data_count++])) return; } } @@ -3536,7 +3331,8 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string for (int j = 0; j < data_count; j++) { offs_t address = space->byte_to_address(offset) & space->logaddrmask(); - if (!memory.translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, address)) + address_space *tspace; + if (!memory.translate(space->spacenum(), device_memory_interface::TR_WRITE, address, tspace)) { m_console.printf("Fill aborted due to page fault at %0*X\n", space->logaddrchars(), space->byte_to_address(offset) & space->logaddrmask()); length = 0; @@ -3545,19 +3341,19 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string switch (fill_data_size[j]) { case 1: - space->write_byte(address, fill_data[j]); + tspace->write_byte(address, fill_data[j]); break; case 2: - space->write_word_unaligned(address, fill_data[j]); + tspace->write_word_unaligned(address, fill_data[j]); break; case 4: - space->write_dword_unaligned(address, fill_data[j]); + tspace->write_dword_unaligned(address, fill_data[j]); break; case 8: - space->read_qword_unaligned(address, fill_data[j]); + tspace->read_qword_unaligned(address, fill_data[j]); break; } offset += fill_data_size[j]; @@ -3577,20 +3373,20 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string execute_dasm - execute the dasm command -------------------------------------------------*/ -void debugger_commands::execute_dasm(const std::vector<std::string> ¶ms) +void debugger_commands::execute_dasm(const std::vector<std::string_view> ¶ms) { u64 offset, length; bool bytes = true; address_space *space; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (params.size() > 3 && !validate_boolean_parameter(params[3], bytes)) + if (params.size() > 3 && !m_console.validate_boolean_parameter(params[3], bytes)) return; - if (!validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space)) + if (!m_console.validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space)) return; // determine the width of the bytes @@ -3636,7 +3432,8 @@ void debugger_commands::execute_dasm(const std::vector<std::string> ¶ms) } /* write the data */ - std::ofstream f(params[0]); + std::string fname(params[0]); + std::ofstream f(fname); if (!f.good()) { m_console.printf("Error opening file '%s'\n", params[0]); @@ -3675,32 +3472,32 @@ void debugger_commands::execute_dasm(const std::vector<std::string> ¶ms) trace over and trace info -------------------------------------------------*/ -void debugger_commands::execute_trace(const std::vector<std::string> ¶ms, bool trace_over) +void debugger_commands::execute_trace(const std::vector<std::string_view> ¶ms, bool trace_over) { - const char *action = nullptr; + std::string_view action; bool detect_loops = true; bool logerror = false; - device_t *cpu; - const char *mode; - std::string filename = params[0]; + std::string filename(params[0]); // replace macros strreplace(filename, "{game}", m_machine.basename()); // validate parameters - if (!validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu)) + device_t *cpu; + if (!m_console.validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu)) return; if (params.size() > 2) { std::stringstream stream; - stream.str(params[2]); + stream.str(std::string(params[2])); std::string flag; while (std::getline(stream, flag, '|')) { - if (!core_stricmp(flag.c_str(), "noloop")) + using namespace std::literals; + if (util::streqlower(flag, "noloop"sv)) detect_loops = false; - else if (!core_stricmp(flag.c_str(), "logerror")) + else if (util::streqlower(flag, "logerror"sv)) logerror = true; else { @@ -3709,24 +3506,27 @@ void debugger_commands::execute_trace(const std::vector<std::string> ¶ms, bo } } } - if (!debug_command_parameter_command(action = (params.size() > 3) ? params[3].c_str() : nullptr)) + if (params.size() > 3 && !m_console.validate_command_parameter(action = params[3])) return; // open the file - FILE *f = nullptr; - if (core_stricmp(filename.c_str(), "off") != 0) + std::unique_ptr<std::ofstream> f; + using namespace std::literals; + if (!util::streqlower(filename, "off"sv)) { - mode = "w"; + std::ios_base::openmode mode = std::ios_base::out; // opening for append? if ((filename[0] == '>') && (filename[1] == '>')) { - mode = "a"; + mode |= std::ios_base::ate; filename = filename.substr(2); } + else + mode |= std::ios_base::trunc; - f = fopen(filename.c_str(), mode); - if (!f) + f = std::make_unique<std::ofstream>(filename.c_str(), mode); + if (f->fail()) { m_console.printf("Error opening file '%s'\n", params[0]); return; @@ -3734,8 +3534,9 @@ void debugger_commands::execute_trace(const std::vector<std::string> ¶ms, bo } // do it - cpu->debug()->trace(f, trace_over, detect_loops, logerror, action); - if (f) + bool const on(f); + cpu->debug()->trace(std::move(f), trace_over, detect_loops, logerror, action); + if (on) m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename); else m_console.printf("Stopped tracing on CPU '%s'\n", cpu->tag()); @@ -3746,7 +3547,7 @@ void debugger_commands::execute_trace(const std::vector<std::string> ¶ms, bo execute_traceflush - execute the trace flush command -------------------------------------------------*/ -void debugger_commands::execute_traceflush(const std::vector<std::string> ¶ms) +void debugger_commands::execute_traceflush(const std::vector<std::string_view> ¶ms) { m_machine.debugger().cpu().flush_traces(); } @@ -3756,15 +3557,15 @@ void debugger_commands::execute_traceflush(const std::vector<std::string> ¶m execute_history - execute the history command -------------------------------------------------*/ -void debugger_commands::execute_history(const std::vector<std::string> ¶ms) +void debugger_commands::execute_history(const std::vector<std::string_view> ¶ms) { // validate parameters device_t *device; - if (!validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device)) + if (!m_console.validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device)) return; u64 count = device_debug::HISTORY_SIZE; - if (params.size() > 1 && !validate_number_parameter(params[1], count)) + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], count)) return; // further validation @@ -3781,13 +3582,13 @@ void debugger_commands::execute_history(const std::vector<std::string> ¶ms) } // loop over lines - debug_disasm_buffer buffer(*device); std::string instruction; for (int index = int(unsigned(count)); index > 0; index--) { auto const pc = debug->history_pc(1 - index); if (pc.second) { + debug_disasm_buffer buffer(*device); offs_t next_offset; offs_t size; u32 info; @@ -3804,16 +3605,16 @@ void debugger_commands::execute_history(const std::vector<std::string> ¶ms) execute_trackpc - execute the trackpc command -------------------------------------------------*/ -void debugger_commands::execute_trackpc(const std::vector<std::string> ¶ms) +void debugger_commands::execute_trackpc(const std::vector<std::string_view> ¶ms) { // Gather the on/off switch (if present) bool turnOn = true; - if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn)) + if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn)) return; // Gather the cpu id (if present) device_t *cpu = nullptr; - if (!validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu)) return; const device_state_interface *state; @@ -3825,7 +3626,7 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> ¶ms) // Should we clear the existing data? bool clear = false; - if (params.size() > 2 && !validate_boolean_parameter(params[2], clear)) + if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear)) return; cpu->debug()->set_track_pc((bool)turnOn); @@ -3853,11 +3654,11 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> ¶ms) execute_trackmem - execute the trackmem command -------------------------------------------------*/ -void debugger_commands::execute_trackmem(const std::vector<std::string> ¶ms) +void debugger_commands::execute_trackmem(const std::vector<std::string_view> ¶ms) { // Gather the on/off switch (if present) bool turnOn = true; - if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn)) + if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn)) return; // Gather the cpu id (if present) @@ -3865,17 +3666,17 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> ¶ms) if (params.size() > 1) cpuparam = params[1]; device_t *cpu = nullptr; - if (!validate_cpu_parameter(cpuparam, cpu)) + if (!m_console.validate_cpu_parameter(cpuparam, cpu)) return; // Should we clear the existing data? bool clear = false; - if (params.size() > 2 && !validate_boolean_parameter(params[2], clear)) + if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear)) return; // Get the address space for the given cpu address_space *space; - if (!validate_device_space_parameter(cpuparam, AS_PROGRAM, space)) + if (!m_console.validate_device_space_parameter(cpuparam, AS_PROGRAM, space)) return; // Inform the CPU it's time to start tracking memory writes @@ -3891,17 +3692,18 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> ¶ms) execute_pcatmem - execute the pcatmem command -------------------------------------------------*/ -void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string_view> ¶ms) { // Gather the required target address/space parameter u64 address; address_space *space; - if (!validate_target_address_parameter(params[0], spacenum, space, address)) + if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address)) return; // Translate the address offs_t a = address & space->logaddrmask(); - if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a)) + address_space *tspace; + if (!space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, a, tspace)) { m_console.printf("Address translation failed\n"); return; @@ -3913,19 +3715,19 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str switch (space->data_width()) { case 8: - data = space->read_byte(a); + data = tspace->read_byte(a); break; case 16: - data = space->read_word_unaligned(a); + data = tspace->read_word_unaligned(a); break; case 32: - data = space->read_dword_unaligned(a); + data = tspace->read_dword_unaligned(a); break; case 64: - data = space->read_qword_unaligned(a); + data = tspace->read_qword_unaligned(a); break; } @@ -3942,7 +3744,7 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str execute_snap - execute the snapshot command -------------------------------------------------*/ -void debugger_commands::execute_snap(const std::vector<std::string> ¶ms) +void debugger_commands::execute_snap(const std::vector<std::string_view> ¶ms) { /* if no params, use the default behavior */ if (params.empty()) @@ -3954,8 +3756,9 @@ void debugger_commands::execute_snap(const std::vector<std::string> ¶ms) /* otherwise, we have to open the file ourselves */ else { - const char *filename = params[0].c_str(); - int scrnum = (params.size() > 1) ? atoi(params[1].c_str()) : 0; + u64 scrnum = 0; + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], scrnum)) + return; screen_device_enumerator iter(m_machine.root_device()); screen_device *screen = iter.byindex(scrnum); @@ -3966,7 +3769,7 @@ void debugger_commands::execute_snap(const std::vector<std::string> ¶ms) return; } - std::string fname(filename); + std::string fname(params[0]); if (fname.find(".png") == -1) fname.append(".png"); emu_file file(m_machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); @@ -3974,12 +3777,12 @@ void debugger_commands::execute_snap(const std::vector<std::string> ¶ms) if (filerr) { - m_console.printf("Error creating file '%s' (%s:%d %s)\n", filename, filerr.category().name(), filerr.value(), filerr.message()); + m_console.printf("Error creating file '%s' (%s:%d %s)\n", params[0], filerr.category().name(), filerr.value(), filerr.message()); return; } screen->machine().video().save_snapshot(screen, file); - m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, filename); + m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, params[0]); } } @@ -3988,9 +3791,10 @@ void debugger_commands::execute_snap(const std::vector<std::string> ¶ms) execute_source - execute the source command -------------------------------------------------*/ -void debugger_commands::execute_source(const std::vector<std::string> ¶ms) +void debugger_commands::execute_source(const std::vector<std::string_view> ¶ms) { - m_console.source_script(params[0].c_str()); + std::string filename(params[0]); + m_console.source_script(filename.c_str()); } @@ -3998,27 +3802,29 @@ void debugger_commands::execute_source(const std::vector<std::string> ¶ms) execute_map - execute the map command -------------------------------------------------*/ -void debugger_commands::execute_map(int spacenum, const std::vector<std::string> ¶ms) +void debugger_commands::execute_map(int spacenum, const std::vector<std::string_view> ¶ms) { // validate parameters u64 address; address_space *space; - if (!validate_target_address_parameter(params[0], spacenum, space, address)) + if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address)) return; + address &= space->logaddrmask(); // do the translation first - for (int intention = TRANSLATE_READ_DEBUG; intention <= TRANSLATE_FETCH_DEBUG; intention++) + for (int intention = device_memory_interface::TR_READ; intention <= device_memory_interface::TR_FETCH; intention++) { static const char *const intnames[] = { "Read", "Write", "Fetch" }; - offs_t taddress = address & space->addrmask(); - if (space->device().memory().translate(space->spacenum(), intention, taddress)) + offs_t taddress = address; + address_space *tspace; + if (space->device().memory().translate(space->spacenum(), intention, taddress, tspace)) { - std::string mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress); + std::string mapname = tspace->get_handler_string((intention == device_memory_interface::TR_WRITE) ? read_or_write::WRITE : read_or_write::READ, taddress); m_console.printf( - "%7s: %0*X logical == %0*X physical -> %s\n", + "%7s: %0*X logical %s == %0*X physical %s -> %s\n", intnames[intention & 3], - space->logaddrchars(), address, - space->addrchars(), taddress, + space->logaddrchars(), address, space->name(), + tspace->addrchars(), taddress, tspace->name(), mapname); } else @@ -4031,14 +3837,15 @@ void debugger_commands::execute_map(int spacenum, const std::vector<std::string> execute_memdump - execute the memdump command -------------------------------------------------*/ -void debugger_commands::execute_memdump(const std::vector<std::string> ¶ms) +void debugger_commands::execute_memdump(const std::vector<std::string_view> ¶ms) { device_t *root = &m_machine.root_device(); - if ((params.size() >= 2) && !validate_device_parameter(params[1], root)) + if ((params.size() >= 2) && !m_console.validate_device_parameter(params[1], root)) return; - char const *const filename = params.empty() ? "memdump.log" : params[0].c_str(); - FILE *const file = fopen(filename, "w"); + using namespace std::literals; + std::string filename = params.empty() ? "memdump.log"s : std::string(params[0]); + FILE *const file = fopen(filename.c_str(), "w"); if (!file) { m_console.printf("Error opening file %s\n", filename); @@ -4097,7 +3904,7 @@ void debugger_commands::execute_memdump(const std::vector<std::string> ¶ms) execute_symlist - execute the symlist command -------------------------------------------------*/ -void debugger_commands::execute_symlist(const std::vector<std::string> ¶ms) +void debugger_commands::execute_symlist(const std::vector<std::string_view> ¶ms) { const char *namelist[1000]; symbol_table *symtable; @@ -4107,7 +3914,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> ¶ms) { // validate parameters device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; symtable = &cpu->debug()->symtable(); m_console.printf("CPU '%s' symbols:\n", cpu->tag()); @@ -4159,7 +3966,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> ¶ms) execute_softreset - execute the softreset command -------------------------------------------------*/ -void debugger_commands::execute_softreset(const std::vector<std::string> ¶ms) +void debugger_commands::execute_softreset(const std::vector<std::string_view> ¶ms) { m_machine.schedule_soft_reset(); } @@ -4169,7 +3976,7 @@ void debugger_commands::execute_softreset(const std::vector<std::string> ¶ms execute_hardreset - execute the hardreset command -------------------------------------------------*/ -void debugger_commands::execute_hardreset(const std::vector<std::string> ¶ms) +void debugger_commands::execute_hardreset(const std::vector<std::string_view> ¶ms) { m_machine.schedule_hard_reset(); } @@ -4179,7 +3986,7 @@ void debugger_commands::execute_hardreset(const std::vector<std::string> ¶ms mounted files -------------------------------------------------*/ -void debugger_commands::execute_images(const std::vector<std::string> ¶ms) +void debugger_commands::execute_images(const std::vector<std::string_view> ¶ms) { image_interface_enumerator iter(m_machine.root_device()); for (device_image_interface &img : iter) @@ -4209,16 +4016,25 @@ void debugger_commands::execute_images(const std::vector<std::string> ¶ms) execute_mount - execute the image mount command -------------------------------------------------*/ -void debugger_commands::execute_mount(const std::vector<std::string> ¶ms) +void debugger_commands::execute_mount(const std::vector<std::string_view> ¶ms) { for (device_image_interface &img : image_interface_enumerator(m_machine.root_device())) { if ((img.instance_name() == params[0]) || (img.brief_instance_name() == params[0])) { - if (img.load(params[1]) != image_init_result::PASS) - m_console.printf("Unable to mount file %s on %s\n", params[1], params[0]); - else + auto [err, msg] = img.load(params[1]); + if (!err) + { m_console.printf("File %s mounted on %s\n", params[1], params[0]); + } + else + { + m_console.printf( + "Unable to mount file %s on %s: %s\n", + params[1], + params[0], + !msg.empty() ? msg : err.message()); + } return; } } @@ -4229,7 +4045,7 @@ void debugger_commands::execute_mount(const std::vector<std::string> ¶ms) execute_unmount - execute the image unmount command -------------------------------------------------*/ -void debugger_commands::execute_unmount(const std::vector<std::string> ¶ms) +void debugger_commands::execute_unmount(const std::vector<std::string_view> ¶ms) { for (device_image_interface &img : image_interface_enumerator(m_machine.root_device())) { @@ -4256,9 +4072,9 @@ void debugger_commands::execute_unmount(const std::vector<std::string> ¶ms) natural keyboard input -------------------------------------------------*/ -void debugger_commands::execute_input(const std::vector<std::string> ¶ms) +void debugger_commands::execute_input(const std::vector<std::string_view> ¶ms) { - m_machine.natkeyboard().post_coded(params[0].c_str()); + m_machine.natkeyboard().post_coded(params[0]); } @@ -4267,15 +4083,15 @@ void debugger_commands::execute_input(const std::vector<std::string> ¶ms) keyboard codes -------------------------------------------------*/ -void debugger_commands::execute_dumpkbd(const std::vector<std::string> ¶ms) +void debugger_commands::execute_dumpkbd(const std::vector<std::string_view> ¶ms) { // was there a file specified? - const char *filename = !params.empty() ? params[0].c_str() : nullptr; + std::string filename = !params.empty() ? std::string(params[0]) : std::string(); FILE *file = nullptr; - if (filename != nullptr) + if (!filename.empty()) { // if so, open it - file = fopen(filename, "w"); + file = fopen(filename.c_str(), "w"); if (file == nullptr) { m_console.printf("Cannot open \"%s\"\n", filename); diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index fd0bcea673a..134f838f8a7 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -24,27 +24,6 @@ class debugger_commands public: debugger_commands(running_machine &machine, debugger_cpu &cpu, debugger_console &console); - // validates a parameter as a boolean value - bool validate_boolean_parameter(const std::string ¶m, bool &result); - - // validates a parameter as a numeric value - bool validate_number_parameter(std::string_view param, u64 &result); - - // validates a parameter as a device - bool validate_device_parameter(std::string_view param, device_t *&result); - - // validates a parameter as a CPU - bool validate_cpu_parameter(std::string_view param, device_t *&result); - - // validates a parameter as an address space identifier - bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result); - - // validates a parameter as a target address and retrieves the given address space and address - bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); - - // validates a parameter as a memory region name and retrieves the given region - bool validate_memory_region_parameter(std::string_view param, memory_region *&result); - private: struct global_entry { @@ -87,11 +66,6 @@ private: u8 disabled = 0U; }; - device_t &get_device_search_base(std::string_view ¶m); - device_t *get_cpu_by_index(u64 cpunum); - bool debug_command_parameter_expression(std::string_view param, parsed_expression &result); - bool debug_command_parameter_command(const char *param); - bool cheat_address_is_valid(address_space &space, offs_t address); u64 get_cpunum(); @@ -99,86 +73,93 @@ private: u64 global_get(global_entry *global); void global_set(global_entry *global, u64 value); - int mini_printf(char *buffer, const char *format, int params, u64 *param); + bool mini_printf(std::ostream &stream, const std::vector<std::string_view> ¶ms); template <typename T> - void execute_index_command(std::vector<std::string> const ¶ms, T &&apply, char const *unused_message); - - void execute_help(const std::vector<std::string> ¶ms); - void execute_print(const std::vector<std::string> ¶ms); - void execute_printf(const std::vector<std::string> ¶ms); - void execute_logerror(const std::vector<std::string> ¶ms); - void execute_tracelog(const std::vector<std::string> ¶ms); - void execute_tracesym(const std::vector<std::string> ¶ms); - void execute_cls(const std::vector<std::string> ¶ms); - void execute_quit(const std::vector<std::string> ¶ms); - void execute_do(const std::vector<std::string> ¶ms); - void execute_step(const std::vector<std::string> ¶ms); - void execute_over(const std::vector<std::string> ¶ms); - void execute_out(const std::vector<std::string> ¶ms); - void execute_go(const std::vector<std::string> ¶ms); - void execute_go_vblank(const std::vector<std::string> ¶ms); - void execute_go_interrupt(const std::vector<std::string> ¶ms); - void execute_go_exception(const std::vector<std::string> ¶ms); - void execute_go_time(const std::vector<std::string> ¶ms); - void execute_go_privilege(const std::vector<std::string> ¶ms); - void execute_focus(const std::vector<std::string> ¶ms); - void execute_ignore(const std::vector<std::string> ¶ms); - void execute_observe(const std::vector<std::string> ¶ms); - void execute_suspend(const std::vector<std::string> ¶ms); - void execute_resume(const std::vector<std::string> ¶ms); - void execute_next(const std::vector<std::string> ¶ms); - void execute_cpulist(const std::vector<std::string> ¶ms); - void execute_comment_add(const std::vector<std::string> ¶ms); - void execute_comment_del(const std::vector<std::string> ¶ms); - void execute_comment_save(const std::vector<std::string> ¶ms); - void execute_comment_list(const std::vector<std::string> ¶ms); - void execute_comment_commit(const std::vector<std::string> ¶ms); - void execute_bpset(const std::vector<std::string> ¶ms); - void execute_bpclear(const std::vector<std::string> ¶ms); - void execute_bpdisenable(bool enable, const std::vector<std::string> ¶ms); - void execute_bplist(const std::vector<std::string> ¶ms); - void execute_wpset(int spacenum, const std::vector<std::string> ¶ms); - void execute_wpclear(const std::vector<std::string> ¶ms); - void execute_wpdisenable(bool enable, const std::vector<std::string> ¶ms); - void execute_wplist(const std::vector<std::string> ¶ms); - void execute_rpset(const std::vector<std::string> ¶ms); - void execute_rpclear(const std::vector<std::string> ¶ms); - void execute_rpdisenable(bool enable, const std::vector<std::string> ¶ms); - void execute_rplist(const std::vector<std::string> ¶ms); - void execute_statesave(const std::vector<std::string> ¶ms); - void execute_stateload(const std::vector<std::string> ¶ms); - void execute_rewind(const std::vector<std::string> ¶ms); - void execute_save(int spacenum, const std::vector<std::string> ¶ms); - void execute_saveregion(const std::vector<std::string> ¶ms); - void execute_load(int spacenum, const std::vector<std::string> ¶ms); - void execute_loadregion(const std::vector<std::string> ¶ms); - void execute_dump(int spacenum, const std::vector<std::string> ¶ms); - void execute_strdump(int spacenum, const std::vector<std::string> ¶ms); - void execute_cheatrange(bool init, const std::vector<std::string> ¶ms); - void execute_cheatnext(bool initial, const std::vector<std::string> ¶ms); - void execute_cheatlist(const std::vector<std::string> ¶ms); - void execute_cheatundo(const std::vector<std::string> ¶ms); - void execute_dasm(const std::vector<std::string> ¶ms); - void execute_find(int spacenum, const std::vector<std::string> ¶ms); - void execute_fill(int spacenum, const std::vector<std::string> ¶ms); - void execute_trace(const std::vector<std::string> ¶ms, bool trace_over); - void execute_traceflush(const std::vector<std::string> ¶ms); - void execute_history(const std::vector<std::string> ¶ms); - void execute_trackpc(const std::vector<std::string> ¶ms); - void execute_trackmem(const std::vector<std::string> ¶ms); - void execute_pcatmem(int spacenum, const std::vector<std::string> ¶ms); - void execute_snap(const std::vector<std::string> ¶ms); - void execute_source(const std::vector<std::string> ¶ms); - void execute_map(int spacenum, const std::vector<std::string> ¶ms); - void execute_memdump(const std::vector<std::string> ¶ms); - void execute_symlist(const std::vector<std::string> ¶ms); - void execute_softreset(const std::vector<std::string> ¶ms); - void execute_hardreset(const std::vector<std::string> ¶ms); - void execute_images(const std::vector<std::string> ¶ms); - void execute_mount(const std::vector<std::string> ¶ms); - void execute_unmount(const std::vector<std::string> ¶ms); - void execute_input(const std::vector<std::string> ¶ms); - void execute_dumpkbd(const std::vector<std::string> ¶ms); + void execute_index_command(std::vector<std::string_view> const ¶ms, T &&apply, char const *unused_message); + + void execute_help(const std::vector<std::string_view> ¶ms); + void execute_print(const std::vector<std::string_view> ¶ms); + void execute_printf(const std::vector<std::string_view> ¶ms); + void execute_logerror(const std::vector<std::string_view> ¶ms); + void execute_tracelog(const std::vector<std::string_view> ¶ms); + void execute_tracesym(const std::vector<std::string_view> ¶ms); + void execute_cls(const std::vector<std::string_view> ¶ms); + void execute_quit(const std::vector<std::string_view> ¶ms); + void execute_do(const std::vector<std::string_view> ¶ms); + void execute_step(const std::vector<std::string_view> ¶ms); + void execute_over(const std::vector<std::string_view> ¶ms); + void execute_out(const std::vector<std::string_view> ¶ms); + void execute_go(const std::vector<std::string_view> ¶ms); + void execute_go_vblank(const std::vector<std::string_view> ¶ms); + void execute_go_interrupt(const std::vector<std::string_view> ¶ms); + void execute_go_exception(const std::vector<std::string_view> ¶ms); + void execute_go_time(const std::vector<std::string_view> ¶ms); + void execute_go_privilege(const std::vector<std::string_view> ¶ms); + void execute_go_branch(bool sense, const std::vector<std::string_view> ¶ms); + void execute_go_next_instruction(const std::vector<std::string_view> ¶ms); + void execute_focus(const std::vector<std::string_view> ¶ms); + void execute_ignore(const std::vector<std::string_view> ¶ms); + void execute_observe(const std::vector<std::string_view> ¶ms); + void execute_suspend(const std::vector<std::string_view> ¶ms); + void execute_resume(const std::vector<std::string_view> ¶ms); + void execute_next(const std::vector<std::string_view> ¶ms); + void execute_cpulist(const std::vector<std::string_view> ¶ms); + void execute_time(const std::vector<std::string_view> ¶ms); + void execute_comment_add(const std::vector<std::string_view> ¶ms); + void execute_comment_del(const std::vector<std::string_view> ¶ms); + void execute_comment_save(const std::vector<std::string_view> ¶ms); + void execute_comment_list(const std::vector<std::string_view> ¶ms); + void execute_comment_commit(const std::vector<std::string_view> ¶ms); + void execute_bpset(const std::vector<std::string_view> ¶ms); + void execute_bpclear(const std::vector<std::string_view> ¶ms); + void execute_bpdisenable(bool enable, const std::vector<std::string_view> ¶ms); + void execute_bplist(const std::vector<std::string_view> ¶ms); + void execute_wpset(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_wpclear(const std::vector<std::string_view> ¶ms); + void execute_wpdisenable(bool enable, const std::vector<std::string_view> ¶ms); + void execute_wplist(const std::vector<std::string_view> ¶ms); + void execute_rpset(const std::vector<std::string_view> ¶ms); + void execute_rpclear(const std::vector<std::string_view> ¶ms); + void execute_rpdisenable(bool enable, const std::vector<std::string_view> ¶ms); + void execute_rplist(const std::vector<std::string_view> ¶ms); + void execute_epset(const std::vector<std::string_view> ¶ms); + void execute_epclear(const std::vector<std::string_view> ¶ms); + void execute_epdisenable(bool enable, const std::vector<std::string_view> ¶ms); + void execute_eplist(const std::vector<std::string_view> ¶ms); + void execute_statesave(const std::vector<std::string_view> ¶ms); + void execute_stateload(const std::vector<std::string_view> ¶ms); + void execute_rewind(const std::vector<std::string_view> ¶ms); + void execute_save(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_saveregion(const std::vector<std::string_view> ¶ms); + void execute_load(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_loadregion(const std::vector<std::string_view> ¶ms); + void execute_dump(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_strdump(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_cheatrange(bool init, const std::vector<std::string_view> ¶ms); + void execute_cheatnext(bool initial, const std::vector<std::string_view> ¶ms); + void execute_cheatlist(const std::vector<std::string_view> ¶ms); + void execute_cheatundo(const std::vector<std::string_view> ¶ms); + void execute_dasm(const std::vector<std::string_view> ¶ms); + void execute_find(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_fill(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_trace(const std::vector<std::string_view> ¶ms, bool trace_over); + void execute_traceflush(const std::vector<std::string_view> ¶ms); + void execute_history(const std::vector<std::string_view> ¶ms); + void execute_trackpc(const std::vector<std::string_view> ¶ms); + void execute_trackmem(const std::vector<std::string_view> ¶ms); + void execute_pcatmem(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_snap(const std::vector<std::string_view> ¶ms); + void execute_source(const std::vector<std::string_view> ¶ms); + void execute_map(int spacenum, const std::vector<std::string_view> ¶ms); + void execute_memdump(const std::vector<std::string_view> ¶ms); + void execute_symlist(const std::vector<std::string_view> ¶ms); + void execute_softreset(const std::vector<std::string_view> ¶ms); + void execute_hardreset(const std::vector<std::string_view> ¶ms); + void execute_images(const std::vector<std::string_view> ¶ms); + void execute_mount(const std::vector<std::string_view> ¶ms); + void execute_unmount(const std::vector<std::string_view> ¶ms); + void execute_input(const std::vector<std::string_view> ¶ms); + void execute_dumpkbd(const std::vector<std::string_view> ¶ms); running_machine& m_machine; debugger_console& m_console; diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 32a4888c285..ec5bc154751 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb /********************************************************************* debugcon.cpp @@ -16,6 +16,8 @@ #include "textbuf.h" #include "debugger.h" +#include "fileio.h" +#include "main.h" #include "corestr.h" @@ -86,10 +88,14 @@ debugger_console::debugger_console(running_machine &machine) } } +debugger_console::~debugger_console() +{ +} -/*------------------------------------------------- - exit - frees the console system --------------------------------------------------*/ + +//------------------------------------------------- +// exit - frees the console system +//------------------------------------------------- void debugger_console::exit() { @@ -114,41 +120,39 @@ void debugger_console::exit() inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const debug_command &b) const { - return core_stricmp(a.command.c_str(), b.command.c_str()) < 0; + return a.command < b.command; } inline bool debugger_console::debug_command::compare::operator()(const char *a, const debug_command &b) const { - return core_stricmp(a, b.command.c_str()) < 0; + return strcmp(a, b.command.c_str()) < 0; } inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const char *b) const { - return core_stricmp(a.command.c_str(), b) < 0; + return strcmp(a.command.c_str(), b) < 0; } -debugger_console::debug_command::debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler) +debugger_console::debug_command::debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string_view> &)> &&_handler) : command(_command), params(nullptr), help(nullptr), handler(std::move(_handler)), flags(_flags), minparams(_minparams), maxparams(_maxparams) { } -/*------------------------------------------------------------ - execute_help_custom - execute the helpcustom command -------------------------------------------------------------*/ +//------------------------------------------------------------ +// execute_help_custom - execute the helpcustom command +//------------------------------------------------------------ -void debugger_console::execute_help_custom(const std::vector<std::string> ¶ms) +void debugger_console::execute_help_custom(const std::vector<std::string_view> ¶ms) { - char buf[64]; for (const debug_command &cmd : m_commandlist) { if (cmd.flags & CMDFLAG_CUSTOM_HELP) { - snprintf(buf, 63, "%s help", cmd.command.c_str()); - buf[63] = 0; - char *temp_params[1] = { buf }; - internal_execute_command(true, 1, &temp_params[0]); + std::string buf = cmd.command + " help"; + std::vector<std::string_view> temp_params = { buf }; + internal_execute_command(true, temp_params); } } } @@ -157,9 +161,9 @@ void debugger_console::execute_help_custom(const std::vector<std::string> ¶m execute_condump - execute the condump command ------------------------------------------------------------*/ -void debugger_console::execute_condump(const std::vector<std::string>& params) +void debugger_console::execute_condump(const std::vector<std::string_view>& params) { - std::string filename = params[0]; + std::string filename(params[0]); const char* mode; /* replace macros */ @@ -195,166 +199,149 @@ void debugger_console::execute_condump(const std::vector<std::string>& params) // symbol table //------------------------------------------------- -symbol_table &debugger_console::visible_symtable() +symbol_table &debugger_console::visible_symtable() const { return m_visiblecpu->debug()->symtable(); } -/*------------------------------------------------- - trim_parameter - executes a - command --------------------------------------------------*/ +//------------------------------------------------- +// trim_parameter - trim spaces and quotes around +// a command parameter +//------------------------------------------------- -void debugger_console::trim_parameter(char **paramptr, bool keep_quotes) +std::string_view debugger_console::trim_parameter(std::string_view param, bool keep_quotes) { - char *param = *paramptr; - size_t len = strlen(param); + std::string_view::size_type len = param.length(); bool repeat; - /* loop until all adornments are gone */ + // loop until all adornments are gone do { repeat = false; - /* check for begin/end quotes */ + // check for begin/end quotes if (len >= 2 && param[0] == '"' && param[len - 1] == '"') { if (!keep_quotes) { - param[len - 1] = 0; - param++; + param = param.substr(1, len - 2); len -= 2; } } - /* check for start/end braces */ + // check for start/end braces else if (len >= 2 && param[0] == '{' && param[len - 1] == '}') { - param[len - 1] = 0; - param++; + param = param.substr(1, len - 2); len -= 2; repeat = true; } - /* check for leading spaces */ + // check for leading spaces else if (len >= 1 && param[0] == ' ') { - param++; + param.remove_prefix(1); len--; repeat = true; } - /* check for trailing spaces */ + // check for trailing spaces else if (len >= 1 && param[len - 1] == ' ') { - param[len - 1] = 0; + param.remove_suffix(1); len--; repeat = true; } } while (repeat); - *paramptr = param; + return param; } -/*------------------------------------------------- - internal_execute_command - executes a - command --------------------------------------------------*/ +//------------------------------------------------- +// internal_execute_command - executes a +// command +//------------------------------------------------- -CMDERR debugger_console::internal_execute_command(bool execute, int params, char **param) +CMDERR debugger_console::internal_execute_command(bool execute, std::vector<std::string_view> ¶ms) { // no params is an error - if (params == 0) + if (params.empty()) return CMDERR::none(); // the first parameter has the command and the real first parameter; separate them - char *p, *command; - for (p = param[0]; *p && isspace(u8(*p)); p++) { } - for (command = p; *p && !isspace(u8(*p)); p++) { } - if (*p != 0) - { - *p++ = 0; - for ( ; *p && isspace(u8(*p)); p++) { } - if (*p != 0) - param[0] = p; - else - params = 0; - } + std::string_view command_param = params[0]; + std::string_view::size_type pos = 0; + while (pos < command_param.length() && !isspace(u8(command_param[pos]))) + pos++; + const std::string command(strmakelower(command_param.substr(0, pos))); + while (pos < command_param.length() && isspace(u8(command_param[pos]))) + pos++; + if (pos == command_param.length() && params.size() == 1) + params.clear(); else - { - params = 0; - param[0] = nullptr; - } + params[0].remove_prefix(pos); // search the command list - size_t const len = strlen(command); - auto const found = m_commandlist.lower_bound(command); + auto const found = m_commandlist.lower_bound(command.c_str()); // error if not found - if ((m_commandlist.end() == found) || core_strnicmp(command, found->command.c_str(), len)) + if (m_commandlist.end() == found || std::string_view(command) != std::string_view(found->command).substr(0, command.length())) return CMDERR::unknown_command(0); - if (found->command.length() > len) + if (found->command.length() > command.length()) { auto const next = std::next(found); - if ((m_commandlist.end() != next) && !core_strnicmp(command, next->command.c_str(), len)) + if (m_commandlist.end() != next && std::string_view(command) == std::string_view(next->command).substr(0, command.length())) return CMDERR::ambiguous_command(0); } - // NUL-terminate and trim space around all the parameters - for (int i = 1; i < params; i++) - *param[i]++ = 0; - // now go back and trim quotes and braces and any spaces they reveal - for (int i = 0; i < params; i++) - trim_parameter(¶m[i], found->flags & CMDFLAG_KEEP_QUOTES); + for (std::string_view ¶m : params) + param = trim_parameter(param, found->flags & CMDFLAG_KEEP_QUOTES); // see if we have the right number of parameters - if (params < found->minparams) + if (params.size() < found->minparams) return CMDERR::not_enough_params(0); - if (params > found->maxparams) + if (params.size() > found->maxparams) return CMDERR::too_many_params(0); // execute the handler if (execute) - { - std::vector<std::string> params_vec(param, param + params); - found->handler(params_vec); - } + found->handler(params); return CMDERR::none(); } -/*------------------------------------------------- - internal_parse_command - parses a command - and either executes or just validates it --------------------------------------------------*/ +//------------------------------------------------- +// internal_parse_command - parses a command +// and either executes or just validates it +//------------------------------------------------- -CMDERR debugger_console::internal_parse_command(const std::string &original_command, bool execute) +CMDERR debugger_console::internal_parse_command(std::string_view command, bool execute) { - char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH]; - char *params[MAX_COMMAND_PARAMS] = { nullptr }; - char *command_start; - char *p, c = 0; - - /* make a copy of the command */ - strcpy(command, original_command.c_str()); + std::string_view::size_type pos = 0; + std::string_view::size_type len = command.length(); - /* loop over all semicolon-separated stuff */ - for (p = command; *p != 0; ) + while (pos < len) { - int paramcount = 0, parendex = 0; + std::string parens; + std::vector<std::string_view> params; bool foundend = false, instring = false, isexpr = false; - /* find a semicolon or the end */ - for (params[paramcount++] = p; !foundend; p++) + // skip leading spaces + while (pos < len && isspace(u8(command[pos]))) + pos++; + std::string_view::size_type startpos = pos; + + // find a semicolon or the end + for (params.push_back(command.substr(pos)); !foundend && pos < len; pos++) { - c = *p; + char c = command[pos]; if (instring) { - if (c == '"' && p[-1] != '\\') + if (c == '"' && command[pos - 1] != '\\') instring = false; } else @@ -364,47 +351,44 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm case '"': instring = true; break; case '(': case '[': - case '{': parens[parendex++] = c; break; - case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break; - case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break; - case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break; - case ',': if (parendex == 0) params[paramcount++] = p; break; - case ';': if (parendex == 0) foundend = true; break; - case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break; - case '+': if (parendex == 0 && paramcount == 1 && p[1] == '+') isexpr = true; *p = c; break; - case '=': if (parendex == 0 && paramcount == 1) isexpr = true; *p = c; break; - case 0: foundend = true; break; - default: *p = c; break; + case '{': parens.push_back(c); break; + case ')': if (parens.empty() || parens.back() != '(') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case ']': if (parens.empty() || parens.back() != '[') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case '}': if (parens.empty() || parens.back() != '{') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case ',': if (parens.empty()) { params.back().remove_suffix(len - pos); params.push_back(command.substr(pos + 1)); } break; + case ';': if (parens.empty()) { params.back().remove_suffix(len - pos); foundend = true; } break; + case '-': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '-') isexpr = true; break; + case '+': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '+') isexpr = true; break; + case '=': if (parens.empty() && params.size() == 1) isexpr = true; break; + default: break; } } } - /* check for unbalanced parentheses or quotes */ + // check for unbalanced parentheses or quotes if (instring) - return CMDERR::unbalanced_quotes(p - command); - if (parendex != 0) - return CMDERR::unbalanced_parens(p - command); - - /* NULL-terminate if we ended in a semicolon */ - p--; - if (c == ';') *p++ = 0; + return CMDERR::unbalanced_quotes(pos); + if (!parens.empty()) + return CMDERR::unbalanced_parens(pos); - /* process the command */ - command_start = params[0]; + // process the command + std::string_view command_or_expr = params[0]; - /* allow for "do" commands */ - if (tolower(u8(command_start[0])) == 'd' && tolower(u8(command_start[1])) == 'o' && isspace(u8(command_start[2]))) + // allow for "do" commands + if (command_or_expr.length() > 3 && tolower(u8(command_or_expr[0])) == 'd' && tolower(u8(command_or_expr[1])) == 'o' && isspace(u8(command_or_expr[2]))) { isexpr = true; - command_start += 3; + command_or_expr.remove_prefix(3); } - /* if it smells like an assignment expression, treat it as such */ - if (isexpr && paramcount == 1) + // if it smells like an assignment expression, treat it as such + if (isexpr && params.size() == 1) { try { - parsed_expression(visible_symtable(), command_start).execute(); + parsed_expression expr(visible_symtable(), command_or_expr); + if (execute) + expr.execute(); } catch (expression_error &err) { @@ -413,29 +397,29 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm } else { - const CMDERR result = internal_execute_command(execute, paramcount, ¶ms[0]); + const CMDERR result = internal_execute_command(execute, params); if (result.error_class() != CMDERR::NONE) - return CMDERR(result.error_class(), command_start - command); + return CMDERR(result.error_class(), startpos); } } return CMDERR::none(); } -/*------------------------------------------------- - execute_command - execute a command string --------------------------------------------------*/ +//------------------------------------------------- +// execute_command - execute a command string +//------------------------------------------------- -CMDERR debugger_console::execute_command(const std::string &command, bool echo) +CMDERR debugger_console::execute_command(std::string_view command, bool echo) { - /* echo if requested */ + // echo if requested if (echo) printf(">%s\n", command); - /* parse and execute */ + // parse and execute const CMDERR result = internal_parse_command(command, true); - /* display errors */ + // display errors if (result.error_class() != CMDERR::NONE) { if (!echo) @@ -444,7 +428,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo) printf("%s\n", cmderr_to_string(result)); } - /* update all views */ + // update all views if (echo) { m_machine.debug_view().update_all(); @@ -454,11 +438,11 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo) } -/*------------------------------------------------- - validate_command - validate a command string --------------------------------------------------*/ +//------------------------------------------------- +// validate_command - validate a command string +//------------------------------------------------- -CMDERR debugger_console::validate_command(const char *command) +CMDERR debugger_console::validate_command(std::string_view command) { return internal_parse_command(command, false); } @@ -468,7 +452,7 @@ CMDERR debugger_console::validate_command(const char *command) register_command - register a command handler -------------------------------------------------*/ -void debugger_console::register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler) +void debugger_console::register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string_view> &)> &&handler) { if (m_machine.phase() != machine_phase::INIT) throw emu_fatalerror("Can only call debugger_console::register_command() at init time!"); @@ -576,6 +560,494 @@ std::string debugger_console::cmderr_to_string(CMDERR error) } +//************************************************************************** +// PARAMETER VALIDATION HELPERS +//************************************************************************** + +namespace { + +template <typename T> +inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim) +{ + unsigned parens = 0; + for (std::string_view::size_type i = 0; str.length() > i; ++i) + { + if (str[i] == '(') + { + ++parens; + } + else if (parens) + { + if (str[i] == ')') + --parens; + } + else if (is_delim(str[i])) + { + return i; + } + } + return std::string_view::npos; +} + +} // anonymous namespace + + +/// \brief Validate parameter as a Boolean value +/// +/// Validates a parameter as a Boolean value. Fixed strings and +/// expressions evaluating to numeric values are recognised. The result +/// is unchanged for an empty string. +/// \param [in] param The parameter string. +/// \param [in,out] result The default value on entry, and the value of +/// the parameter interpreted as a Boolean on success. Unchanged if +/// the parameter is an empty string. +/// \return true if the parameter is a valid Boolean value or an empty +/// string, or false otherwise. +bool debugger_console::validate_boolean_parameter(std::string_view param, bool &result) +{ + // nullptr parameter does nothing and returns no error + if (param.empty()) + return true; + + // evaluate the expression; success if no error + using namespace std::literals; + bool const is_true = util::streqlower(param, "true"sv); + bool const is_false = util::streqlower(param, "false"sv); + + if (is_true || is_false) + { + result = is_true; + return true; + } + + // try to evaluate as a number + u64 val; + if (!validate_number_parameter(param, val)) + return false; + + result = val != 0; + return true; +} + + +/// \brief Validate parameter as a numeric value +/// +/// Parses the parameter as an expression and evaluates it as a number. +/// \param [in] param The parameter string. +/// \param [out] result The numeric value of the expression on success. +/// Unchanged on failure. +/// \return true if the parameter is a valid expression that evaluates +/// to a numeric value, or false otherwise. +bool debugger_console::validate_number_parameter(std::string_view param, u64 &result) +{ + // evaluate the expression; success if no error + try + { + result = parsed_expression(visible_symtable(), param).execute(); + return true; + } + catch (expression_error const &error) + { + // print an error pointing to the character that caused it + printf("Error in expression: %s\n", param); + printf(" %*s^", error.offset(), ""); + printf("%s\n", error.code_string()); + return false; + } +} + + +/// \brief Validate parameter as a device +/// +/// Validates a parameter as a device identifier and retrieves the +/// device on success. A string corresponding to the tag of a device +/// refers to that device; an empty string refers to the current CPU +/// with debugger focus; any other string is parsed as an expression +/// and treated as an index of a device implementing +/// #device_execute_interface and #device_state_interface, and exposing +/// a generic PC base value. +/// \param [in] param The parameter string. +/// \param [out] result A pointer to the device on success, or unchanged +/// on failure. +/// \return true if the parameter refers to a device in the current +/// system, or false otherwise. +bool debugger_console::validate_device_parameter(std::string_view param, device_t *&result) +{ + // if no parameter, use the visible CPU + if (param.empty()) + { + device_t *const current = m_visiblecpu; + if (current) + { + result = current; + return true; + } + else + { + printf("No valid CPU is currently selected\n"); + return false; + } + } + + // next look for a tag match + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + device_t *device = base.subdevice(strmakelower(relative)); + if (device) + { + result = device; + return true; + } + + // then evaluate as an expression; on an error assume it was a tag + u64 cpunum; + try + { + cpunum = parsed_expression(visible_symtable(), param).execute(); + } + catch (expression_error &) + { + printf("Unable to find device '%s'\n", param); + return false; + } + + // attempt to find by numerical index + device = get_cpu_by_index(cpunum); + if (device) + { + result = device; + return true; + } + else + { + // if out of range, complain + printf("Invalid CPU index %u\n", cpunum); + return false; + } +} + + +/// \brief Validate a parameter as a CPU +/// +/// Validates a parameter as a CPU identifier. Uses the same rules as +/// #validate_device_parameter to identify devices, but additionally +/// checks that the device is a "CPU" for the debugger's purposes. +/// \param [in] The parameter string. +/// \param [out] result The device on success, or unchanged on failure. +/// \return true if the parameter refers to a CPU-like device in the +/// current system, or false otherwise. +bool debugger_console::validate_cpu_parameter(std::string_view param, device_t *&result) +{ + // first do the standard device thing + device_t *device; + if (!validate_device_parameter(param, device)) + return false; + + // check that it's a "CPU" for the debugger's purposes + device_execute_interface const *execute; + if (device->interface(execute)) + { + result = device; + return true; + } + + printf("Device %s is not a CPU\n", device->name()); + return false; +} + + +/// \brief Validate a parameter as an address space identifier +/// +/// Validates a parameter as an address space identifier. Uses the same +/// rules as #validate_device_parameter to identify devices. If the +/// default address space number is negative, the first address space +/// exposed by the device will be used as the default. +/// \param [in] The parameter string. +/// \param [in] spacenum The default address space index. If negative, +/// the first address space exposed by the device (i.e. the address +/// space with the lowest index) will be used as the default. +/// \param [out] result The addresfs space on success, or unchanged on +/// failure. +/// \return true if the parameter refers to an address space in the +/// current system, or false otherwise. +bool debugger_console::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result) +{ + device_t *device; + std::string spacename; + if (param.empty()) + { + // if no parameter, use the visible CPU + device = m_visiblecpu; + if (!device) + { + printf("No valid CPU is currently selected\n"); + return false; + } + } + else + { + // look for a tag match on the whole parameter value + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + device = base.subdevice(strmakelower(relative)); + + // if that failed, treat the last component as an address space + if (!device) + { + auto const delimiter = relative.find_last_of(":^"); + bool const found = std::string_view::npos != delimiter; + if (!found || (':' == relative[delimiter])) + { + spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0)); + relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter); + if (!relative.empty()) + device = base.subdevice(strmakelower(relative)); + else if (m_visiblecpu) + device = m_visiblecpu; + else + device = &m_machine.root_device(); + } + } + } + + // if still no device found, evaluate as an expression + if (!device) + { + u64 cpunum; + try + { + cpunum = parsed_expression(visible_symtable(), param).execute(); + } + catch (expression_error const &) + { + // parsing failed - assume it was a tag + printf("Unable to find device '%s'\n", param); + return false; + } + + // attempt to find by numerical index + device = get_cpu_by_index(cpunum); + if (!device) + { + // if out of range, complain + printf("Invalid CPU index %u\n", cpunum); + return false; + } + } + + // ensure the device implements the memory interface + device_memory_interface *memory; + if (!device->interface(memory)) + { + printf("No memory interface found for device %s\n", device->name()); + return false; + } + + // fall back to supplied default space if appropriate + if (spacename.empty() && (0 <= spacenum)) + { + if (memory->has_space(spacenum)) + { + result = &memory->space(spacenum); + return true; + } + else + { + printf("No matching memory space found for device '%s'\n", device->tag()); + return false; + } + } + + // otherwise find the specified space or fall back to the first populated space + for (int i = 0; memory->max_space_count() > i; ++i) + { + if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename))) + { + result = &memory->space(i); + return true; + } + } + + // report appropriate error message + if (spacename.empty()) + printf("No memory spaces found for device '%s'\n", device->tag()); + else + printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag()); + return false; +} + + +/// \brief Validate a parameter as a target address +/// +/// Validates a parameter as an numeric expression to use as an address +/// optionally followed by a colon and a device identifier. If the +/// device identifier is not presnt, the current CPU with debugger focus +/// is assumed. See #validate_device_parameter for information on how +/// device parametersare interpreted. +/// \param [in] The parameter string. +/// \param [in] spacenum The default address space index. If negative, +/// the first address space exposed by the device (i.e. the address +/// space with the lowest index) will be used as the default. +/// \param [out] space The address space on success, or unchanged on +/// failure. +/// \param [out] addr The address on success, or unchanged on failure. +/// \return true if the address is a valid expression evaluating to a +/// number and the address space is found, or false otherwise. +bool debugger_console::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr) +{ + // check for the device delimiter + std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; }); + std::string_view device; + if (devdelim != std::string::npos) + device = param.substr(devdelim + 1); + + // parse the address first + u64 addrval; + if (!validate_number_parameter(param.substr(0, devdelim), addrval)) + return false; + + // find the address space + if (!validate_device_space_parameter(device, spacenum, space)) + return false; + + // set the address now that we have the space + addr = addrval; + return true; +} + + +/// \brief Validate a parameter as a memory region +/// +/// Validates a parameter as a memory region tag and retrieves the +/// specified memory region. +/// \param [in] The parameter string. +/// \param [out] result The memory region on success, or unchanged on +/// failure. +/// \return true if the parameter refers to a memory region in the +/// current system, or false otherwise. +bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result) +{ + auto const ®ions = m_machine.memory().regions(); + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + auto const iter = regions.find(base.subtag(strmakelower(relative))); + if (regions.end() != iter) + { + result = iter->second.get(); + return true; + } + else + { + printf("No matching memory region found for '%s'\n", param); + return false; + } +} + + +/// \brief Get search base for device or address space parameter +/// +/// Handles prefix prefixes used to indicate that a device tag should be +/// interpreted relative to the selected CPU. Removes the recognised +/// prefixes from the parameter value. +/// \param [in,out] param The parameter string. Recognised prefixes +/// affecting the search base are removed, leaving a tag relative to +/// the base device. +/// \return A reference to the base device that the tag should be +/// interpreted relative to. +device_t &debugger_console::get_device_search_base(std::string_view ¶m) const +{ + if (!param.empty()) + { + // handle ".:" or ".^" prefix for tag relative to current CPU if any + if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1]))) + { + param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1); + device_t *const current = m_visiblecpu; + return current ? *current : m_machine.root_device(); + } + + // a sibling path makes most sense relative to current CPU + if ('^' == param[0]) + { + device_t *const current = m_visiblecpu; + return current ? *current : m_machine.root_device(); + } + } + + // default to root device + return m_machine.root_device(); +} + + +/// \brief Get CPU by index +/// +/// Looks up a CPU by the number the debugger assigns it based on its +/// position in the device tree relative to other CPUs. +/// \param [in] cpunum Zero-based index of the CPU to find. +/// \return A pointer to the CPU if found, or \c nullptr if no CPU has +/// the specified index. +device_t *debugger_console::get_cpu_by_index(u64 cpunum) const +{ + unsigned index = 0; + for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device())) + { + // real CPUs should have pcbase + device_state_interface const *state; + if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE)) + { + if (index++ == cpunum) + { + return &exec.device(); + } + } + } + return nullptr; +} + + +//------------------------------------------------- +// validate_expression_parameter - validates +// an expression parameter +//-----------------------------------------------*/ + +bool debugger_console::validate_expression_parameter(std::string_view param, parsed_expression &result) +{ + try + { + // parse the expression; success if no error + result.parse(param); + return true; + } + catch (expression_error const &err) + { + // output an error + printf("Error in expression: %s\n", param); + printf(" %*s^", err.offset(), ""); + printf("%s\n", err.code_string()); + return false; + } +} + + +//------------------------------------------------- +// validate_command_parameter - validates a +// command parameter +//------------------------------------------------- + +bool debugger_console::validate_command_parameter(std::string_view param) +{ + // validate the comment; success if no error + CMDERR err = validate_command(param); + if (err.error_class() == CMDERR::NONE) + return true; + + // output an error + printf("Error in command: %s\n", param); + printf(" %*s^", err.error_offset(), ""); + printf("%s\n", cmderr_to_string(err)); + return false; +} + /*************************************************************************** @@ -614,7 +1086,7 @@ void debugger_console::print_core_wrap(std::string_view text, int wrapcol) // the format to the debug console //------------------------------------------------- -void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &args) +void debugger_console::vprintf(util::format_argument_pack<char> const &args) { print_core(util::string_format(args)); @@ -622,7 +1094,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &a m_machine.debug_view().update_all(DVT_CONSOLE); } -void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args) +void debugger_console::vprintf(util::format_argument_pack<char> &&args) { print_core(util::string_format(std::move(args))); @@ -636,7 +1108,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args) // using the format to the debug console //------------------------------------------------- -void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args) +void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args) { print_core_wrap(util::string_format(args), wrapcol); @@ -644,7 +1116,7 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std: m_machine.debug_view().update_all(DVT_CONSOLE); } -void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args) +void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args) { print_core_wrap(util::string_format(std::move(args)), wrapcol); diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 5271b0e5ae5..37b2e235348 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -23,18 +23,13 @@ CONSTANTS ***************************************************************************/ -#define MAX_COMMAND_LENGTH 4096 -#define MAX_COMMAND_PARAMS 128 +constexpr int MAX_COMMAND_PARAMS = 128; // flags for command parsing constexpr u32 CMDFLAG_NONE = 0x0000; constexpr u32 CMDFLAG_KEEP_QUOTES = 0x0001; constexpr u32 CMDFLAG_CUSTOM_HELP = 0x0002; -// parameter separator macros -#define CMDPARAM_SEPARATOR "\0" -#define CMDPARAM_TERMINATOR "\0\0" - /*************************************************************************** @@ -79,19 +74,20 @@ class debugger_console { public: debugger_console(running_machine &machine); + ~debugger_console(); // command handling - CMDERR execute_command(const std::string &command, bool echo); - CMDERR validate_command(const char *command); - void register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler); + CMDERR execute_command(std::string_view command, bool echo); + CMDERR validate_command(std::string_view command); + void register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string_view> &)> &&handler); void source_script(const char *file); void process_source_file(); // console management - void vprintf(util::format_argument_pack<std::ostream> const &args); - void vprintf(util::format_argument_pack<std::ostream> &&args); - void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args); - void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args); + void vprintf(util::format_argument_pack<char> const &args); + void vprintf(util::format_argument_pack<char> &&args); + void vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args); + void vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args); text_buffer &get_console_textbuf() const { return *m_console_textbuf; } // errorlog management @@ -110,28 +106,58 @@ public: vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)); } - device_t *get_visible_cpu() { return m_visiblecpu; } + device_t *get_visible_cpu() const { return m_visiblecpu; } void set_visible_cpu(device_t *visiblecpu) { m_visiblecpu = visiblecpu; } - symbol_table &visible_symtable(); + symbol_table &visible_symtable() const; static std::string cmderr_to_string(CMDERR error); + // validates a parameter as a boolean value + bool validate_boolean_parameter(std::string_view param, bool &result); + + // validates a parameter as a numeric value + bool validate_number_parameter(std::string_view param, u64 &result); + + // validates a parameter as a device + bool validate_device_parameter(std::string_view param, device_t *&result); + + // validates a parameter as a CPU + bool validate_cpu_parameter(std::string_view param, device_t *&result); + + // validates a parameter as an address space identifier + bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result); + + // validates a parameter as a target address and retrieves the given address space and address + bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); + + // validates a parameter as a memory region name and retrieves the given region + bool validate_memory_region_parameter(std::string_view param, memory_region *&result); + + // validates a parameter as a debugger expression + bool validate_expression_parameter(std::string_view param, parsed_expression &result); + + // validates a parameter as a debugger command + bool validate_command_parameter(std::string_view param); + private: void exit(); - void execute_help_custom(const std::vector<std::string> ¶ms); - void execute_condump(const std::vector<std::string>& params); + void execute_help_custom(const std::vector<std::string_view> ¶ms); + void execute_condump(const std::vector<std::string_view>& params); - void trim_parameter(char **paramptr, bool keep_quotes); - CMDERR internal_execute_command(bool execute, int params, char **param); - CMDERR internal_parse_command(const std::string &original_command, bool execute); + [[nodiscard]] static std::string_view trim_parameter(std::string_view param, bool keep_quotes); + CMDERR internal_execute_command(bool execute, std::vector<std::string_view> ¶ms); + CMDERR internal_parse_command(std::string_view command, bool execute); void print_core(std::string_view text); // core text output void print_core_wrap(std::string_view text, int wrapcol); // core text output + device_t &get_device_search_base(std::string_view ¶m) const; + device_t *get_cpu_by_index(u64 cpunum) const; + struct debug_command { - debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler); + debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string_view> &)> &&_handler); struct compare { @@ -144,7 +170,7 @@ private: std::string command; const char * params; const char * help; - std::function<void (const std::vector<std::string> &)> handler; + std::function<void (const std::vector<std::string_view> &)> handler; u32 flags; int minparams; int maxparams; diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index 403d0b104ee..fd0093bd283 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -19,11 +19,12 @@ #include "debugger.h" #include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "screen.h" #include "uiinput.h" #include "corestr.h" -#include "coreutil.h" #include "osdepend.h" #include "xmlfile.h" @@ -46,6 +47,7 @@ debugger_cpu::debugger_cpu(running_machine &machine) , m_bpindex(1) , m_wpindex(1) , m_rpindex(1) + , m_epindex(1) , m_wpdata(0) , m_wpaddr(0) , m_wpsize(0) @@ -91,7 +93,7 @@ debugger_cpu::debugger_cpu(running_machine &machine) for (int regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++) { char symname[10]; - sprintf(symname, "temp%d", regnum); + snprintf(symname, 10, "temp%d", regnum); m_symtable->add(symname, symbol_table::READ_WRITE, &m_tempvar[regnum]); } } @@ -385,7 +387,7 @@ void debugger_cpu::go_vblank() m_execution_state = exec_state::RUNNING; } -void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args) +void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args) { // if something is pending on this CPU already, ignore this request if (device == m_breakcpu) @@ -423,9 +425,9 @@ device_debug::device_debug(device_t &device) , m_disasm(nullptr) , m_flags(0) , m_symtable(std::make_unique<symbol_table>(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device)) - , m_instrhook(nullptr) , m_stepaddr(0) , m_stepsleft(0) + , m_delay_steps(0) , m_stopaddr(0) , m_stoptime(attotime::zero) , m_stopirq(0) @@ -436,7 +438,8 @@ device_debug::device_debug(device_t &device) , m_pc_history_index(0) , m_pc_history_valid(0) , m_bplist() - , m_rplist(std::make_unique<std::forward_list<debug_registerpoint>>()) + , m_rplist() + , m_eplist() , m_triggered_breakpoint(nullptr) , m_triggered_watchpoint(nullptr) , m_trace(nullptr) @@ -458,14 +461,14 @@ device_debug::device_debug(device_t &device) // set up notifiers and clear the passthrough handlers if (m_memory) { int count = m_memory->max_space_count(); - m_phw.resize(count, nullptr); + m_phw.resize(count); for (int i=0; i != count; i++) if (m_memory->has_space(i)) { address_space &space = m_memory->space(i); - m_notifiers.push_back(space.add_change_notifier([this, &space](read_or_write mode) { reinstall(space, mode); })); + m_notifiers.emplace_back(space.add_change_notifier([this, &space] (read_or_write mode) { reinstall(space, mode); })); } else - m_notifiers.push_back(-1); + m_notifiers.emplace_back(); } // set up state-related stuff @@ -547,6 +550,7 @@ device_debug::~device_debug() breakpoint_clear_all(); watchpoint_clear_all(); registerpoint_clear_all(); + exceptionpoint_clear_all(); } void device_debug::write_tracking(address_space &space, offs_t address, u64 data) @@ -562,15 +566,14 @@ void device_debug::reinstall(address_space &space, read_or_write mode) int id = space.spacenum(); if (u32(mode) & u32(read_or_write::WRITE)) { - if (m_phw[id]) - m_phw[id]->remove(); + m_phw[id].remove(); if (m_track_mem) switch (space.data_width()) { - case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, m_phw[id]); break; - case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, m_phw[id]); break; - case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, m_phw[id]); break; - case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, m_phw[id]); break; + case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, &m_phw[id]); break; + case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, &m_phw[id]); break; + case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, &m_phw[id]); break; + case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, &m_phw[id]); break; } } } @@ -633,15 +636,46 @@ void device_debug::stop_hook() // acknowledged //------------------------------------------------- -void device_debug::interrupt_hook(int irqline) +void device_debug::interrupt_hook(int irqline, offs_t pc) { // see if this matches a pending interrupt request if ((m_flags & DEBUG_FLAG_STOP_INTERRUPT) != 0 && (m_stopirq == -1 || m_stopirq == irqline)) { m_device.machine().debugger().cpu().set_execution_stopped(); - m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d)\n", m_device.tag(), irqline); + const address_space &space = m_memory->space(AS_PROGRAM); + if (space.is_octal()) + m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*o)\n", m_device.tag(), irqline, (space.logaddr_width() + 2) / 3, pc); + else + m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*X)\n", m_device.tag(), irqline, space.logaddrchars(), pc); compute_debug_flags(); } + + if (m_trace != nullptr) + m_trace->interrupt_update(irqline, pc); + + if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0) + { + if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) == 0) + { + if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0) + { + if ((m_stepaddr == pc && (m_flags & DEBUG_FLAG_STEPPING_BRANCH_FALSE) != 0) || + (m_stepaddr != pc && m_delay_steps == 1 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0)) + { + // step over the interrupt and then call it finished + m_flags = (m_flags & ~(DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_ANY)) | DEBUG_FLAG_STEPPING_OVER; + m_stepsleft = 1; + } + } + + // remember the interrupt return address + m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS; + m_stepaddr = pc; + } + + m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS; + m_delay_steps = 0; + } } @@ -671,10 +705,39 @@ void device_debug::exception_hook(int exception) if (matched) { m_device.machine().debugger().cpu().set_execution_stopped(); - m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %d, PC=%X)\n", m_device.tag(), exception, m_state->pcbase()); + m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %X, PC=%s)\n", m_device.tag(), exception, m_state->state_string(STATE_GENPC)); compute_debug_flags(); } } + + // see if any exception points match + if (!m_eplist.empty()) + { + auto epitp = m_eplist.equal_range(exception); + for (auto epit = epitp.first; epit != epitp.second; ++epit) + { + debug_exceptionpoint &ep = *epit->second; + if (ep.hit(exception)) + { + // halt in the debugger by default + debugger_cpu &debugcpu = m_device.machine().debugger().cpu(); + debugcpu.set_execution_stopped(); + + // if we hit, evaluate the action + if (!ep.m_action.empty()) + m_device.machine().debugger().console().execute_command(ep.m_action, false); + + // print a notification, unless the action made us go again + if (debugcpu.is_stopped()) + { + debugcpu.set_execution_stopped(); + m_device.machine().debugger().console().printf("Stopped at exception point %X (CPU '%s', PC=%s)\n", ep.m_index, m_device.tag(), m_state->state_string(STATE_GENPC)); + compute_debug_flags(); + } + break; + } + } + } } @@ -688,11 +751,11 @@ void device_debug::privilege_hook() if ((m_flags & DEBUG_FLAG_STOP_PRIVILEGE) != 0) { bool matched = true; - if (m_privilege_condition && !m_privilege_condition->is_empty()) + if (m_stop_condition && !m_stop_condition->is_empty()) { try { - matched = m_privilege_condition->execute(); + matched = m_stop_condition->execute(); } catch (expression_error &) { @@ -743,26 +806,56 @@ void device_debug::instruction_hook(offs_t curpc) if (m_trace != nullptr) m_trace->update(curpc); - // per-instruction hook? - if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_HOOKED) != 0 && (*m_instrhook)(m_device, curpc)) - debugcpu.set_execution_stopped(); - // handle single stepping if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_STEPPING_ANY) != 0) { + bool do_step = true; + if ((m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) != 0) + { + if (curpc == m_stepaddr) + { + if ((~m_flags & (DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0) + { + debugcpu.set_execution_stopped(); + do_step = false; + } + + // reset the breakpoint + m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS); + m_delay_steps = 0; + } + else if (m_delay_steps != 0) + { + m_delay_steps--; + if (m_delay_steps == 0) + { + // branch taken or subroutine entered (TODO: interleaved multithreading can falsely trigger this) + if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0) + { + debugcpu.set_execution_stopped(); + do_step = false; + } + if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) != 0) + do_step = false; + m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS; + } + } + else + do_step = false; + } + // is this an actual step? - if (m_stepaddr == ~0 || curpc == m_stepaddr) + if (do_step) { - // decrement the count and reset the breakpoint + // decrement the count m_stepsleft--; - m_stepaddr = ~0; // if we hit 0, stop if (m_stepsleft == 0) debugcpu.set_execution_stopped(); // update every 100 steps until we are within 200 of the end - else if ((m_flags & DEBUG_FLAG_STEPPING_OUT) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0)) + else if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0)) { machine.debug_view().update_all(); machine.debug_view().flush_osd_updates(); @@ -784,7 +877,10 @@ void device_debug::instruction_hook(offs_t curpc) // check the temp running breakpoint and break if we hit it else if ((m_flags & DEBUG_FLAG_STOP_PC) != 0 && m_stopaddr == curpc) { - machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag()); + if (is_octal()) + machine.debugger().console().printf("Stopped at temporary breakpoint %o on CPU '%s'\n", m_stopaddr, m_device.tag()); + else + machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag()); debugcpu.set_execution_stopped(); } @@ -849,7 +945,7 @@ void device_debug::instruction_hook(offs_t curpc) } // handle step out/over on the instruction we are about to execute - if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT)) != 0 && m_stepaddr == ~0) + if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0 && (m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) == 0) prepare_for_step_overout(m_state->pcbase()); // no longer in debugger code @@ -858,22 +954,6 @@ void device_debug::instruction_hook(offs_t curpc) //------------------------------------------------- -// set_instruction_hook - set a hook to be -// called on each instruction for a given device -//------------------------------------------------- - -void device_debug::set_instruction_hook(debug_instruction_hook_func hook) -{ - // set the hook and also the CPU's flag for fast knowledge of the hook - m_instrhook = hook; - if (hook != nullptr) - m_flags |= DEBUG_FLAG_HOOKED; - else - m_flags &= ~DEBUG_FLAG_HOOKED; -} - - -//------------------------------------------------- // ignore - ignore/observe a given device //------------------------------------------------- @@ -928,8 +1008,9 @@ void device_debug::single_step(int numsteps) m_device.machine().rewind_capture(); m_stepsleft = numsteps; - m_stepaddr = ~0; + m_delay_steps = 0; m_flags |= DEBUG_FLAG_STEPPING; + m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS); m_device.machine().debugger().cpu().set_execution_running(); } @@ -945,8 +1026,9 @@ void device_debug::single_step_over(int numsteps) m_device.machine().rewind_capture(); m_stepsleft = numsteps; - m_stepaddr = ~0; + m_delay_steps = 0; m_flags |= DEBUG_FLAG_STEPPING_OVER; + m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS); m_device.machine().debugger().cpu().set_execution_running(); } @@ -961,9 +1043,11 @@ void device_debug::single_step_out() assert(m_exec != nullptr); m_device.machine().rewind_capture(); + m_stop_condition.reset(); m_stepsleft = 100; - m_stepaddr = ~0; + m_delay_steps = 0; m_flags |= DEBUG_FLAG_STEPPING_OUT; + m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS); m_device.machine().debugger().cpu().set_execution_running(); } @@ -1060,20 +1144,38 @@ void device_debug::go_privilege(const char *condition) { assert(m_exec != nullptr); m_device.machine().rewind_invalidate(); - m_privilege_condition = std::make_unique<parsed_expression>(*m_symtable, condition); + m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition); m_flags |= DEBUG_FLAG_STOP_PRIVILEGE; m_device.machine().debugger().cpu().set_execution_running(); } //------------------------------------------------- +// go_branch - execute until branch taken or +// not taken +//------------------------------------------------- + +void device_debug::go_branch(bool sense, const char *condition) +{ + assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); + m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition); + m_stepsleft = 100; + m_delay_steps = 0; + m_flags |= sense ? DEBUG_FLAG_STEPPING_BRANCH_TRUE : DEBUG_FLAG_STEPPING_BRANCH_FALSE; + m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS); + m_device.machine().debugger().cpu().set_execution_running(); +} + + +//------------------------------------------------- // halt_on_next_instruction_impl - halt in the // debugger on the next instruction, internal // implementation which is necessary solely due // to templates in C++ being janky as all get out //------------------------------------------------- -void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args) +void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<char> &&args) { assert(m_exec != nullptr); m_device.machine().debugger().cpu().halt_on_next_instruction(&m_device, std::move(args)); @@ -1098,7 +1200,7 @@ const debug_breakpoint *device_debug::breakpoint_find(offs_t address) const // returning its index //------------------------------------------------- -int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action) +int device_debug::breakpoint_set(offs_t address, const char *condition, std::string_view action) { // allocate a new one and hook it into our list u32 id = m_device.machine().debugger().cpu().get_breakpoint_index(); @@ -1185,7 +1287,7 @@ void device_debug::breakpoint_enable_all(bool enable) // returning its index //------------------------------------------------- -int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action) +int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, std::string_view action) { if (space.spacenum() >= int(m_wplist.size())) m_wplist.resize(space.spacenum()+1); @@ -1272,15 +1374,15 @@ void device_debug::watchpoint_enable_all(bool enable) // returning its index //------------------------------------------------- -int device_debug::registerpoint_set(const char *condition, const char *action) +int device_debug::registerpoint_set(const char *condition, std::string_view action) { // allocate a new one u32 id = m_device.machine().debugger().cpu().get_registerpoint_index(); - m_rplist->emplace_front(*m_symtable, id, condition, action); + m_rplist.emplace_front(*m_symtable, id, condition, action); // update the flags and return the index breakpoint_update_flags(); - return m_rplist->front().m_index; + return m_rplist.front().m_index; } @@ -1292,10 +1394,10 @@ int device_debug::registerpoint_set(const char *condition, const char *action) bool device_debug::registerpoint_clear(int index) { // scan the list to see if we own this registerpoint - for (auto brp = m_rplist->before_begin(); std::next(brp) != m_rplist->end(); ++brp) + for (auto brp = m_rplist.before_begin(); std::next(brp) != m_rplist.end(); ++brp) if (std::next(brp)->m_index == index) { - m_rplist->erase_after(brp); + m_rplist.erase_after(brp); breakpoint_update_flags(); return true; } @@ -1312,7 +1414,7 @@ bool device_debug::registerpoint_clear(int index) void device_debug::registerpoint_clear_all() { // clear the list - m_rplist->clear(); + m_rplist.clear(); breakpoint_update_flags(); } @@ -1325,7 +1427,7 @@ void device_debug::registerpoint_clear_all() bool device_debug::registerpoint_enable(int index, bool enable) { // scan the list to see if we own this conditionpoint - for (debug_registerpoint &rp : *m_rplist) + for (debug_registerpoint &rp : m_rplist) if (rp.m_index == index) { rp.m_enabled = enable; @@ -1346,12 +1448,97 @@ bool device_debug::registerpoint_enable(int index, bool enable) void device_debug::registerpoint_enable_all(bool enable) { // apply the enable to all registerpoints we own - for (debug_registerpoint &rp : *m_rplist) + for (debug_registerpoint &rp : m_rplist) registerpoint_enable(rp.index(), enable); } //------------------------------------------------- +// exceptionpoint_set - set a new exception +// point, returning its index +//------------------------------------------------- + +int device_debug::exceptionpoint_set(int exception, const char *condition, std::string_view action) +{ + // allocate a new one and hook it into our list + u32 id = m_device.machine().debugger().cpu().get_exceptionpoint_index(); + m_eplist.emplace(exception, std::make_unique<debug_exceptionpoint>(this, *m_symtable, id, exception, condition, action)); + + // return the index + return id; +} + + +//------------------------------------------------- +// exceptionpoint_clear - clear an exception +// point by index, returning true if we found it +//------------------------------------------------- + +bool device_debug::exceptionpoint_clear(int index) +{ + // scan the list to see if we own this breakpoint + for (auto epit = m_eplist.begin(); epit != m_eplist.end(); ++epit) + if (epit->second->m_index == index) + { + m_eplist.erase(epit); + return true; + } + + // we don't own it, return false + return false; +} + + +//------------------------------------------------- +// exceptionpoint_clear_all - clear all exception +// points +//------------------------------------------------- + +void device_debug::exceptionpoint_clear_all() +{ + // clear the list + m_eplist.clear(); +} + + +//------------------------------------------------- +// exceptionpoint_enable - enable/disable an +// exception point by index, returning true if we +// found it +//------------------------------------------------- + +bool device_debug::exceptionpoint_enable(int index, bool enable) +{ + // scan the list to see if we own this exception point + for (auto &epp : m_eplist) + { + debug_exceptionpoint &ep = *epp.second; + if (ep.m_index == index) + { + ep.m_enabled = enable; + return true; + } + } + + // we don't own it, return false + return false; +} + + +//------------------------------------------------- +// exceptionpoint_enable_all - enable/disable all +// exception points +//------------------------------------------------- + +void device_debug::exceptionpoint_enable_all(bool enable) +{ + // apply the enable to all exception points we own + for (auto &epp : m_eplist) + exceptionpoint_enable(epp.second->index(), enable); +} + + +//------------------------------------------------- // history_pc - return an entry from the PC // history //------------------------------------------------- @@ -1385,7 +1572,6 @@ void device_debug::set_track_pc(bool value) // track_pc_visited - returns a boolean stating // if this PC has been visited or not. CRC32 is // done in this function on currently active CPU. -// TODO: Take a CPU context as input //------------------------------------------------- bool device_debug::track_pc_visited(offs_t pc) const @@ -1399,7 +1585,6 @@ bool device_debug::track_pc_visited(offs_t pc) const //------------------------------------------------- // set_track_pc_visited - set this pc as visited. -// TODO: Take a CPU context as input //------------------------------------------------- void device_debug::set_track_pc_visited(offs_t pc) @@ -1541,7 +1726,7 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const buffer.data_get(pc, dasmresult & util::disasm_interface::LENGTHMASK, true, opbuf); // return a CRC of the exact count of opcode bytes - return core_crc32(0, &opbuf[0], opbuf.size()); + return util::crc32_creator::simple(&opbuf[0], opbuf.size()); } @@ -1549,31 +1734,14 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const // trace - trace execution of a given device //------------------------------------------------- -void device_debug::trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action) +void device_debug::trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action) { // delete any existing tracers m_trace = nullptr; // if we have a new file, make a new tracer if (file != nullptr) - m_trace = std::make_unique<tracer>(*this, *file, trace_over, detect_loops, logerror, action); -} - - -//------------------------------------------------- -// trace_printf - output data into the given -// device's tracefile, if tracing -//------------------------------------------------- - -void device_debug::trace_printf(const char *fmt, ...) -{ - if (m_trace != nullptr) - { - va_list va; - va_start(va, fmt); - m_trace->vprintf(fmt, va); - va_end(va); - } + m_trace = std::make_unique<tracer>(*this, std::move(file), trace_over, detect_loops, logerror, action); } @@ -1601,7 +1769,7 @@ void device_debug::compute_debug_flags() // if we're tracking history, or we're hooked, or stepping, or stopping at a breakpoint // make sure we call the hook - if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_HOOKED | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) + if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) machine.debug_flags |= DEBUG_FLAG_CALL_HOOK; // also call if we are tracing @@ -1625,12 +1793,32 @@ void device_debug::prepare_for_step_overout(offs_t pc) // disassemble the current instruction and get the flags u32 dasmresult = buffer.disassemble_info(pc); + if ((dasmresult & util::disasm_interface::SUPPORTED) == 0) + return; + + bool step_out = (m_flags & DEBUG_FLAG_STEPPING_OUT) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) != 0; + bool test_cond = (dasmresult & util::disasm_interface::STEP_COND) != 0 && ((m_flags & (DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0 || step_out); + if (test_cond && m_stop_condition && !m_stop_condition->is_empty()) + { + try + { + test_cond = m_stop_condition->execute(); + } + catch (expression_error &) + { + test_cond = false; + } + } // if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction - if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0) + // (TODO: this completely fails for subroutines that consume inline operands or use alternate returns) + if ((dasmresult & util::disasm_interface::STEP_OVER) != 0 || test_cond) { int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT; pc = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK); + m_delay_steps = extraskip + 1; + if (m_stepsleft < m_delay_steps) + m_stepsleft = m_delay_steps; // if we need to skip additional instructions, advance as requested while (extraskip-- > 0) { @@ -1638,13 +1826,17 @@ void device_debug::prepare_for_step_overout(offs_t pc) pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK); } m_stepaddr = pc; + if ((dasmresult & util::disasm_interface::STEP_OVER) != 0) + m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS; + if (test_cond) + m_flags |= DEBUG_FLAG_TEST_IN_PROGRESS; } // if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number - // (TODO: this doesn't work with conditional return instructions) - if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0) + if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0) { - if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) == 0) + // make sure to also reset the number of steps for conditionals that may be single-instruction loops + if (test_cond || !step_out) m_stepsleft = 100; else { @@ -1678,7 +1870,7 @@ void device_debug::breakpoint_update_flags() if (!(m_flags & DEBUG_FLAG_LIVE_BP)) { // see if there are any enabled registerpoints - for (debug_registerpoint &rp : *m_rplist) + for (debug_registerpoint &rp : m_rplist) { if (rp.m_enabled) { @@ -1728,7 +1920,7 @@ void device_debug::breakpoint_check(offs_t pc) } // see if we have any matching registerpoints - for (debug_registerpoint &rp : *m_rplist) + for (debug_registerpoint &rp : m_rplist) { if (rp.hit()) { @@ -1761,10 +1953,10 @@ void device_debug::breakpoint_check(offs_t pc) // tracer - constructor //------------------------------------------------- -device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action) +device_debug::tracer::tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action) : m_debug(debug) - , m_file(file) - , m_action((action != nullptr) ? action : "") + , m_file(std::move(file)) + , m_action(action) , m_detect_loops(detect_loops) , m_logerror(logerror) , m_loops(0) @@ -1783,7 +1975,7 @@ device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, b device_debug::tracer::~tracer() { // make sure we close the file if we can - fclose(&m_file); + m_file.reset(); } @@ -1819,7 +2011,7 @@ void device_debug::tracer::update(offs_t pc) // if we just finished looping, indicate as much if (m_loops != 0) - fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops); + util::stream_format(*m_file, "\n (loops for %d instructions)\n\n", m_loops); m_loops = 0; } @@ -1834,7 +2026,7 @@ void device_debug::tracer::update(offs_t pc) buffer.disassemble(pc, instruction, next_pc, size, dasmresult); // output the result - fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str()); + util::stream_format(*m_file, "%s: %s\n", buffer.pc_to_string(pc), instruction); // do we need to step the trace over this instruction? if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0) @@ -1852,7 +2044,33 @@ void device_debug::tracer::update(offs_t pc) // log this PC m_nextdex = (m_nextdex + 1) % TRACE_LOOPS; m_history[m_nextdex] = pc; - fflush(&m_file); + m_file->flush(); +} + + +//------------------------------------------------- +// interrupt_update - log interrupt to tracefile +//------------------------------------------------- + +void device_debug::tracer::interrupt_update(int irqline, offs_t pc) +{ + if (m_trace_over) + { + if (m_trace_over_target != ~0) + return; + m_trace_over_target = pc; + } + + // if we just finished looping, indicate as much + *m_file << "\n"; + if (m_detect_loops && m_loops != 0) + { + util::stream_format(*m_file, " (loops for %d instructions)\n", m_loops); + m_loops = 0; + } + + util::stream_format(*m_file, " (interrupted at %s, IRQ %d)\n\n", debug_disasm_buffer(m_debug.device()).pc_to_string(pc), irqline); + m_file->flush(); } @@ -1860,11 +2078,11 @@ void device_debug::tracer::update(offs_t pc) // vprintf - generic print to the trace file //------------------------------------------------- -void device_debug::tracer::vprintf(const char *format, va_list va) +void device_debug::tracer::vprintf(util::format_argument_pack<char> const &args) { // pass through to the file - vfprintf(&m_file, format, va); - fflush(&m_file); + util::stream_format(*m_file, args); + m_file->flush(); } @@ -1875,7 +2093,7 @@ void device_debug::tracer::vprintf(const char *format, va_list va) void device_debug::tracer::flush() { - fflush(&m_file); + m_file->flush(); } diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 9e3d23d8d7f..9a9f6e69f70 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -29,9 +29,6 @@ constexpr int COMMENT_VERSION = 1; // TYPE DEFINITIONS //************************************************************************** -typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc); - - // ======================> device_debug // [TODO] This whole thing is terrible. @@ -54,14 +51,11 @@ public: // hooks used by the rest of the system void start_hook(const attotime &endtime); void stop_hook(); - void interrupt_hook(int irqline); + void interrupt_hook(int irqline, offs_t pc); void exception_hook(int exception); void privilege_hook(); void instruction_hook(offs_t curpc); - // hooks into our operations - void set_instruction_hook(debug_instruction_hook_func hook); - // debugger focus void ignore(bool ignore = true); bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); } @@ -82,6 +76,7 @@ public: void go_exception(int exception, const char *condition); void go_milliseconds(u64 milliseconds); void go_privilege(const char *condition); + void go_branch(bool sense, const char *condition); void go_next_device(); template <typename Format, typename... Params> @@ -93,7 +88,7 @@ public: // breakpoints const auto &breakpoint_list() const { return m_bplist; } const debug_breakpoint *breakpoint_find(offs_t address) const; - int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr); + int breakpoint_set(offs_t address, const char *condition = nullptr, std::string_view action = {}); bool breakpoint_clear(int index); void breakpoint_clear_all(); bool breakpoint_enable(int index, bool enable = true); @@ -103,7 +98,7 @@ public: // watchpoints int watchpoint_space_count() const { return m_wplist.size(); } const std::vector<std::unique_ptr<debug_watchpoint>> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; } - int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action); + int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition = nullptr, std::string_view action = {}); bool watchpoint_clear(int wpnum); void watchpoint_clear_all(); bool watchpoint_enable(int index, bool enable = true); @@ -112,12 +107,20 @@ public: debug_watchpoint *triggered_watchpoint() { debug_watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; } // registerpoints - const std::forward_list<debug_registerpoint> ®isterpoint_list() const { return *m_rplist; } - int registerpoint_set(const char *condition, const char *action = nullptr); + const std::forward_list<debug_registerpoint> ®isterpoint_list() const { return m_rplist; } + int registerpoint_set(const char *condition, std::string_view action = {}); bool registerpoint_clear(int index); void registerpoint_clear_all(); bool registerpoint_enable(int index, bool enable = true); - void registerpoint_enable_all(bool enable = true ); + void registerpoint_enable_all(bool enable = true); + + // exception points + const auto &exceptionpoint_list() const { return m_eplist; } + int exceptionpoint_set(int exception, const char *condition = nullptr, std::string_view action = {}); + bool exceptionpoint_clear(int index); + void exceptionpoint_clear_all(); + bool exceptionpoint_enable(int index, bool enable = true); + void exceptionpoint_enable_all(bool enable = true); // comments void comment_add(offs_t address, const char *comment, rgb_t color); @@ -146,8 +149,12 @@ public: void track_mem_data_clear() { m_track_mem_set.clear(); } // tracing - void trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action); - void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3); + void trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action); + template <typename Format, typename... Params> void trace_printf(Format &&fmt, Params &&...args) + { + if (m_trace != nullptr) + m_trace->vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)); + } void trace_flush() { if (m_trace != nullptr) m_trace->flush(); } void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; } @@ -158,7 +165,7 @@ public: void compute_debug_flags(); private: - void halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args); + void halt_on_next_instruction_impl(util::format_argument_pack<char> &&args); // internal helpers void prepare_for_step_overout(offs_t pc); @@ -181,18 +188,18 @@ private: // global state u32 m_flags; // debugging flags for this CPU std::unique_ptr<symbol_table> m_symtable; // symbol table for expression evaluation - debug_instruction_hook_func m_instrhook; // per-instruction callback hook // stepping information - offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER + offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER or DEBUG_FLAG_STEPPING_BRANCH int m_stepsleft; // number of steps left until done + int m_delay_steps; // number of steps until target address check // execution information offs_t m_stopaddr; // stop address for DEBUG_FLAG_STOP_PC attotime m_stoptime; // stop time for DEBUG_FLAG_STOP_TIME int m_stopirq; // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT int m_stopexception; // stop exception number for DEBUG_FLAG_STOP_EXCEPTION - std::unique_ptr<parsed_expression> m_privilege_condition; // expression to evaluate on privilege change + std::unique_ptr<parsed_expression> m_stop_condition; // expression to evaluate on privilege change std::unique_ptr<parsed_expression> m_exception_condition; // expression to evaluate on exception hit attotime m_endexectime; // ending time of the current execution u64 m_total_cycles; // current total cycles @@ -206,7 +213,8 @@ private: // breakpoints and watchpoints std::multimap<offs_t, std::unique_ptr<debug_breakpoint>> m_bplist; // list of breakpoints std::vector<std::vector<std::unique_ptr<debug_watchpoint>>> m_wplist; // watchpoint lists for each address space - std::unique_ptr<std::forward_list<debug_registerpoint>> m_rplist; // list of registerpoints + std::forward_list<debug_registerpoint> m_rplist; // list of registerpoints + std::multimap<offs_t, std::unique_ptr<debug_exceptionpoint>> m_eplist; // list of exception points debug_breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered debug_watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered @@ -215,11 +223,12 @@ private: class tracer { public: - tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action); + tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action); ~tracer(); void update(offs_t pc); - void vprintf(const char *format, va_list va); + void interrupt_update(int irqline, offs_t pc); + void vprintf(util::format_argument_pack<char> const &args); void flush(); bool logerror() const { return m_logerror; } @@ -227,7 +236,7 @@ private: static const int TRACE_LOOPS = 64; device_debug & m_debug; // reference to our owner - FILE & m_file; // tracing file for this CPU + std::unique_ptr<std::ostream> m_file; // tracing file for this CPU std::string m_action; // action to perform during a trace offs_t m_history[TRACE_LOOPS]; // history of recent PCs bool m_detect_loops; // whether or not we should detect loops @@ -239,10 +248,10 @@ private: // (0 = not tracing over, // ~0 = not currently tracing over) }; - std::unique_ptr<tracer> m_trace; // tracer state + std::unique_ptr<tracer> m_trace; // tracer state - std::vector<memory_passthrough_handler *> m_phw; // passthrough handler reference for each space, write mode - std::vector<int> m_notifiers; // notifiers for each space + std::vector<memory_passthrough_handler> m_phw; // passthrough handler reference for each space, write mode + std::vector<util::notifier_subscription> m_notifiers; // notifiers for each space // pc tracking class dasm_pc_tag @@ -310,7 +319,6 @@ private: static constexpr u32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history static constexpr u32 DEBUG_FLAG_TRACING = 0x00000004; // tracing this CPU static constexpr u32 DEBUG_FLAG_TRACING_OVER = 0x00000008; // tracing this CPU with step over behavior - static constexpr u32 DEBUG_FLAG_HOOKED = 0x00000010; // per-instruction callback hook static constexpr u32 DEBUG_FLAG_STEPPING = 0x00000020; // CPU is single stepping static constexpr u32 DEBUG_FLAG_STEPPING_OVER = 0x00000040; // CPU is stepping over a function static constexpr u32 DEBUG_FLAG_STEPPING_OUT = 0x00000080; // CPU is stepping out of a function @@ -322,12 +330,17 @@ private: static constexpr u32 DEBUG_FLAG_SUSPENDED = 0x00004000; // CPU currently suspended static constexpr u32 DEBUG_FLAG_LIVE_BP = 0x00010000; // there are live breakpoints for this CPU static constexpr u32 DEBUG_FLAG_STOP_PRIVILEGE = 0x00020000; // run until execution level changes + static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_TRUE = 0x0040000; // run until true branch + static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_FALSE = 0x0080000; // run until false branch + static constexpr u32 DEBUG_FLAG_CALL_IN_PROGRESS = 0x01000000; // CPU is in the middle of a subroutine call + static constexpr u32 DEBUG_FLAG_TEST_IN_PROGRESS = 0x02000000; // CPU is performing a conditional test and branch - static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT; + static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH = DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE; + static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH; static constexpr u32 DEBUG_FLAG_TRACING_ANY = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER; static constexpr u32 DEBUG_FLAG_TRANSIENT = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK | - DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE; + DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE | DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS; }; //************************************************************************** @@ -377,6 +390,7 @@ public: u32 get_breakpoint_index() { return m_bpindex++; } u32 get_watchpoint_index() { return m_wpindex++; } u32 get_registerpoint_index() { return m_rpindex++; } + u32 get_exceptionpoint_index() { return m_epindex++; } // setters void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; } @@ -392,7 +406,7 @@ public: void stop_hook(device_t *device); void go_next_device(device_t *device); void go_vblank(); - void halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args); + void halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args); void ensure_comments_loaded(); void reset_transient_flags(); @@ -419,6 +433,7 @@ private: u32 m_bpindex; u32 m_wpindex; u32 m_rpindex; + u32 m_epindex; u64 m_wpdata; u64 m_wpaddr; diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp index 87bf8f0f18f..76102402bcb 100644 --- a/src/emu/debug/debughlp.cpp +++ b/src/emu/debug/debughlp.cpp @@ -46,6 +46,7 @@ const help_item f_static_help_list[] = " Breakpoints\n" " Watchpoints\n" " Registerpoints\n" + " Exception Points\n" " Expressions\n" " Comments\n" " Cheats\n" @@ -81,6 +82,7 @@ const help_item f_static_help_list[] = " stateload[sl] <filename> -- load a state file for the current driver\n" " snap [<filename>] -- save a screen snapshot.\n" " source <filename> -- reads commands from <filename> and executes them one by one\n" + " time -- prints current machine time to the console\n" " cls -- clears the console text buffer\n" " quit -- exits MAME and the debugger\n" }, @@ -132,8 +134,12 @@ const help_item f_static_help_list[] = " o[ver] [<count>=1] -- single steps over <count> instructions (F10)\n" " out -- single steps until the current subroutine/exception handler is exited (Shift-F11)\n" " g[o] [<address>] -- resumes execution, sets temp breakpoint at <address> (F5)\n" + " gbf [<condition>] -- resumes execution until next false branch\n" + " gbt [<condition>] -- resumes execution until next true branch\n" + " gn[i] [<count>] -- resumes execution, sets temp breakpoint <count> instructions ahead\n" " ge[x] [<exception>[,<condition>]] -- resumes execution, setting temp breakpoint if <exception> is raised\n" " gi[nt] [<irqline>] -- resumes execution, setting temp breakpoint if <irqline> is taken (F7)\n" + " gp [<condition>] -- resumes execution, setting temp breakpoint if privilege level changes\n" " gt[ime] <milliseconds> -- resumes execution until the given delay has elapsed\n" " gv[blank] -- resumes execution, setting temp breakpoint on the next VBLANK (F8)\n" " n[ext] -- executes until the next CPU switch (F6)\n" @@ -187,6 +193,18 @@ const help_item f_static_help_list[] = " rplist [<CPU>] -- lists all the registerpoints\n" }, { + "exceptionpoints", + "\n" + "Exception Point Commands\n" + "Type help <command> for further details on each command\n" + "\n" + " ep[set] <type>[,<condition>[,<action>]] -- sets exception point on <type>\n" + " epclear [<epnum>] -- clears a given exception point or all if no <epnum> specified\n" + " epdisable [<epnum>] -- disabled a given exception point or all if no <epnum> specified\n" + " epenable [<epnum>] -- enables a given exception point or all if no <epnum> specified\n" + " eplist -- lists all the exception points\n" + }, + { "expressions", "\n" "Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is " @@ -341,16 +359,20 @@ const help_item f_static_help_list[] = "The printf command performs a C-style printf to the debugger console. Only a very limited set of " "formatting options are available:\n" "\n" - " %[0][<n>]d -- prints <item> as a decimal value with optional digit count and zero-fill\n" - " %[0][<n>]x -- prints <item> as a hexadecimal value with optional digit count and zero-fill\n" + " %c -- 8-bit character\n" + " %[-][0][<n>]d -- decimal number with optional left justification, zero fill and minimum width\n" + " %[-][0][<n>]o -- octal number with optional left justification, zero fill and minimum width\n" + " %[-][0][<n>]x -- lowercase hexadecimal number with optional left justification, zero fill and minimum width\n" + " %[-][0][<n>]X -- uppercase hexadecimal number with optional left justification, zero fill and minimum width\n" + " %[-][<n>][.[<n>]]s -- null-terminated string of 8-bit characters with optional left justification, minimum and maximum width\n" "\n" - "All remaining formatting options are ignored. Use %% together to output a % character. Multiple " - "lines can be printed by embedding a \\n in the text.\n" + "All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be " + "printed by embedding a \\n in the text.\n" "\n" "Examples:\n" "\n" "printf \"PC=%04X\",pc\n" - " Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n" + " Prints PC=<pcval> where <pcval> is displayed in uppercase hexadecimal with 4 digits and zero fill.\n" "\n" "printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n" " Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n" @@ -361,18 +383,12 @@ const help_item f_static_help_list[] = " logerror <format>[,<item>[,...]]\n" "\n" "The logerror command performs a C-style printf to the error log. Only a very limited set of " - "formatting options are available:\n" - "\n" - " %[0][<n>]d -- logs <item> as a decimal value with optional digit count and zero-fill\n" - " %[0][<n>]x -- logs <item> as a hexadecimal value with optional digit count and zero-fill\n" - "\n" - "All remaining formatting options are ignored. Use %% together to output a % character. Multiple " - "lines can be printed by embedding a \\n in the text.\n" + "formatting options are available. See the 'printf' help for details.\n" "\n" "Examples:\n" "\n" - "logerror \"PC=%04X\",pc\n" - " Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n" + "logerror \"PC=%04x\",pc\n" + " Logs PC=<pcval> where <pcval> is displayed in lowercase hexadecimal with 4 digits and zero fill.\n" "\n" "logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n" " Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n" @@ -578,6 +594,13 @@ const help_item f_static_help_list[] = " Reads in debugger commands from break_and_trace.cmd and executes them.\n" }, { + "time", + "\n" + " time\n" + "\n" + "The time command prints the current machine time to the console.\n" + }, + { "quit", "\n" " quit\n" @@ -920,6 +943,66 @@ const help_item f_static_help_list[] = " Resume execution, stopping at address 1234 unless something else stops us first.\n" }, { + "gbf", + "\n" + " gbf [<condition>]\n" + "\n" + "The gbf command resumes execution of the current code. Control will not be returned to the " + "debugger until a conditional branch or skip instruction tests false and falls through to the " + "next instruction, or the instruction that follows its delay slot. The optional conditional " + "expression, if provided, will be evaluated at (not after) each conditional branch; execution " + "will not halt regardless of consequent program flow unless its result is true (non-zero).\n" + "\n" + "Examples:\n" + "\n" + "gbf\n" + " Resume execution until the next break/watchpoint or until the next false branch.\n" + "\n" + "gbf {pc != 1234}\n" + " Resume execution until the next false branch, disregarding the instruction at address 1234.\n" + }, + { + "gbt", + "\n" + " gbt [<condition>]\n" + "\n" + "The gbt command resumes execution of the current code. Control will not be returned to the " + "debugger until a conditional branch or skip instruction tests true and program flow transfers " + "to any instruction other than the next one following the delay slot (if any). The optional " + "conditional expression, if provided, will be evaluated at (not after) each conditional " + "branch; execution will not halt regardless of consequent program flow unless its result is " + "true (non-zero).\n" + "\n" + "Examples:\n" + "\n" + "gbt\n" + " Resume execution until the next break/watchpoint or until the next true branch.\n" + "\n" + "gbt {pc != 1234}\n" + " Resume execution until the next true branch, disregarding the instruction at address 1234.\n" + }, + { + "gni", + "\n" + " gn[i] [<count>]\n" + "\n" + "The gni command resumes execution of the current code. Control will not be returned to the " + "debugger until a breakpoint or watchpoint is hit, or until you manually break in using the " + "assigned key. Before executing, the gni command sets a temporary unconditional breakpoint " + "<count> instructions sequentially past the current one, which is automatically removed when " + "hit. If <count> is omitted, its default value is 1. If <count> is specified as zero, the " + "command does nothing. <count> is not permitted to exceed 512 decimal." + "\n" + "Examples:\n" + "\n" + "gni\n" + " Resume execution, stopping at the address of the next instruction unless something else " + "stops us first.\n" + "\n" + "gni 2\n" + " Resume execution, stopping at two instructions past the current one.\n" + }, + { "gex", "\n" " ge[x] [<exception>,[<condition>]]\n" @@ -965,6 +1048,27 @@ const help_item f_static_help_list[] = "acknowledged on the current CPU.\n" }, { + "gp", + "\n" + " gp [<condition>]\n" + "\n" + "The gp command resumes execution of the current code. Control will not be returned to " + "the debugger until a breakpoint or watchpoint is hit, or the privilege level of the current " + "CPU changes. The optional <condition> parameter lets you specify an expression that will " + "be evaluated each time the privilege level changes. If the expression evaluates to true " + "(non-zero), execution will halt; otherwise, execution will continue with no notification.\n" + "\n" + "Examples:\n" + "\n" + "gp\n" + " Resume execution until the next break/watchpoint or the privilege level of the current " + "CPU changes.\n" + "\n" + "gp {pc != 1234}\n" + " Resume execution until the next break/watchpoint or the privilege level of the current " + "CPU changes, disregarding the instruction at address 1234.\n" + }, + { "gtime", "\n" " gt[ime] <milliseconds>\n" @@ -1484,6 +1588,92 @@ const help_item f_static_help_list[] = "actions attached to them.\n" }, { + "epset", + "\n" + " ep[set] <type>[,<condition>[,<action>]]\n" + "\n" + "Sets a new exception point for exceptions of type <type> on the currently visible CPU. " + "The optional <condition> parameter lets you specify an expression that will be evaluated " + "each time the exception point is hit. If the result of the expression is true (non-zero), " + "the exception point will actually halt execution at the start of the exception handler; " + "otherwise, execution will continue with no notification. The optional <action> parameter " + "provides a command that is executed whenever the exception point is hit and the " + "<condition> is true. Note that you may need to embed the action within braces { } in order " + "to prevent commas and semicolons from being interpreted as applying to the epset command " + "itself.\n" + "\n" + "The numbering of exceptions depends upon the CPU type. Causes of exceptions may include " + "internally or externally vectored interrupts, errors occurring within instructions and " + "system calls.\n" + "\n" + "Each exception point that is set is assigned an index which can be used in other " + "exception point commands to reference this exception point.\n" + "\n" + "Examples:\n" + "\n" + "ep 2\n" + " Set an exception that will halt execution whenever the visible CPU raises exception " + "number 2.\n" + }, + { + "epclear", + "\n" + " epclear [<epnum>[,...]]\n" + "\n" + "The epclear command clears exception points. If <epnum> is specified, only the requested " + "exception points are cleared, otherwise all exception points are cleared.\n" + "\n" + "Examples:\n" + "\n" + "epclear 3\n" + " Clear exception point index 3.\n" + "\n" + "epclear\n" + " Clear all exception points.\n" + }, + { + "epdisable", + "\n" + " epdisable [<epnum>[,...]]\n" + "\n" + "The epdisable command disables exception points. If <epnum> is specified, only the requested " + "exception points are disabled, otherwise all exception points are disabled. Note that " + "disabling an exception point does not delete it, it just temporarily marks the exception " + "point as inactive.\n" + "\n" + "Examples:\n" + "\n" + "epdisable 3\n" + " Disable exception point index 3.\n" + "\n" + "epdisable\n" + " Disable all exception points.\n" + }, + { + "epenable", + "\n" + " epenable [<epnum>[,...]]\n" + "\n" + "The epenable command enables exception points. If <epnum> is specified, only the " + "requested exception points are enabled, otherwise all exception points are enabled.\n" + "\n" + "Examples:\n" + "\n" + "epenable 3\n" + " Enable exception point index 3.\n" + "\n" + "epenable\n" + " Enable all exception points.\n" + }, + { + "eplist", + "\n" + " eplist\n" + "\n" + "The eplist command lists all the current exception points, along with their index and " + "any conditions or actions attached to them.\n" + }, + { "map", "\n" " map[{d|i|o}] <address>[:<space>]\n" @@ -1853,10 +2043,12 @@ private: help_map m_help_list; help_item const *m_uncached_help = std::begin(f_static_help_list); + util::ovectorstream m_message_buffer; + help_manager() = default; public: - char const *find(std::string_view tag) + std::string_view find(std::string_view tag) { // find a cached exact match if possible std::string const lower = strmakelower(tag); @@ -1892,16 +2084,17 @@ public: if ((m_help_list.end() == next) || (next->first.substr(0, lower.length()) != lower)) return candidate->second; - // TODO: pointers to static strings are bad, mmmkay? - static char ambig_message[1024]; - int msglen = std::sprintf(ambig_message, "Ambiguous help request, did you mean:\n"); + m_message_buffer.clear(); + m_message_buffer.reserve(1024); + m_message_buffer.seekp(0, util::ovectorstream::beg); + m_message_buffer << "Ambiguous help request, did you mean:\n"; do { - msglen += std::sprintf(&ambig_message[msglen], " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]); + util::stream_format(m_message_buffer, " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]); ++candidate; } while ((m_help_list.end() != candidate) && (candidate->first.substr(0, lower.length()) == lower)); - return ambig_message; + return util::buf_to_string_view(m_message_buffer); } // take the first help entry if no matches at all @@ -1923,7 +2116,7 @@ public: PUBLIC INTERFACE ***************************************************************************/ -const char *debug_get_help(std::string_view tag) +std::string_view debug_get_help(std::string_view tag) { return help_manager::instance().find(tag); } diff --git a/src/emu/debug/debughlp.h b/src/emu/debug/debughlp.h index 495d674eb0d..9efe12acaca 100644 --- a/src/emu/debug/debughlp.h +++ b/src/emu/debug/debughlp.h @@ -21,6 +21,6 @@ ***************************************************************************/ // help management -const char *debug_get_help(std::string_view tag); +std::string_view debug_get_help(std::string_view tag); #endif // MAME_EMU_DEBUG_DEBUGHLP_H diff --git a/src/emu/debug/debugvw.cpp b/src/emu/debug/debugvw.cpp index 5bcc3d057b8..54fe57ecf5a 100644 --- a/src/emu/debug/debugvw.cpp +++ b/src/emu/debug/debugvw.cpp @@ -503,11 +503,11 @@ bool debug_view_expression::recompute() std::string oldstring(m_parsed.original_string()); try { - m_parsed.parse(m_string.c_str()); + m_parsed.parse(m_string); } catch (expression_error &) { - m_parsed.parse(oldstring.c_str()); + m_parsed.parse(oldstring); } } diff --git a/src/emu/debug/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp index b42b86a0e90..d7be62c1eaa 100644 --- a/src/emu/debug/dvbpoints.cpp +++ b/src/emu/debug/dvbpoints.cpp @@ -71,7 +71,7 @@ static bool cConditionDescending(const debug_breakpoint *a, const debug_breakpoi static bool cActionAscending(const debug_breakpoint *a, const debug_breakpoint *b) { - return strcmp(a->action(), b->action()) < 0; + return a->action() < b->action(); } static bool cActionDescending(const debug_breakpoint *a, const debug_breakpoint *b) diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp index 02fcde9cbc3..da792305c0d 100644 --- a/src/emu/debug/dvmemory.cpp +++ b/src/emu/debug/dvmemory.cpp @@ -20,6 +20,20 @@ //************************************************************************** +// HELPER FUNCTIONS +//************************************************************************** + +namespace { + +constexpr u8 sanitise_character(u8 ch) +{ + // assume ISO-8859-1 (low 256 Unicode codepoints) - tab, soft hyphen, C0 and C1 cause problems + return ('\t' == ch) ? ' ' : (0xadU == ch) ? '-' : ((' ' > ch) || (('~' < ch) && (0xa0U > ch))) ? '.' : ch; +} + +} // anonymous namespace + +//************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -295,13 +309,13 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char * // generate the address char addrtext[20]; - sprintf(addrtext, m_addrformat.c_str(), address); + snprintf(addrtext, 20, m_addrformat.c_str(), address); debug_view_char *dest = destrow + m_section[0].m_pos + 1; for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++) if (dest >= destmin && dest < destmax) dest->byte = addrtext[ch]; - // generate the data and the ascii string + // generate the data and the ASCII string std::string chunkascii; if (m_shift_bits != 0) { @@ -323,7 +337,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char * for (int i = 0; i < m_bytes_per_chunk; i++) { u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + chunkascii += char(ismapped ? sanitise_character(chval) : '.'); } } } @@ -345,15 +359,15 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char * switch (m_data_format) { case data_format::FLOAT_32BIT: - sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata))); + snprintf(valuetext, 64, "%.8g", u32_to_float(u32(chunkdata))); break; case data_format::FLOAT_64BIT: - sprintf(valuetext, "%.24g", u64_to_double(chunkdata)); + snprintf(valuetext, 64, "%.24g", u64_to_double(chunkdata)); break; case data_format::FLOAT_80BIT: { float64_t f64 = extF80M_to_f64(&chunkdata80); - sprintf(valuetext, "%.24g", u64_to_double(f64.v)); + snprintf(valuetext, 64, "%.24g", u64_to_double(f64.v)); break; } default: @@ -380,7 +394,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char * for (int i = 0; i < m_bytes_per_chunk; i++) { u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + chunkascii += char(ismapped ? sanitise_character(chval) : '.'); } } } @@ -526,16 +540,8 @@ void debug_view_memory::view_char(int chval) if (hexchar == nullptr || (m_shift_bits == 3 && chval >= '8')) break; - const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); - offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(pos.m_address) : pos.m_address; - u64 data; - bool ismapped = read(m_bytes_per_chunk, address, data); - if (!ismapped) - break; - - data &= ~(util::make_bitmask<u64>(m_shift_bits) << pos.m_shift); - data |= u64(hexchar - hexvals) << pos.m_shift; - write(m_bytes_per_chunk, address, data); + if (!write_digit(pos.m_address, pos.m_shift, hexchar - hexvals)) + break; // TODO: alert OSD? } // fall through to the right-arrow press [[fallthrough]]; @@ -856,14 +862,17 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) auto dis = machine().disable_side_effects(); bool ismapped = offs <= m_maxaddr; + address_space *tspace; if (ismapped && !m_no_translation) { offs_t dummyaddr = offs; - ismapped = source.m_memintf->translate(source.m_space->spacenum(), TRANSLATE_READ_DEBUG, dummyaddr); + ismapped = source.m_memintf->translate(source.m_space->spacenum(), device_memory_interface::TR_READ, dummyaddr, tspace); } + else + tspace = source.m_space; data = ~u64(0); if (ismapped) - data = m_expression.context().read_memory(*source.m_space, offs, size, !m_no_translation); + data = m_expression.context().read_memory(*tspace, offs, size, !m_no_translation); return ismapped; } @@ -984,6 +993,41 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data) //------------------------------------------------- +// write_digit - write one hex or octal digit +// at the given address and bit position +//------------------------------------------------- + +bool debug_view_memory::write_digit(offs_t offs, u8 pos, u8 digit) +{ + const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); + offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(offs) : offs; + u64 data; + bool ismapped = read(m_bytes_per_chunk, address, data); + if (!ismapped) + return false; + + // clamp to chunk size + if (m_bytes_per_chunk * 8 < pos + m_shift_bits) + { + assert(m_bytes_per_chunk * 8 > pos); + digit &= util::make_bitmask<u8>(m_bytes_per_chunk * 8 - pos); + } + + u64 write_data = (data & ~(util::make_bitmask<u64>(m_shift_bits) << pos)) | (u64(digit) << pos); + write(m_bytes_per_chunk, address, write_data); + + // verify that data reads back as it was written + if (source.m_space != nullptr) + { + read(m_bytes_per_chunk, address, data); + return data == write_data; + } + else + return true; +} + + +//------------------------------------------------- // set_expression - set the expression string // describing the home address //------------------------------------------------- diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h index f2c738a6ff4..6f1ffab4e9e 100644 --- a/src/emu/debug/dvmemory.h +++ b/src/emu/debug/dvmemory.h @@ -127,6 +127,7 @@ private: // memory access bool read(u8 size, offs_t offs, u64 &data); void write(u8 size, offs_t offs, u64 data); + bool write_digit(offs_t offs, u8 pos, u8 digit); bool read(u8 size, offs_t offs, extFloat80_t &data); bool read_chunk(offs_t address, int chunknum, u64 &chunkdata); void generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address); diff --git a/src/emu/debug/dvrpoints.cpp b/src/emu/debug/dvrpoints.cpp index 3ecadaec8e5..7295a1b2170 100644 --- a/src/emu/debug/dvrpoints.cpp +++ b/src/emu/debug/dvrpoints.cpp @@ -62,7 +62,7 @@ bool cConditionDescending(std::pair<device_t *, debug_registerpoint const *> con bool cActionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b) { - return strcmp(a.second->action(), b.second->action()) < 0; + return a.second->action() < b.second->action(); } bool cActionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b) diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp index 8363928e5cb..9ab75b7b655 100644 --- a/src/emu/debug/express.cpp +++ b/src/emu/debug/express.cpp @@ -387,10 +387,10 @@ void symbol_table::set_memory_modified_func(memory_modified_func modified) // add - add a new u64 pointer symbol //------------------------------------------------- -void symbol_table::add(const char *name, read_write rw, u64 *ptr) +symbol_entry &symbol_table::add(const char *name, read_write rw, u64 *ptr) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr)); + return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr)).first->second; } @@ -398,10 +398,10 @@ void symbol_table::add(const char *name, read_write rw, u64 *ptr) // add - add a new value symbol //------------------------------------------------- -void symbol_table::add(const char *name, u64 value) +symbol_entry &symbol_table::add(const char *name, u64 value) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value)); + return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value)).first->second; } @@ -409,10 +409,10 @@ void symbol_table::add(const char *name, u64 value) // add - add a new register symbol //------------------------------------------------- -void symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string) +symbol_entry &symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)); + return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)).first->second; } @@ -420,10 +420,10 @@ void symbol_table::add(const char *name, getter_func getter, setter_func setter, // add - add a new function symbol //------------------------------------------------- -void symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute) +symbol_entry &symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute) { m_symlist.erase(name); - m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)); + return *m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)).first->second; } @@ -482,23 +482,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo { u64 result = ~u64(0) >> (64 - 8*size); + address_space *tspace = &space; + if (apply_translation) { // mask against the logical byte mask address &= space.logaddrmask(); // translate if necessary; if not mapped, return 0xffffffffffffffff - if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace)) return result; } // otherwise, call the reading function for the translated address switch (size) { - case 1: result = space.read_byte(address); break; - case 2: result = space.read_word_unaligned(address); break; - case 4: result = space.read_dword_unaligned(address); break; - case 8: result = space.read_qword_unaligned(address); break; + case 1: result = tspace->read_byte(address); break; + case 2: result = tspace->read_word_unaligned(address); break; + case 4: result = tspace->read_dword_unaligned(address); break; + case 8: result = tspace->read_qword_unaligned(address); break; } return result; } @@ -511,23 +513,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo void symbol_table::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation) { + address_space *tspace = &space; + if (apply_translation) { // mask against the logical byte mask address &= space.logaddrmask(); // translate if necessary; if not mapped, we're done - if (!space.device().memory().translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) + if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_WRITE, address, tspace)) return; } // otherwise, call the writing function for the translated address switch (size) { - case 1: space.write_byte(address, data); break; - case 2: space.write_word_unaligned(address, data); break; - case 4: space.write_dword_unaligned(address, data); break; - case 8: space.write_qword_unaligned(address, data); break; + case 1: tspace->write_byte(address, data); break; + case 2: tspace->write_word_unaligned(address, data); break; + case 4: tspace->write_dword_unaligned(address, data); break; + case 8: tspace->write_qword_unaligned(address, data); break; } notify_memory_modified(); @@ -1736,7 +1740,7 @@ void parsed_expression::infix_to_postfix() else if (token->is_operator()) { // normalize the operator based on neighbors - normalize_operator(*token, prev, next != m_tokenlist.end() ? &*next : nullptr, stack, was_rparen); + normalize_operator(*token, prev, next != origlist.end() ? &*next : nullptr, stack, was_rparen); was_rparen = false; // if the token is an opening parenthesis, push it onto the stack. diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index 23284193f47..251d8b4365c 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -86,17 +86,19 @@ public: }; // construction/destruction - expression_error(error_code code, int offset = 0, int num = 0) - : m_code(code), - m_offset(offset), - m_num(num) { } + constexpr expression_error(error_code code, int offset = 0, int num = 0) + : m_code(code) + , m_offset(offset) + , m_num(num) + { + } // operators - operator error_code() const { return m_code; } + constexpr operator error_code() const { return m_code; } // getters - error_code code() const { return m_code; } - int offset() const { return m_offset; } + constexpr error_code code() const { return m_code; } + constexpr int offset() const { return m_offset; } std::string code_string() const; private: @@ -175,15 +177,16 @@ public: // getters const std::unordered_map<std::string, std::unique_ptr<symbol_entry>> &entries() const { return m_symlist; } symbol_table *parent() const { return m_parent; } + running_machine &machine() { return m_machine; } // setters void set_memory_modified_func(memory_modified_func modified); // symbol access - void add(const char *name, read_write rw, u64 *ptr = nullptr); - void add(const char *name, u64 constvalue); - void add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = ""); - void add(const char *name, int minparams, int maxparams, execute_func execute); + symbol_entry &add(const char *name, read_write rw, u64 *ptr = nullptr); + symbol_entry &add(const char *name, u64 constvalue); + symbol_entry &add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = ""); + symbol_entry &add(const char *name, int minparams, int maxparams, execute_func execute); symbol_entry *find(const char *name) const { if (name) { auto search = m_symlist.find(name); if (search != m_symlist.end()) return search->second.get(); else return nullptr; } else return nullptr; } symbol_entry *find_deep(const char *name); diff --git a/src/emu/debug/points.cpp b/src/emu/debug/points.cpp index c44bc3f7563..961488eebb2 100644 --- a/src/emu/debug/points.cpp +++ b/src/emu/debug/points.cpp @@ -22,18 +22,19 @@ // debug_breakpoint - constructor //------------------------------------------------- -debug_breakpoint::debug_breakpoint(device_debug* debugInterface, - symbol_table &symbols, - int index, - offs_t address, - const char *condition, - const char *action) - : m_debugInterface(debugInterface), - m_index(index), - m_enabled(true), - m_address(address), - m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : "") +debug_breakpoint::debug_breakpoint( + device_debug *debugInterface, + symbol_table &symbols, + int index, + offs_t address, + const char *condition, + std::string_view action) : + m_debugInterface(debugInterface), + m_index(index), + m_enabled(true), + m_address(address), + m_condition(symbols, condition ? condition : "1"), + m_action(action) { } @@ -59,7 +60,7 @@ bool debug_breakpoint::hit(offs_t pc) { return (m_condition.execute() != 0); } - catch (expression_error &) + catch (expression_error const &) { return false; } @@ -78,27 +79,28 @@ bool debug_breakpoint::hit(offs_t pc) // debug_watchpoint - constructor //------------------------------------------------- -debug_watchpoint::debug_watchpoint(device_debug* debugInterface, - symbol_table &symbols, - int index, - address_space &space, - read_or_write type, - offs_t address, - offs_t length, - const char *condition, - const char *action) - : m_debugInterface(debugInterface), - m_phr(nullptr), - m_phw(nullptr), - m_space(space), - m_index(index), - m_enabled(true), - m_type(type), - m_address(address & space.addrmask()), - m_length(length), - m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : ""), - m_installing(false) +debug_watchpoint::debug_watchpoint( + device_debug* debugInterface, + symbol_table &symbols, + int index, + address_space &space, + read_or_write type, + offs_t address, + offs_t length, + const char *condition, + std::string_view action) : + m_debugInterface(debugInterface), + m_phr(nullptr), + m_phw(nullptr), + m_space(space), + m_index(index), + m_enabled(true), + m_type(type), + m_address(address & space.addrmask()), + m_length(length), + m_condition(symbols, condition ? condition : "1"), + m_action(action), + m_installing(false) { std::fill(std::begin(m_start_address), std::end(m_start_address), 0); std::fill(std::begin(m_end_address), std::end(m_end_address), 0); @@ -170,21 +172,21 @@ debug_watchpoint::debug_watchpoint(device_debug* debugInterface, } install(read_or_write::READWRITE); - m_notifier = m_space.add_change_notifier([this](read_or_write mode) { - if (m_enabled) - { - install(mode); - } - }); + m_notifier = m_space.add_change_notifier( + [this] (read_or_write mode) + { + if (m_enabled) + { + install(mode); + } + }); } debug_watchpoint::~debug_watchpoint() { - m_space.remove_change_notifier(m_notifier); - if (m_phr) - m_phr->remove(); - if (m_phw) - m_phw->remove(); + m_notifier.reset(); + m_phr.remove(); + m_phw.remove(); } void debug_watchpoint::setEnabled(bool value) @@ -197,10 +199,8 @@ void debug_watchpoint::setEnabled(bool value) else { m_installing = true; - if(m_phr) - m_phr->remove(); - if(m_phw) - m_phw->remove(); + m_phr.remove(); + m_phw.remove(); m_installing = false; } } @@ -211,24 +211,28 @@ void debug_watchpoint::install(read_or_write mode) if (m_installing) return; m_installing = true; - if ((u32(mode) & u32(read_or_write::READ)) && m_phr) - m_phr->remove(); - if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw) - m_phw->remove(); + if (u32(mode) & u32(read_or_write::READ)) + m_phr.remove(); + if (u32(mode) & u32(read_or_write::WRITE)) + m_phw.remove(); std::string name = util::string_format("wp@%x", m_address); switch (m_space.data_width()) { case 8: if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name, - [this](offs_t offset, u8 &data, u8 mem_mask) { - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); + m_phr = m_space.install_read_tap( + m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::READ, offset, data, mem_mask); + }, + &m_phr); if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name, - [this](offs_t offset, u8 &data, u8 mem_mask) { - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); + m_phw = m_space.install_write_tap( + m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, + &m_phw); break; case 16: @@ -237,17 +241,21 @@ void debug_watchpoint::install(read_or_write mode) { u16 mask = m_masks[i]; if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u16 &data, u16 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); + m_phr = m_space.install_read_tap( + m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, + &m_phr); if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u16 &data, u16 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); + m_phw = m_space.install_write_tap( + m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, + &m_phw); } break; @@ -257,17 +265,21 @@ void debug_watchpoint::install(read_or_write mode) { u32 mask = m_masks[i]; if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u32 &data, u32 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); + m_phr = m_space.install_read_tap( + m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, + &m_phr); if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u32 &data, u32 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); + m_phw = m_space.install_write_tap( + m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, + &m_phw); } break; @@ -277,17 +289,20 @@ void debug_watchpoint::install(read_or_write mode) { u64 mask = m_masks[i]; if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u64 &data, u64 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); + m_phr = m_space.install_read_tap( + m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, + &m_phr); if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u64 &data, u64 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, + &m_phw); } break; } @@ -416,11 +431,11 @@ void debug_watchpoint::triggered(read_or_write type, offs_t address, u64 data, u // debug_registerpoint - constructor //------------------------------------------------- -debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action) +debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action) : m_index(index), m_enabled(true), m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : "") + m_action(action) { } @@ -450,3 +465,59 @@ bool debug_registerpoint::hit() return true; } + + +//************************************************************************** +// DEBUG EXCEPTION POINT +//************************************************************************** + +//------------------------------------------------- +// debug_exceptionpoint - constructor +//------------------------------------------------- + +debug_exceptionpoint::debug_exceptionpoint( + device_debug *debugInterface, + symbol_table &symbols, + int index, + int type, + const char *condition, + std::string_view action) + : m_debugInterface(debugInterface), + m_index(index), + m_enabled(true), + m_type(type), + m_condition(symbols, (condition != nullptr) ? condition : "1"), + m_action(action) +{ +} + + +//------------------------------------------------- +// hit - detect a hit +//------------------------------------------------- + +bool debug_exceptionpoint::hit(int exception) +{ + // don't hit if disabled + if (!m_enabled) + return false; + + // must match our type + if (m_type != exception) + return false; + + // must satisfy the condition + if (!m_condition.is_empty()) + { + try + { + return (m_condition.execute() != 0); + } + catch (expression_error &) + { + return false; + } + } + + return true; +} diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h index 84cdad7720b..42abd46398f 100644 --- a/src/emu/debug/points.h +++ b/src/emu/debug/points.h @@ -36,7 +36,7 @@ public: int index, offs_t address, const char *condition = nullptr, - const char *action = nullptr); + std::string_view action = {}); // getters const device_debug *debugInterface() const { return m_debugInterface; } @@ -44,7 +44,7 @@ public: bool enabled() const { return m_enabled; } offs_t address() const { return m_address; } const char *condition() const { return m_condition.original_string(); } - const char *action() const { return m_action.c_str(); } + const std::string &action() const { return m_action; } // setters void setEnabled(bool value) { m_enabled = value; } // FIXME: need to update breakpoint flags but it's a private method @@ -77,7 +77,7 @@ public: offs_t address, offs_t length, const char *condition = nullptr, - const char *action = nullptr); + std::string_view action = {}); ~debug_watchpoint(); // getters @@ -102,8 +102,8 @@ private: void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask); device_debug * m_debugInterface; // the interface we were created from - memory_passthrough_handler *m_phr; // passthrough handler reference, read access - memory_passthrough_handler *m_phw; // passthrough handler reference, write access + memory_passthrough_handler m_phr; // passthrough handler reference, read access + memory_passthrough_handler m_phw; // passthrough handler reference, write access address_space & m_space; // address space int m_index; // user reported index bool m_enabled; // enabled? @@ -112,7 +112,7 @@ private: offs_t m_length; // length of watch area parsed_expression m_condition; // condition std::string m_action; // action - int m_notifier; // address map change notifier id + util::notifier_subscription m_notifier; // address map change notifier ID offs_t m_start_address[3]; // the start addresses of the checks to install offs_t m_end_address[3]; // the end addresses @@ -128,13 +128,13 @@ class debug_registerpoint public: // construction/destruction - debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr); + debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action = {}); // getters int index() const { return m_index; } bool enabled() const { return m_enabled; } const char *condition() const { return m_condition.original_string(); } - const char *action() const { return m_action.c_str(); } + const std::string &action() const { return m_action; } private: // internals @@ -146,4 +146,42 @@ private: std::string m_action; // action }; +// ======================> debug_exceptionpoint + +class debug_exceptionpoint +{ + friend class device_debug; + +public: + // construction/destruction + debug_exceptionpoint( + device_debug* debugInterface, + symbol_table &symbols, + int index, + int type, + const char *condition = nullptr, + std::string_view action = {}); + + // getters + const device_debug *debugInterface() const { return m_debugInterface; } + int index() const { return m_index; } + bool enabled() const { return m_enabled; } + int type() const { return m_type; } + const char *condition() const { return m_condition.original_string(); } + const std::string &action() const { return m_action; } + + // setters + void setEnabled(bool value) { m_enabled = value; } + +private: + // internals + bool hit(int exception); + const device_debug * m_debugInterface; // the interface we were created from + int m_index; // user reported index + bool m_enabled; // enabled? + int m_type; // exception type + parsed_expression m_condition; // condition + std::string m_action; // action +}; + #endif // MAME_EMU_DEBUG_POINTS_H diff --git a/src/emu/devcb.cpp b/src/emu/devcb.cpp index 19970f45c5f..b6e08f13b45 100644 --- a/src/emu/devcb.cpp +++ b/src/emu/devcb.cpp @@ -257,7 +257,6 @@ template class devcb_write8::creator_impl<devcb_write8::latched_inputline_builde template class devcb_write8::creator_impl<devcb_write8::ioport_builder>; template class devcb_write8::creator_impl<devcb_write8::membank_builder>; template class devcb_write8::creator_impl<devcb_write8::output_builder>; -template class devcb_write8::creator_impl<devcb_write8::log_builder>; template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8s_delegate> >; template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >; @@ -277,7 +276,6 @@ template class devcb_write16::creator_impl<devcb_write16::latched_inputline_buil template class devcb_write16::creator_impl<devcb_write16::ioport_builder>; template class devcb_write16::creator_impl<devcb_write16::membank_builder>; template class devcb_write16::creator_impl<devcb_write16::output_builder>; -template class devcb_write16::creator_impl<devcb_write16::log_builder>; template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8s_delegate> >; template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >; @@ -297,7 +295,6 @@ template class devcb_write32::creator_impl<devcb_write32::latched_inputline_buil template class devcb_write32::creator_impl<devcb_write32::ioport_builder>; template class devcb_write32::creator_impl<devcb_write32::membank_builder>; template class devcb_write32::creator_impl<devcb_write32::output_builder>; -template class devcb_write32::creator_impl<devcb_write32::log_builder>; template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8s_delegate> >; template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >; @@ -317,7 +314,6 @@ template class devcb_write64::creator_impl<devcb_write64::latched_inputline_buil template class devcb_write64::creator_impl<devcb_write64::ioport_builder>; template class devcb_write64::creator_impl<devcb_write64::membank_builder>; template class devcb_write64::creator_impl<devcb_write64::output_builder>; -template class devcb_write64::creator_impl<devcb_write64::log_builder>; template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8s_delegate> >; template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >; @@ -337,11 +333,11 @@ template class devcb_write_line::creator_impl<devcb_write_line::latched_inputlin template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>; template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>; template class devcb_write_line::creator_impl<devcb_write_line::output_builder>; -template class devcb_write_line::creator_impl<devcb_write_line::log_builder>; devcb_base::devcb_base(device_t &owner) - : m_owner(owner) + : device_resolver_base(owner) + , m_owner(owner) { } diff --git a/src/emu/devcb.h b/src/emu/devcb.h index d27d3beb74d..be62d8b6365 100644 --- a/src/emu/devcb.h +++ b/src/emu/devcb.h @@ -64,11 +64,8 @@ template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write_ /// /// Provides utilities for supporting multiple read/write/transform /// signatures, and the base exclusive-or/mask transform methods. -class devcb_base +class devcb_base : protected device_resolver_base { -public: - virtual void validity_check(validity_checker &valid) const = 0; - protected: // This is in C++17 but not C++14 template <typename... T> struct void_wrapper { using type = void; }; @@ -82,16 +79,10 @@ protected: template <typename T, typename U> using mask_t = std::make_unsigned_t<intermediate_t<T, U> >; // Detecting candidates for transform functions - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form1 : public std::false_type { }; - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form2 : public std::false_type { }; - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form3 : public std::false_type { }; - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form4 : public std::false_type { }; - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form5 : public std::false_type { }; - template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form6 : public std::false_type { }; - template <typename Input, typename Result, typename Func> struct is_transform_form3<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input, std::make_unsigned_t<Input> &>, Result>::value> > : public std::true_type { }; - template <typename Input, typename Result, typename Func> struct is_transform_form4<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input>, Result>::value> > : public std::true_type { }; - template <typename Input, typename Result, typename Func> struct is_transform_form6<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, Input>, Result>::value> > : public std::true_type { }; - template <typename Input, typename Result, typename Func> struct is_transform : public std::bool_constant<is_transform_form1<Input, Result, Func>::value || is_transform_form2<Input, Result, Func>::value || is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form5<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value> { }; + template <typename Input, typename Result, typename Func> using is_transform_form3 = std::is_invocable_r<Result, Func, offs_t &, Input, std::make_unsigned_t<Input> &>; + template <typename Input, typename Result, typename Func> using is_transform_form4 = std::is_invocable_r<Result, Func, offs_t &, Input>; + template <typename Input, typename Result, typename Func> using is_transform_form6 = std::is_invocable_r<Result, Func, Input>; + template <typename Input, typename Result, typename Func> using is_transform = std::bool_constant<is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value>; // Determining the result type of a transform function template <typename Input, typename Result, typename Func, typename Enable = void> struct transform_result; @@ -137,12 +128,18 @@ protected: auto rshift(unsigned val) { auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask >>= val; return data >> val; })); - return inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask >> val)); + if (inherited_mask()) + return trans; + else + return std::move(trans.mask(m_mask >> val)); } auto lshift(unsigned val) { auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask <<= val; return data << val; })); - return inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask << val)); + if (inherited_mask()) + return trans; + else + return std::move(trans.mask(m_mask << val)); } auto bit(unsigned val) { return std::move(rshift(val).mask(T(1U))); } @@ -174,9 +171,9 @@ protected: class array : public std::array<T, Count> { private: - template <unsigned... V> - array(device_t &owner, std::integer_sequence<unsigned, V...> const &) - : std::array<T, Count>{{ { make_one<V>(owner) }... }} + template <unsigned... V, typename... Params> + array(device_t &owner, std::integer_sequence<unsigned, V...>, Params &&... args) + : std::array<T, Count>{{ { make_one<V>(owner), std::forward<Params>(args)... }... }} { } @@ -185,12 +182,10 @@ protected: public: using std::array<T, Count>::array; - array(device_t &owner) : array(owner, std::make_integer_sequence<unsigned, Count>()) { } - - void resolve_all() + template <typename... Params> + array(device_t &owner, Params &&... args) + : array(owner, std::make_integer_sequence<unsigned, Count>(), std::forward<Params>(args)...) { - for (T &elem : *this) - elem.resolve(); } }; @@ -211,13 +206,10 @@ class devcb_read_base : public devcb_base { protected: // Detecting candidates for read functions - template <typename Result, typename Func, typename Enable = void> struct is_read_form1 : public std::false_type { }; - template <typename Result, typename Func, typename Enable = void> struct is_read_form2 : public std::false_type { }; - template <typename Result, typename Func, typename Enable = void> struct is_read_form3 : public std::false_type { }; - template <typename Result, typename Func> struct is_read_form1<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t, Result>, Result>::value> > : public std::true_type { }; - template <typename Result, typename Func> struct is_read_form2<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t>, Result>::value> > : public std::true_type { }; - template <typename Result, typename Func> struct is_read_form3<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func>, Result>::value> > : public std::true_type { }; - template <typename Result, typename Func> struct is_read : public std::bool_constant<is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value> { }; + template <typename Result, typename Func> using is_read_form1 = std::is_invocable_r<Result, Func, offs_t, Result>; + template <typename Result, typename Func> using is_read_form2 = std::is_invocable_r<Result, Func, offs_t>; + template <typename Result, typename Func> using is_read_form3 = std::is_invocable_r<Result, Func>; + template <typename Result, typename Func> using is_read = std::bool_constant<is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value>; // Determining the result type of a read function template <typename Result, typename Func, typename Enable = void> struct read_result; @@ -275,13 +267,10 @@ class devcb_write_base : public devcb_base { protected: // Detecting candidates for write functions - template <typename Input, typename Func, typename Enable = void> struct is_write_form1 : public std::false_type { }; - template <typename Input, typename Func, typename Enable = void> struct is_write_form2 : public std::false_type { }; - template <typename Input, typename Func, typename Enable = void> struct is_write_form3 : public std::false_type { }; - template <typename Input, typename Func> struct is_write_form1<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input, std::make_unsigned_t<Input>> > > : public std::true_type { }; - template <typename Input, typename Func> struct is_write_form2<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input> > > : public std::true_type { }; - template <typename Input, typename Func> struct is_write_form3<Input, Func, void_t<std::invoke_result_t<Func, Input> > > : public std::true_type { }; - template <typename Input, typename Func> struct is_write : public std::bool_constant<is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value> { }; + template <typename Input, typename Func> using is_write_form1 = std::is_invocable<Func, offs_t, Input, std::make_unsigned_t<Input> >; + template <typename Input, typename Func> using is_write_form2 = std::is_invocable<Func, offs_t, Input>; + template <typename Input, typename Func> using is_write_form3 = std::is_invocable<Func, Input>; + template <typename Input, typename Func> using is_write = std::bool_constant<is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value>; // Detecting candidates for write delegates template <typename T, typename Enable = void> struct is_write_method : public std::false_type { }; @@ -342,7 +331,7 @@ private: using ptr = std::unique_ptr<creator>; virtual ~creator() { } - virtual void validity_check(validity_checker &valid) const = 0; + virtual bool validity_check(validity_checker &valid) const = 0; virtual func_t create() = 0; std::make_unsigned_t<Result> mask() const { return m_mask; } @@ -359,7 +348,7 @@ private: public: creator_impl(T &&builder) : creator(builder.mask()), m_builder(std::move(builder)) { } - virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); } + virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); } virtual func_t create() override { @@ -372,28 +361,6 @@ private: T m_builder; }; - class log_creator : public creator - { - public: - log_creator(device_t &devbase, std::string &&message) : creator(0U), m_devbase(devbase), m_message(std::move(message)) { } - - virtual void validity_check(validity_checker &valid) const override { } - - virtual func_t create() override - { - return - [&devbase = m_devbase, message = std::move(m_message)] (offs_t offset, std::make_unsigned_t<Result> mem_mask) - { - devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); - return Result(0); - }; - } - - private: - device_t &m_devbase; - std::string m_message; - }; - template <typename Source, typename Func> class transform_builder; // workaround for MSVC class builder_base @@ -473,7 +440,7 @@ private: return transform_builder<transform_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m); } - void validity_check(validity_checker &valid) const { m_src.validity_check(valid); } + bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); } template <typename T> void build(T &&chain) @@ -494,7 +461,7 @@ private: assert(this->m_consumed); this->built(); chain( - [src = std::forward<U>(f), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_mask_t &mem_mask) + [src = std::forward<U>(f), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_mask_t &mem_mask) { typename Source::input_mask_t source_mask(mem_mask); auto const data(src(offset, source_mask)); @@ -541,7 +508,7 @@ private: return transform_builder<functoid_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } template <typename T> void build(T &&chain) @@ -549,7 +516,7 @@ private: assert(this->m_consumed); this->built(); chain( - [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) + [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) { return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; }); } @@ -601,11 +568,15 @@ private: return transform_builder<delegate_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { auto const target(m_delegate.finder_target()); if (target.second && !target.first.subdevice(target.second)) + { osd_printf_error("Read callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } template <typename T> @@ -615,7 +586,7 @@ private: this->built(); m_delegate.resolve(); chain( - [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) + [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask) { return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; }); } @@ -661,7 +632,7 @@ private: return transform_builder<ioport_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } template <typename T> void build(T &&chain) @@ -722,6 +693,13 @@ private: return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_read::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name); } + template <typename T> + std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name); + } + template <typename T, typename U, bool R> std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name) { @@ -775,40 +753,6 @@ private: return set_ioport(std::forward<Params>(args)...); } - template <typename... Params> - void set_log(device_t &devbase, Params &&... args) - { - set_used(); - if (!m_append) - m_target.m_creators.clear(); - m_target.m_creators.emplace_back(std::make_unique<log_creator>(devbase, std::string(std::forward<Params>(args)...))); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args) - { - set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args) - { - set_log(devbase.device(), std::forward<Params>(args)...); - } - - template <typename... Params> - void set_log(Params &&... args) - { - set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...); - } - - template <typename... Params> - void append_log(Params &&... args) - { - m_append = true; - set_log(std::forward<Params>(args)...); - } - auto set_constant(Result val) { return set([val] () { return val; }); } auto append_constant(Result val) { return append([val] () { return val; }); } @@ -822,47 +766,46 @@ private: std::vector<func_t> m_functions; std::vector<typename creator::ptr> m_creators; + Result const m_default; + bool m_unset = false; + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; public: template <unsigned Count> class array : public devcb_read_base::array<devcb_read<Result, DefaultMask>, Count> { public: - using devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array; - - void resolve_all_safe(Result dflt) + array(device_t &owner, Result dflt) + : devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array(owner, dflt) { - for (devcb_read<Result, DefaultMask> &elem : *this) - elem.resolve_safe(dflt); } }; - devcb_read(device_t &owner); + devcb_read(device_t &owner, Result dflt); binder bind(); void reset(); - virtual void validity_check(validity_checker &valid) const override; - - void resolve(); - void resolve_safe(Result dflt); - Result operator()(offs_t offset, std::make_unsigned_t<Result> mem_mask = DefaultMask); Result operator()(); - bool isnull() const { return m_functions.empty() && m_creators.empty(); } - explicit operator bool() const { return !m_functions.empty(); } + bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); } }; template <typename Result, std::make_unsigned_t<Result> DefaultMask> -devcb_read<Result, DefaultMask>::devcb_read(device_t &owner) +devcb_read<Result, DefaultMask>::devcb_read(device_t &owner, Result dflt) : devcb_read_base(owner) + , m_default(dflt & DefaultMask) { } template <typename Result, std::make_unsigned_t<Result> DefaultMask> typename devcb_read<Result, DefaultMask>::binder devcb_read<Result, DefaultMask>::bind() { + assert(m_functions.empty()); return binder(*this); } @@ -874,38 +817,48 @@ void devcb_read<Result, DefaultMask>::reset() } template <typename Result, std::make_unsigned_t<Result> DefaultMask> -void devcb_read<Result, DefaultMask>::validity_check(validity_checker &valid) const +bool devcb_read<Result, DefaultMask>::findit(validity_checker *valid) { assert(m_functions.empty()); - for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i) + if (!valid) { - (*i)->validity_check(valid); - std::make_unsigned_t<Result> const m((*i)->mask()); - for (typename std::vector<typename creator::ptr>::const_iterator j = std::next(i); m_creators.end() != j; ++j) + // FIXME: report errors by returning false rather than throwing fatal errors + m_functions.reserve(m_creators.size()); + for (typename creator::ptr const &c : m_creators) + m_functions.emplace_back(c->create()); + m_creators.clear(); + if (m_functions.empty()) { - std::make_unsigned_t<Result> const n((*j)->mask()); - if (m & n) - osd_printf_error("Read callback masks %lX and %lX overlap\n", static_cast<unsigned long>(m), static_cast<unsigned long>(n)); // FIXME: doesn't work with u64 + m_functions.emplace_back([dflt = m_default] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; }); + m_unset = true; } + return true; + } + else + { + bool success(true); + for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i) + { + if (!(*i)->validity_check(*valid)) + success = false; + std::make_unsigned_t<Result> const m((*i)->mask()); + for (typename std::vector<typename creator::ptr>::const_iterator j = std::next(i); m_creators.end() != j; ++j) + { + std::make_unsigned_t<Result> const n((*j)->mask()); + if (m & n) + { + osd_printf_error("Read callback masks 0x%X and 0x%X overlap\n", m, n); + success = false; + } + } + } + return success; } } template <typename Result, std::make_unsigned_t<Result> DefaultMask> -void devcb_read<Result, DefaultMask>::resolve() -{ - assert(m_functions.empty()); - m_functions.reserve(m_creators.size()); - for (typename creator::ptr const &c : m_creators) - m_functions.emplace_back(c->create()); - m_creators.clear(); -} - -template <typename Result, std::make_unsigned_t<Result> DefaultMask> -void devcb_read<Result, DefaultMask>::resolve_safe(Result dflt) +void devcb_read<Result, DefaultMask>::end_configuration() { - resolve(); - if (m_functions.empty()) - m_functions.emplace_back([dflt] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; }); } template <typename Result, std::make_unsigned_t<Result> DefaultMask> @@ -943,7 +896,7 @@ private: using ptr = std::unique_ptr<creator>; virtual ~creator() { } - virtual void validity_check(validity_checker &valid) const = 0; + virtual bool validity_check(validity_checker &valid) const = 0; virtual func_t create() = 0; }; @@ -953,7 +906,7 @@ private: public: creator_impl(T &&builder) : m_builder(std::move(builder)) { } - virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); } + virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); } virtual func_t create() override { @@ -967,7 +920,7 @@ private: class nop_creator : public creator { public: - virtual void validity_check(validity_checker &valid) const override { } + virtual bool validity_check(validity_checker &valid) const override { return true; } virtual func_t create() override { return [] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }; } }; @@ -1066,7 +1019,7 @@ private: }); } - void validity_check(validity_checker &valid) const { m_src.validity_check(valid); } + bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); } private: transform_builder(transform_builder const &) = delete; @@ -1079,7 +1032,7 @@ private: assert(this->m_consumed); this->built(); return m_src.build( - [f = std::move(chain), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask) + [f = std::move(chain), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask) { auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, offset, data, mem_mask)); output_t out_mask(mem_mask & mask); @@ -1123,7 +1076,7 @@ private: } ~first_transform_builder() { this->template register_creator<first_transform_builder>(); } - void validity_check(validity_checker &valid) const { m_sink.validity_check(valid); } + bool validity_check(validity_checker &valid) const { return m_sink.validity_check(valid); } template <typename T> std::enable_if_t<is_transform<output_t, output_t, T>::value, transform_builder<first_transform_builder, std::remove_reference_t<T> > > transform(T &&cb) @@ -1139,7 +1092,7 @@ private: assert(this->m_consumed); this->built(); return - [sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { data = (data ^ in_exor) & in_mask; mem_mask &= in_mask; @@ -1160,7 +1113,7 @@ private: assert(this->m_consumed); this->built(); return - [f = std::move(chain), sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [f = std::move(chain), sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { data = (data ^ in_exor) & in_mask; mem_mask &= in_mask; @@ -1190,14 +1143,14 @@ private: wrapped_builder(functoid_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); } wrapped_builder(wrapped_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); return - [cb = std::move(this->m_cb)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [cb = std::move(m_cb)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); }; } @@ -1240,14 +1193,14 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { assert(this->m_consumed); this->built(); return - [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); }; } }; @@ -1278,11 +1231,15 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { auto const target(m_delegate.finder_target()); if (target.second && !target.first.subdevice(target.second)) + { osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } auto build() @@ -1291,7 +1248,7 @@ private: this->built(); m_delegate.resolve(); return - [cb = std::move(this->m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [cb = std::move(m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); }; } @@ -1344,11 +1301,15 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), in_mask, out_mask); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { auto const target(m_delegate.finder_target()); if (target.second && !target.first.subdevice(target.second)) + { osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name()); + return false; + } + return true; } auto build() @@ -1357,7 +1318,7 @@ private: this->built(); m_delegate.resolve(); return - [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) + [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) { devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); }; } }; @@ -1393,16 +1354,23 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { if (!m_exec) { device_t *const device(m_devbase.subdevice(m_tag)); if (!device) + { osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag); + return false; + } else if (!dynamic_cast<device_execute_interface *>(device)) + { osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name()); + return false; + } } + return true; } auto build() @@ -1484,16 +1452,23 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), in_mask, 1U); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { if (!m_exec) { device_t *const device(m_devbase.subdevice(m_tag)); if (!device) + { osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag); + return false; + } else if (!dynamic_cast<device_execute_interface *>(device)) + { osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name()); + return false; + } } + return true; } auto build() @@ -1548,16 +1523,23 @@ private: that.built(); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { if (!m_exec) { device_t *const device(m_devbase.subdevice(m_tag)); if (!device) + { osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag); + return false; + } else if (!dynamic_cast<device_execute_interface *>(device)) + { osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name()); + return false; + } } + return true; } auto build() @@ -1643,16 +1625,23 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); } - void validity_check(validity_checker &valid) const + bool validity_check(validity_checker &valid) const { if (!m_exec) { device_t *const device(m_devbase.subdevice(m_tag)); if (!device) + { osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag); + return false; + } else if (!dynamic_cast<device_execute_interface *>(device)) + { osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name()); + return false; + } } + return true; } auto build() @@ -1701,7 +1690,7 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1759,7 +1748,7 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1801,7 +1790,7 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1859,7 +1848,7 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1901,7 +1890,7 @@ private: that.built(); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1956,7 +1945,7 @@ private: return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); } - void validity_check(validity_checker &valid) const { } + bool validity_check(validity_checker &valid) const { return true; } auto build() { @@ -1968,99 +1957,6 @@ private: } }; - class log_builder : public builder_base, public transform_base<std::make_unsigned_t<Input>, log_builder> - { - private: - class wrapped_builder : public builder_base - { - public: - template <typename T, typename U> friend class first_transform_builder; - - using input_t = Input; - - wrapped_builder(log_builder &&that) - : builder_base(std::move(that)) - , m_devbase(that.m_devbase) - , m_message(std::move(that.m_message)) - { - that.consume(); - that.built(); - } - wrapped_builder(wrapped_builder &&that) - : builder_base(std::move(that)) - , m_devbase(that.m_devbase) - , m_message(std::move(that.m_message)) - { - that.consume(); - that.built(); - } - - void validity_check(validity_checker &valid) const { } - - auto build() - { - assert(this->m_consumed); - this->built(); - return - [&devbase = m_devbase, message = std::move(m_message)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) - { if (data) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); }; - } - - private: - wrapped_builder(wrapped_builder const &) = delete; - wrapped_builder operator=(wrapped_builder const &) = delete; - wrapped_builder operator=(wrapped_builder &&that) = delete; - - device_t &m_devbase; - std::string m_message; - }; - - friend class wrapped_builder; // workaround for MSVC - - log_builder(log_builder const &) = delete; - log_builder &operator=(log_builder const &) = delete; - log_builder &operator=(log_builder &&that) = delete; - - device_t &m_devbase; - std::string m_message; - - public: - using input_t = Input; - - log_builder(devcb_write &target, bool append, device_t &devbase, std::string &&message) - : builder_base(target, append) - , transform_base<std::make_unsigned_t<Input>, log_builder>(DefaultMask) - , m_devbase(devbase) - , m_message(std::move(message)) - { } - log_builder(log_builder &&that) - : builder_base(std::move(that)) - , transform_base<std::make_unsigned_t<Input>, log_builder>(std::move(that)) - , m_devbase(that.m_devbase) - , m_message(std::move(that.m_message)) - { - that.consume(); - that.built(); - } - ~log_builder() { this->template register_creator<log_builder>(); } - - template <typename T> - std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb) - { - return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask); - } - - void validity_check(validity_checker &valid) const { } - - auto build() - { - assert(this->m_consumed); - this->built(); - return - [&devbase = m_devbase, message = std::move(m_message), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask) - { if ((data ^ exor) & mask) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); }; - } - }; class binder { public: @@ -2098,6 +1994,13 @@ private: return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_write::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name); } + template <typename T> + std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name) + { + set_used(); + return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name); + } + template <typename T, typename U, bool R> std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name) { @@ -2242,38 +2145,6 @@ private: return set_output(std::forward<Params>(args)...); } - template <typename... Params> - log_builder set_log(device_t &devbase, Params &&... args) - { - set_used(); - return log_builder(m_target, m_append, devbase, std::string(std::forward<Params>(args)...)); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args) - { - return set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...); - } - - template <typename T, typename... Params> - std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args) - { - return set_log(devbase.device(), std::forward<Params>(args)...); - } - - template <typename... Params> - log_builder set_log(Params &&... args) - { - return set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...); - } - - template <typename... Params> - log_builder append_log(Params &&... args) - { - m_append = true; - return set_log(std::forward<Params>(args)...); - } - void set_nop() { set_used(); @@ -2291,18 +2162,20 @@ private: std::vector<func_t> m_functions; std::vector<typename creator::ptr> m_creators; + bool m_unset = false; + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; public: template <unsigned Count> class array : public devcb_write_base::array<devcb_write<Input, DefaultMask>, Count> { public: - using devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array; - - void resolve_all_safe() + array(device_t &owner) + : devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array(owner) { - for (devcb_write<Input, DefaultMask> &elem : *this) - elem.resolve_safe(); } }; @@ -2311,16 +2184,10 @@ public: binder bind(); void reset(); - virtual void validity_check(validity_checker &valid) const override; - - void resolve(); - void resolve_safe(); - void operator()(offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask = DefaultMask); void operator()(Input data); - bool isnull() const { return m_functions.empty() && m_creators.empty(); } - explicit operator bool() const { return !m_functions.empty(); } + bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); } }; template <typename Input, std::make_unsigned_t<Input> DefaultMask> @@ -2332,6 +2199,7 @@ devcb_write<Input, DefaultMask>::devcb_write(device_t &owner) template <typename Input, std::make_unsigned_t<Input> DefaultMask> typename devcb_write<Input, DefaultMask>::binder devcb_write<Input, DefaultMask>::bind() { + assert(m_functions.empty()); return binder(*this); } @@ -2343,29 +2211,38 @@ void devcb_write<Input, DefaultMask>::reset() } template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::validity_check(validity_checker &valid) const -{ - assert(m_functions.empty()); - for (typename creator::ptr const &c : m_creators) - c->validity_check(valid); -} - -template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::resolve() +bool devcb_write<Input, DefaultMask>::findit(validity_checker *valid) { assert(m_functions.empty()); - m_functions.reserve(m_creators.size()); - for (typename creator::ptr const &c : m_creators) - m_functions.emplace_back(c->create()); - m_creators.clear(); + if (!valid) + { + // FIXME: report errors by returning false rather than throwing fatal errors + m_functions.reserve(m_creators.size()); + for (typename creator::ptr const &c : m_creators) + m_functions.emplace_back(c->create()); + m_creators.clear(); + if (m_functions.empty()) + { + m_functions.emplace_back([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }); + m_unset = true; + } + return true; + } + else + { + bool success(true); + for (typename creator::ptr const &c : m_creators) + { + if (!c->validity_check(*valid)) + success = false; + } + return success; + } } template <typename Input, std::make_unsigned_t<Input> DefaultMask> -void devcb_write<Input, DefaultMask>::resolve_safe() +void devcb_write<Input, DefaultMask>::end_configuration() { - resolve(); - if (m_functions.empty()) - m_functions.emplace_back([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }); } template <typename Input, std::make_unsigned_t<Input> DefaultMask> @@ -2646,7 +2523,6 @@ extern template class devcb_write8::creator_impl<devcb_write8::latched_inputline extern template class devcb_write8::creator_impl<devcb_write8::ioport_builder>; extern template class devcb_write8::creator_impl<devcb_write8::membank_builder>; extern template class devcb_write8::creator_impl<devcb_write8::output_builder>; -extern template class devcb_write8::creator_impl<devcb_write8::log_builder>; extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8s_delegate> >; extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >; @@ -2666,7 +2542,6 @@ extern template class devcb_write16::creator_impl<devcb_write16::latched_inputli extern template class devcb_write16::creator_impl<devcb_write16::ioport_builder>; extern template class devcb_write16::creator_impl<devcb_write16::membank_builder>; extern template class devcb_write16::creator_impl<devcb_write16::output_builder>; -extern template class devcb_write16::creator_impl<devcb_write16::log_builder>; extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8s_delegate> >; extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >; @@ -2686,7 +2561,6 @@ extern template class devcb_write32::creator_impl<devcb_write32::latched_inputli extern template class devcb_write32::creator_impl<devcb_write32::ioport_builder>; extern template class devcb_write32::creator_impl<devcb_write32::membank_builder>; extern template class devcb_write32::creator_impl<devcb_write32::output_builder>; -extern template class devcb_write32::creator_impl<devcb_write32::log_builder>; extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8s_delegate> >; extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >; @@ -2706,7 +2580,6 @@ extern template class devcb_write64::creator_impl<devcb_write64::latched_inputli extern template class devcb_write64::creator_impl<devcb_write64::ioport_builder>; extern template class devcb_write64::creator_impl<devcb_write64::membank_builder>; extern template class devcb_write64::creator_impl<devcb_write64::output_builder>; -extern template class devcb_write64::creator_impl<devcb_write64::log_builder>; extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8s_delegate> >; extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >; @@ -2726,6 +2599,5 @@ extern template class devcb_write_line::creator_impl<devcb_write_line::latched_i extern template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>; extern template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>; extern template class devcb_write_line::creator_impl<devcb_write_line::output_builder>; -extern template class devcb_write_line::creator_impl<devcb_write_line::log_builder>; #endif // MAME_EMU_DEVCB_H diff --git a/src/emu/devcpu.cpp b/src/emu/devcpu.cpp index 03df7990a3d..efd12d682a9 100644 --- a/src/emu/devcpu.cpp +++ b/src/emu/devcpu.cpp @@ -27,7 +27,9 @@ cpu_device::cpu_device(const machine_config &mconfig, device_type type, const ch device_memory_interface(mconfig, *this), device_state_interface(mconfig, *this), device_disasm_interface(mconfig, *this), - m_force_no_drc(false) + m_force_no_drc(false), + m_access_to_be_redone(false), + m_access_before_delay_tag(nullptr) { } @@ -49,3 +51,55 @@ bool cpu_device::allow_drc() const { return mconfig().options().drc() && !m_force_no_drc; } + + + +bool cpu_device::cpu_is_interruptible() const +{ + return false; +} + +bool cpu_device::access_before_time(u64 access_time, u64 current_time) noexcept +{ + s32 delta = access_time - current_time; + if(*m_icountptr <= delta) { + if(*m_icountptr > 0) + *m_icountptr = 0; + m_access_to_be_redone = true; + return true; + } + + *m_icountptr -= delta; + + return false; +} + +bool cpu_device::access_before_delay(u32 cycles, const void *tag) noexcept +{ + if(tag == m_access_before_delay_tag) { + m_access_before_delay_tag = nullptr; + return false; + } + + *m_icountptr -= cycles; + + if(*m_icountptr <= 0) { + m_access_before_delay_tag = tag; + m_access_to_be_redone = true; + return true; + } + + m_access_before_delay_tag = nullptr; + return false; +} + +void cpu_device::access_after_delay(u32 cycles) noexcept +{ + *m_icountptr -= cycles; +} + +void cpu_device::defer_access() noexcept +{ + m_access_to_be_redone = true; + *m_icountptr = 0; +} diff --git a/src/emu/devcpu.h b/src/emu/devcpu.h index 6e9251ab3a9..70f7b1667a5 100644 --- a/src/emu/devcpu.h +++ b/src/emu/devcpu.h @@ -16,6 +16,8 @@ #include "didisasm.h" #include "diexec.h" +#include <utility> + //************************************************************************** // TYPE DEFINITIONS @@ -36,6 +38,20 @@ public: void set_force_no_drc(bool value) { m_force_no_drc = value; } bool allow_drc() const; + virtual bool cpu_is_interruptible() const; + + // To be used only for interruptible cpus + bool access_to_be_redone() noexcept { return std::exchange(m_access_to_be_redone, false); } + bool access_to_be_redone_noclear() noexcept { return m_access_to_be_redone; } + + // Returns true if the access must be aborted + bool access_before_time(u64 access_time, u64 current_time) noexcept; + bool access_before_delay(u32 cycles, const void *tag) noexcept; + + // The access has already happened, nothing to abort + void access_after_delay(u32 cycles) noexcept; + void defer_access() noexcept; + protected: // construction/destruction cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); @@ -43,6 +59,9 @@ protected: private: // configured state bool m_force_no_drc; // whether or not to force DRC off + + bool m_access_to_be_redone; // whether an access needs to be redone + const void *m_access_before_delay_tag; // if the tag matches on access_before_delay, consider the delay to have already happened }; #endif // MAME_EMU_DEVCPU_H diff --git a/src/emu/devdelegate.h b/src/emu/devdelegate.h index 69381b2576b..3a63c874d92 100644 --- a/src/emu/devdelegate.h +++ b/src/emu/devdelegate.h @@ -21,6 +21,14 @@ #include <utility> +// older versions of libc++ are missing deduction guides that the things using this constructor require +#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 10000) +namespace std { inline namespace __1 { +template<class R, class... ArgTypes > function( R(*)(ArgTypes...) ) -> function<R(ArgTypes...)>; +} } +#endif + + namespace emu { //************************************************************************** @@ -35,41 +43,6 @@ template <typename Signature, unsigned Count> class device_delegate_array; // TYPE DEFINITIONS //************************************************************************** -namespace detail { - -// ======================> device_delegate_helper - -// device_delegate_helper does non-template work -class device_delegate_helper -{ -public: - // accessors - char const *finder_tag() const { return m_tag; } - std::pair<device_t &, char const *> finder_target() const { return std::make_pair(m_base, m_tag); } - -protected: - // construct/assign - device_delegate_helper(device_t &owner, char const *tag = nullptr) : m_base(owner), m_tag(tag) { } - template <class DeviceClass, bool Required> device_delegate_helper(device_finder<DeviceClass, Required> const &finder); - device_delegate_helper(device_delegate_helper const &) = default; - device_delegate_helper &operator=(device_delegate_helper const &) = default; - - // internal helpers - delegate_late_bind &bound_object() const; - void set_tag(device_t &object) { m_base = object; m_tag = nullptr; } - void set_tag(device_t &base, char const *tag) { m_base = base; m_tag = tag; } - void set_tag(char const *tag); - template <class DeviceClass, bool Required> void set_tag(device_finder<DeviceClass, Required> const &finder); - -private: - std::reference_wrapper<device_t> m_base; - char const *m_tag; -}; - -} // namespace detail - - -// ======================> named_delegate template <typename Signature> class named_delegate : public delegate<Signature> { @@ -96,8 +69,8 @@ public: template <typename T> named_delegate(T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name) : basetype(std::forward<T>(funcptr)), m_name(name) { } // allow assignment - named_delegate &operator=(named_delegate const &src) = default; - named_delegate &operator=(named_delegate &&src) = default; + named_delegate &operator=(named_delegate const &) = default; + named_delegate &operator=(named_delegate &&) = default; named_delegate &operator=(std::nullptr_t) noexcept { reset(); return *this; } // getters @@ -107,14 +80,53 @@ public: void reset() noexcept { basetype::reset(); m_name = nullptr; } }; -// ======================> device_delegate +template <class FunctionClass, typename ReturnType, typename... Params> +named_delegate(ReturnType (FunctionClass::*)(Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>; -// device_delegate is a delegate that wraps with a device tag and can be easily -// late bound without replicating logic everywhere -template <typename Signature> class device_delegate; +template <class FunctionClass, typename ReturnType, typename... Params> +named_delegate(ReturnType (FunctionClass::*)(Params...) const, char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>; + +template <class FunctionClass, typename ReturnType, typename... Params> +named_delegate(ReturnType (*)(FunctionClass &, Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>; + + +namespace detail { + +// device_delegate_helper does non-template work + +class device_delegate_helper +{ +public: + // accessors + char const *finder_tag() const { return m_tag; } + std::pair<device_t &, char const *> finder_target() const { return std::make_pair(m_base, m_tag); } + +protected: + // construct/assign + device_delegate_helper(device_t &owner, char const *tag = nullptr) : m_base(owner), m_tag(tag) { } + template <class DeviceClass, bool Required> device_delegate_helper(device_finder<DeviceClass, Required> const &finder); + device_delegate_helper(device_delegate_helper const &) = default; + device_delegate_helper &operator=(device_delegate_helper const &) = default; + + // internal helpers + delegate_late_bind &bound_object() const; + void set_tag(device_t &object) { m_base = object; m_tag = nullptr; } + void set_tag(device_t &base, char const *tag) { m_base = base; m_tag = tag; } + void set_tag(char const *tag); + template <class DeviceClass, bool Required> void set_tag(device_finder<DeviceClass, Required> const &finder); + +private: + std::reference_wrapper<device_t> m_base; + char const *m_tag; +}; + + +// device_delegate_base doesn't need to be specialised on return type + +template <typename Signature> class device_delegate_base; template <typename ReturnType, typename... Params> -class device_delegate<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public detail::device_delegate_helper +class device_delegate_base<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public device_delegate_helper { private: using basetype = named_delegate<ReturnType (Params...)>; @@ -133,77 +145,72 @@ private: template <class T> static std::enable_if_t<is_related_device_interface<T, T>::value, device_t &> get_device(T &object) { return object.device(); } public: - template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>; - - template <typename T> - using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >; - // construct/assign - explicit device_delegate(device_t &owner) : basetype(), detail::device_delegate_helper(owner) { } - device_delegate(device_delegate const &) = default; - device_delegate &operator=(device_delegate const &) = default; + explicit device_delegate_base(device_t &owner) : basetype(), device_delegate_helper(owner) { } + device_delegate_base(device_delegate_base const &) = default; + device_delegate_base &operator=(device_delegate_base const &) = default; // construct with prototype and target - device_delegate(basetype const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { } - device_delegate(device_delegate const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { } + device_delegate_base(basetype const &proto, device_t &object) : basetype(proto, object), device_delegate_helper(object) { } + device_delegate_base(device_delegate_base const &proto, device_t &object) : basetype(proto, object), device_delegate_helper(object) { } // construct with base and tag template <class D> - device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name) + device_delegate_base(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name) : basetype(funcptr, name, static_cast<D *>(nullptr)) - , detail::device_delegate_helper(base, tag) + , device_delegate_helper(base, tag) { } template <class D> - device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name) + device_delegate_base(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name) : basetype(funcptr, name, static_cast<D *>(nullptr)) - , detail::device_delegate_helper(base, tag) + , device_delegate_helper(base, tag) { } template <class D> - device_delegate(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name) + device_delegate_base(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name) : basetype(funcptr, name, static_cast<D *>(nullptr)) - , detail::device_delegate_helper(base, tag) + , device_delegate_helper(base, tag) { } // construct with device finder template <class D, bool R, class E> - device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...), char const *name) + device_delegate_base(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...), char const *name) : basetype(funcptr, name, static_cast<E *>(nullptr)) - , detail::device_delegate_helper(finder) + , device_delegate_helper(finder) { } template <class D, bool R, class E> - device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name) + device_delegate_base(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name) : basetype(funcptr, name, static_cast<E *>(nullptr)) - , detail::device_delegate_helper(finder) + , device_delegate_helper(finder) { } template <class D, bool R, class E> - device_delegate(device_finder<D, R> const &finder, ReturnType (*funcptr)(E &, Params...), char const *name) + device_delegate_base(device_finder<D, R> const &finder, ReturnType (*funcptr)(E &, Params...), char const *name) : basetype(funcptr, name, static_cast<E *>(nullptr)) - , detail::device_delegate_helper(finder) + , device_delegate_helper(finder) { } // construct with target object template <class T, class D> - device_delegate(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) + device_delegate_base(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) : basetype(funcptr, name, static_cast<D *>(&object)) - , detail::device_delegate_helper(get_device(object)) + , device_delegate_helper(get_device(object)) { } template <class T, class D> - device_delegate(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t<is_related_device<D, T>::value, char const *> name) + device_delegate_base(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t<is_related_device<D, T>::value, char const *> name) : basetype(funcptr, name, static_cast<D *>(&object)) - , detail::device_delegate_helper(get_device(object)) + , device_delegate_helper(get_device(object)) { } template <class T, class D> - device_delegate(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) + device_delegate_base(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name) : basetype(funcptr, name, static_cast<D *>(&object)) - , detail::device_delegate_helper(get_device(object)) + , device_delegate_helper(get_device(object)) { } // construct with callable object template <typename T> - device_delegate(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name) + device_delegate_base(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name) : basetype(std::forward<T>(funcptr), name) - , detail::device_delegate_helper(owner) - { basetype::operator=(basetype(std::forward<T>(funcptr), name)); } + , device_delegate_helper(owner) + { } // setters that implicitly bind to the current device template <class D> void set(ReturnType (D::*funcptr)(Params...), char const *name) @@ -239,18 +246,117 @@ public: void reset() { basetype::reset(); set_tag(finder_target().first); } - // perform the binding - void resolve() { if (!basetype::isnull() && !basetype::has_object()) basetype::late_bind(bound_object()); } - // accessors using basetype::operator(); using basetype::isnull; using basetype::has_object; using basetype::name; + + // perform the binding + void resolve() + { + if (!this->isnull() && !this->has_object()) + this->late_bind(bound_object()); + } +}; + +} // namespace detail + + +// device_delegate is a delegate that can be late bound to a device specification + +template <typename Signature> class device_delegate; + +template <typename ReturnType, typename... Params> +class device_delegate<ReturnType (Params...)> : protected detail::device_delegate_base<ReturnType (Params...)> +{ +public: + template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>; + + template <typename T> + using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >; + + // constructors + using detail::device_delegate_base<ReturnType (Params...)>::device_delegate_base; + device_delegate(device_delegate const &) = default; + device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<ReturnType (Params...)>(proto, object) { } + + // assignment + device_delegate &operator=(device_delegate const &) = default; + device_delegate &operator=(std::nullptr_t) { this->reset(); } + + // setters/unsetters + void set(device_delegate const &src) { operator=(src); } + using detail::device_delegate_base<ReturnType (Params...)>::set; + using detail::device_delegate_base<ReturnType (Params...)>::reset; + + // accessors + using detail::device_delegate_base<ReturnType (Params...)>::operator(); + using detail::device_delegate_base<ReturnType (Params...)>::isnull; + using detail::device_delegate_base<ReturnType (Params...)>::has_object; + using detail::device_delegate_base<ReturnType (Params...)>::name; + using detail::device_delegate_base<ReturnType (Params...)>::finder_tag; + using detail::device_delegate_base<ReturnType (Params...)>::finder_target; + + // perform the binding + using detail::device_delegate_base<ReturnType (Params...)>::resolve; + + template <typename T> + void resolve_safe(T &&dflt) + { + if (this->isnull()) + this->set([result = std::decay_t<T>(std::forward<T>(dflt))] (Params...) { return ReturnType(result); }, "default"); + else if (!this->has_object()) + this->late_bind(this->bound_object()); + } +}; + +template <typename... Params> +class device_delegate<void (Params...)> : protected detail::device_delegate_base<void (Params...)> +{ +public: + template <unsigned Count> using array = device_delegate_array<void (Params...), Count>; + + template <typename T> + using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >; + + // constructors + using detail::device_delegate_base<void (Params...)>::device_delegate_base; + device_delegate(device_delegate const &) = default; + device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<void (Params...)>(proto, object) { } + + // assignment + device_delegate &operator=(device_delegate const &) = default; + device_delegate &operator=(std::nullptr_t) { this->reset(); } + + // setters/unsetters + void set(device_delegate const &src) { operator=(src); } + using detail::device_delegate_base<void (Params...)>::set; + using detail::device_delegate_base<void (Params...)>::reset; + + // accessors + using detail::device_delegate_base<void (Params...)>::operator(); + using detail::device_delegate_base<void (Params...)>::isnull; + using detail::device_delegate_base<void (Params...)>::has_object; + using detail::device_delegate_base<void (Params...)>::name; + using detail::device_delegate_base<void (Params...)>::finder_tag; + using detail::device_delegate_base<void (Params...)>::finder_target; + + // perform the binding + using detail::device_delegate_base<void (Params...)>::resolve; + + void resolve_safe() + { + if (this->isnull()) + this->set([] (Params...) { }, "default"); + else if (!this->has_object()) + this->late_bind(this->bound_object()); + } }; // simplifies constructing an array of delegates with a single owner + template <typename Signature, unsigned Count> class device_delegate_array : public std::array<device_delegate<Signature>, Count> { @@ -280,8 +386,42 @@ public: for (device_delegate<Signature> &elem : *this) elem.resolve(); } + + template <typename... T> + void resolve_all_safe(T &&... args) + { + for (device_delegate<Signature> &elem : *this) + elem.resolve_safe(args...); + } }; +template <class D, typename ReturnType, typename... Params> +device_delegate(device_t &, char const *, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>; + +template <class D, typename ReturnType, typename... Params> +device_delegate(device_t &, char const *, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>; + +template <class D, typename ReturnType, typename... Params> +device_delegate(device_t &, char const *, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>; + +template <class D, bool R, class E, typename ReturnType, typename... Params> +device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>; + +template <class D, bool R, class E, typename ReturnType, typename... Params> +device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>; + +template <class D, bool R, class E, typename ReturnType, typename... Params> +device_delegate(device_finder<D, R> const &, ReturnType (*)(E &, Params...), char const *) -> device_delegate<ReturnType (Params...)>; + +template <class T, class D, typename ReturnType, typename... Params> +device_delegate(T &, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>; + +template <class T, class D, typename ReturnType, typename... Params> +device_delegate(T &, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>; + +template <class T, class D, typename ReturnType, typename... Params> +device_delegate(T &, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>; + } // namespace emu diff --git a/src/emu/devfind.cpp b/src/emu/devfind.cpp index d6bc984703e..6170b2fca8c 100644 --- a/src/emu/devfind.cpp +++ b/src/emu/devfind.cpp @@ -18,27 +18,42 @@ // BASE FINDER CLASS //************************************************************************** -constexpr char finder_base::DUMMY_TAG[]; +//------------------------------------------------- +// device_resolver_base - constructor +//------------------------------------------------- + +device_resolver_base::device_resolver_base(device_t &base) + : m_next(base.register_auto_finder(*this)) +{ +} //------------------------------------------------- -// finder_base - constructor +// ~device_resolver_base - destructor //------------------------------------------------- -finder_base::finder_base(device_t &base, char const *tag) - : m_next(base.register_auto_finder(*this)) - , m_base(base) - , m_tag(tag) - , m_resolved(false) +device_resolver_base::~device_resolver_base() { } + +//************************************************************************** +// BASE FINDER CLASS +//************************************************************************** + +constexpr char finder_base::DUMMY_TAG[]; + + //------------------------------------------------- -// ~finder_base - destructor +// finder_base - constructor //------------------------------------------------- -finder_base::~finder_base() +finder_base::finder_base(device_t &base, char const *tag) + : device_resolver_base(base) + , m_base(base) + , m_tag(tag) + , m_resolved(false) { } @@ -50,6 +65,7 @@ finder_base::~finder_base() void finder_base::set_tag(char const *tag) { assert(!m_resolved); + assert(tag); m_base = m_base.get().mconfig().current_device(); m_tag = tag; } diff --git a/src/emu/devfind.h b/src/emu/devfind.h index c8884d9582f..81ebb9f9812 100644 --- a/src/emu/devfind.h +++ b/src/emu/devfind.h @@ -216,21 +216,21 @@ public: /// Abstract non-template base class for object auto-discovery helpers. /// Provides the interface that the device_t uses to manage discovery at /// resolution time. -class finder_base +class device_resolver_base { public: /// \brief Destructor /// /// Destruction via base class pointer and dynamic type behaviour /// are allowed. - virtual ~finder_base(); + virtual ~device_resolver_base(); /// \brief Get next registered object discovery helper /// /// Implementation of basic single-linked list behaviour. /// \return Pointer to the next registered object discovery helper, /// or nullptr if this is the last. - finder_base *next() const { return m_next; } + device_resolver_base *next() const noexcept { return m_next; } /// \brief Attempt discovery /// @@ -254,6 +254,32 @@ public: /// subsequently removes or replaces devices. virtual void end_configuration() = 0; +protected: + /// \brief Designated constructor + /// + /// Construct base object discovery helper and register with device + /// to be invoked at resolution time. + /// \param [in] base Device to register with for resolution. + device_resolver_base(device_t &base); + + + /// \brief Pointer to next registered discovery helper + /// + /// This is a polymorphic class, so it can't be held in a standard + /// list container that requires elements of the same type. Hence + /// it implements basic intrusive single-linked list behaviour. + device_resolver_base *const m_next; +}; + + +/// \brief Base class for object discovery helpers +/// +/// Abstract non-template base class for object auto-discovery helpers. +/// Provides functionality for specifying a target as a base device and +/// relative tag. Also supplies helpers for looking up resources. +class finder_base : protected device_resolver_base +{ +public: /// \brief Get search tag /// /// Returns the search tag. @@ -280,6 +306,7 @@ public: void set_tag(device_t &base, char const *tag) { assert(!m_resolved); + assert(tag); m_base = base; m_tag = tag; } @@ -315,7 +342,9 @@ protected: /// /// Construct base object discovery helper and register with device /// to be invoked at resolution time. - /// \param [in] base Base device to search from. + /// \param [in] base Device to register with for resolution. Also + /// sets initial base device to search from. The tag must be + /// specified relative to this device. /// \param [in] tag Object tag to search for. This is not copied, /// it is the caller's responsibility to ensure this pointer /// remains valid until resolution time. @@ -419,13 +448,6 @@ protected: bool report_missing(bool found, char const *objname, bool required) const; - /// \brief Pointer to next registered discovery helper - /// - /// This is a polymorphic class, so it can't be held in a standard - /// list container that requires elements of the same type. Hence - /// it implements basic intrusive single-linked list behaviour. - finder_base *const m_next; - /// \brief Base device to search from std::reference_wrapper<device_t> m_base; @@ -600,6 +622,12 @@ public: return device; } + /// \brief Look up target during configuration + /// Look up the current target device during configuration, before + /// resolution. + /// \return Pointer to target device if found, or nullptr otherwise. + DeviceClass *lookup() const { return this->m_base.get().template subdevice<DeviceClass>(this->m_tag); } + private: /// \brief Check that device implementation has expected tag /// \param [in] device Reference to device. @@ -1186,6 +1214,33 @@ public: /// been found. size_t bytes() const { return m_bytes; } + /// \brief Get iterator to first element + /// + /// Returns an iterator to the first element of the memory share. + /// \return Iterator to first element. + PointerType *begin() const { return this->m_target; } + + /// \brief Get iterator beyond last element + /// + /// Returns an iterator one past the last element of the memory + /// share. + /// \return Iterator one past last element. + PointerType *end() const { return this->m_target + length(); } + + /// \brief Get constant iterator to first element + /// + /// Returns a constant iterator to the first element of the memory + /// share. + /// \return Constant iterator to first element. + PointerType const *cbegin() const { return this->m_target; } + + /// \brief Get constant iterator beyond last element + /// + /// Returns a constant iterator one past the last element of the + /// memory share. + /// \return Constant iterator one past last element. + PointerType const *cend() const { return this->m_target + length(); } + private: /// \brief Find memory share base pointer /// @@ -1312,6 +1367,34 @@ public: /// \return Memory share width in bytes. u8 bytewidth() const { return m_target->bytewidth(); } + /// \brief Get iterator to first element + /// + /// Returns an iterator to the first element of the memory share. + /// Must not be called before creation is attempted. + /// \return Iterator to first element. + PointerType *begin() const { return target(); } + + /// \brief Get iterator beyond last element + /// + /// Returns an iterator one past the last element of the memory + /// share. Must not be called before creation is attempted. + /// \return Iterator one past last element. + PointerType *end() const { return target() + length(); } + + /// \brief Get constant iterator to first element + /// + /// Returns a constant iterator to the first element of the memory + /// share. Must not be called before creation is attempted. + /// \return Constant iterator to first element. + PointerType const *cbegin() const { return target(); } + + /// \brief Get constant iterator beyond last element + /// + /// Returns a constant iterator one past the last element of the + /// memory share. Must not be called before creation is attempted. + /// \return Constant iterator one past last element. + PointerType const *cend() const { return target() + length(); } + protected: virtual bool findit(validity_checker *valid) override; virtual void end_configuration() override; diff --git a/src/emu/device.cpp b/src/emu/device.cpp index c9097a59d4f..1940c619455 100644 --- a/src/emu/device.cpp +++ b/src/emu/device.cpp @@ -224,7 +224,7 @@ void device_t::add_machine_configuration(machine_config &config) assert(&config == &m_machine_config); machine_config::token const tok(config.begin_configuration(*this)); device_add_mconfig(config); - for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next()) + for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next()) autodev->end_configuration(); } @@ -321,11 +321,7 @@ void device_t::config_complete() void device_t::validity_check(validity_checker &valid) const { - // validate callbacks - for (devcb_base const *callback : m_callbacks) - callback->validity_check(valid); - - // validate via the interfaces + // validate mixins for (device_interface &intf : interfaces()) intf.interface_validity_check(valid); @@ -365,7 +361,7 @@ void device_t::reset() // unscaled clock //------------------------------------------------- -void device_t::set_unscaled_clock(u32 clock) +void device_t::set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain) { // do nothing if no actual change if (clock == m_unscaled_clock) @@ -381,7 +377,7 @@ void device_t::set_unscaled_clock(u32 clock) // if the device has already started, make sure it knows about the new clock if (m_started) - notify_clock_changed(); + notify_clock_changed(sync_on_new_clock_domain); } @@ -460,28 +456,6 @@ u64 device_t::attotime_to_clocks(const attotime &duration) const noexcept //------------------------------------------------- -// timer_alloc - allocate a timer for our device -// callback -//------------------------------------------------- - -emu_timer *device_t::timer_alloc(device_timer_id id, void *ptr) -{ - return machine().scheduler().timer_alloc(*this, id, ptr); -} - - -//------------------------------------------------- -// timer_set - set a temporary timer that will -// call our device callback -//------------------------------------------------- - -void device_t::timer_set(const attotime &duration, device_timer_id id, int param, void *ptr) -{ - machine().scheduler().timer_set(duration, *this, id, param, ptr); -} - - -//------------------------------------------------- // set_machine - notify that the machine now // exists //------------------------------------------------- @@ -500,26 +474,10 @@ void device_t::set_machine(running_machine &machine) bool device_t::findit(validity_checker *valid) const { bool allfound = true; - for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next()) + for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next()) { - if (valid) - { - // sanity checking - char const *const tag = autodev->finder_tag(); - if (!tag) - { - osd_printf_error("Finder tag is null!\n"); - allfound = false; - continue; - } - if (tag[0] == '^' && tag[1] == ':') - { - osd_printf_error("Malformed finder tag: %s\n", tag); - allfound = false; - continue; - } - } - allfound &= autodev->findit(valid); + if (!autodev->findit(valid)) + allfound = false; } return allfound; } @@ -609,7 +567,6 @@ void device_t::start() } // register our save states - save_item(NAME(m_clock)); save_item(NAME(m_unscaled_clock)); save_item(NAME(m_clock_scale)); @@ -688,6 +645,21 @@ void device_t::pre_save() void device_t::post_load() { + // recompute clock-related parameters if something changed + u32 const scaled_clock = m_unscaled_clock * m_clock_scale; + if (m_clock != scaled_clock) + { + m_clock = scaled_clock; + m_attoseconds_per_clock = (scaled_clock == 0) ? 0 : HZ_TO_ATTOSECONDS(scaled_clock); + + // recalculate all derived clocks + for (device_t &child : subdevices()) + child.calculate_derived_clock(); + + // make sure the device knows about the new clock + notify_clock_changed(); + } + // notify the interface for (device_interface &intf : interfaces()) intf.interface_post_load(); @@ -702,11 +674,11 @@ void device_t::post_load() // that the clock has changed //------------------------------------------------- -void device_t::notify_clock_changed() +void device_t::notify_clock_changed(bool sync_on_new_clock_domain) { // first notify interfaces for (device_interface &intf : interfaces()) - intf.interface_clock_changed(); + intf.interface_clock_changed(sync_on_new_clock_domain); // then notify the device device_clock_changed(); @@ -868,17 +840,6 @@ void device_t::device_debug_setup() //------------------------------------------------- -// device_timer - called whenever a device timer -// fires -//------------------------------------------------- - -void device_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - // do nothing by default -} - - -//------------------------------------------------- // subdevice_slow - perform a slow name lookup, // caching the results //------------------------------------------------- @@ -1025,18 +986,9 @@ void device_t::subdevice_list::remove(device_t &device) // list of stuff to find after we go live //------------------------------------------------- -finder_base *device_t::register_auto_finder(finder_base &autodev) -{ - // add to this list - finder_base *old = m_auto_finder_list; - m_auto_finder_list = &autodev; - return old; -} - - -void device_t::register_callback(devcb_base &callback) +device_resolver_base *device_t::register_auto_finder(device_resolver_base &autodev) { - m_callbacks.emplace_back(&callback); + return std::exchange(m_auto_finder_list, &autodev); } @@ -1188,7 +1140,7 @@ void device_interface::interface_post_load() // implementation //------------------------------------------------- -void device_interface::interface_clock_changed() +void device_interface::interface_clock_changed(bool sync_on_new_clock_domain) { // do nothing by default } diff --git a/src/emu/device.h b/src/emu/device.h index 77c12cb2d56..87736144292 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -37,19 +37,6 @@ //************************************************************************** -// DEVICE CONFIGURATION MACROS -//************************************************************************** - -// configure devices - -#define DECLARE_READ_LINE_MEMBER(name) int name() -#define READ_LINE_MEMBER(name) int name() -#define DECLARE_WRITE_LINE_MEMBER(name) void name([[maybe_unused]] int state) -#define WRITE_LINE_MEMBER(name) void name([[maybe_unused]] int state) - - - -//************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -210,7 +197,7 @@ private: assert(!owner); assert(!clock); - return make_unique_clear<DriverClass>(mconfig, type, tag); + return std::make_unique<DriverClass>(mconfig, type, tag); } create_func const m_creator; @@ -468,10 +455,6 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass class device_missing_dependencies : public emu_exception { }; -// timer IDs for devices -typedef u32 device_timer_id; - - /// \brief Base class for devices /// /// The base class for all device implementations in MAME's modular @@ -482,8 +465,7 @@ class device_t : public delegate_late_bind friend class simple_list<device_t>; friend class running_machine; - friend class finder_base; - friend class devcb_base; + friend class device_resolver_base; class subdevice_list { @@ -651,8 +633,8 @@ public: // interface helpers interface_list &interfaces() { return m_interfaces; } const interface_list &interfaces() const { return m_interfaces; } - template<class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); } - template<class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); } + template <class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); } + template <class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); } // specialized helpers for common core interfaces bool interface(device_execute_interface *&intf) { intf = m_interfaces.m_execute; return (intf != nullptr); } @@ -675,8 +657,42 @@ public: ioport_port *ioport(std::string_view tag) const; device_t *subdevice(std::string_view tag) const; device_t *siblingdevice(std::string_view tag) const; - template<class DeviceClass> DeviceClass *subdevice(std::string_view tag) const { return downcast<DeviceClass *>(subdevice(tag)); } - template<class DeviceClass> DeviceClass *siblingdevice(std::string_view tag) const { return downcast<DeviceClass *>(siblingdevice(tag)); } + template <class DeviceClass> + DeviceClass *subdevice(std::string_view tag) const + { + device_t *const found = subdevice(tag); + if constexpr (std::is_base_of_v<device_t, DeviceClass>) + { + return downcast<DeviceClass *>(found); + } + else + { + auto const result = dynamic_cast<DeviceClass *>(found); +#if defined(MAME_DEBUG) + if (found && !result) + report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass)); +#endif + return result; + } + } + template <class DeviceClass> + DeviceClass *siblingdevice(std::string_view tag) const + { + device_t *const found = siblingdevice(tag); + if constexpr (std::is_base_of_v<device_t, DeviceClass>) + { + return downcast<DeviceClass *>(found); + } + else + { + auto const result = dynamic_cast<DeviceClass *>(found); +#if defined(MAME_DEBUG) + if (found && !result) + report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass)); +#endif + return result; + } + } std::string parameter(std::string_view tag) const; // configuration helpers @@ -696,19 +712,17 @@ public: // clock/timing accessors u32 clock() const { return m_clock; } u32 unscaled_clock() const { return m_unscaled_clock; } - void set_unscaled_clock(u32 clock); - void set_unscaled_clock(const XTAL &xtal) { set_unscaled_clock(xtal.value()); } - void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock); } // non-overloaded name because binding to overloads is ugly + void set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain = false); + void set_unscaled_clock(const XTAL &xtal, bool sync_on_new_clock_domain = false) { set_unscaled_clock(xtal.value(), sync_on_new_clock_domain); } + void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock, false); } // non-overloaded name because binding to overloads is ugly + void set_unscaled_clock_int_sync(u32 clock) { set_unscaled_clock(clock, true); } // non-overloaded name because binding to overloads is ugly double clock_scale() const { return m_clock_scale; } void set_clock_scale(double clockscale); attotime clocks_to_attotime(u64 clocks) const noexcept; u64 attotime_to_clocks(const attotime &duration) const noexcept; // timer interfaces - emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr); - void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr); - void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); } - void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); } + template <typename... T> emu_timer *timer_alloc(T &&... args); /// \brief Register data for save states /// @@ -777,7 +791,7 @@ public: /// \param [in] index A numeric value to distinguish between saved /// items with the same name. /// \sa save_item - template<typename ItemType> + template <typename ItemType> void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0) { assert(m_save); @@ -806,7 +820,7 @@ public: /// \param [in] index A numeric value to distinguish between saved /// items with the same name. /// \sa save_item - template<typename ItemType, typename StructType, typename ElementType> + template <typename ItemType, typename StructType, typename ElementType> void ATTR_COLD save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0) { assert(m_save); @@ -834,9 +848,8 @@ protected: void debug_setup(); void pre_save(); void post_load(); - void notify_clock_changed(); - finder_base *register_auto_finder(finder_base &autodev); - void register_callback(devcb_base &callback); + void notify_clock_changed(bool sync_on_new_clock_domain = false); + device_resolver_base *register_auto_finder(device_resolver_base &autodev); //------------------- begin derived class overrides @@ -976,7 +989,6 @@ protected: virtual void device_clock_changed(); virtual void device_debug_setup(); - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); //------------------- end derived class overrides @@ -1016,9 +1028,8 @@ private: std::string m_basetag; // base part of the tag bool m_config_complete; // have we completed our configuration? bool m_started; // true if the start function has succeeded - finder_base * m_auto_finder_list; // list of objects to auto-find + device_resolver_base * m_auto_finder_list; // list of objects to auto-find mutable std::vector<rom_entry> m_rom_entries; - std::list<devcb_base *> m_callbacks; std::vector<memory_view *> m_viewlist; // list of views // string formatting buffer for logerror @@ -1182,7 +1193,7 @@ public: /// \sa interface_pre_save device_t::device_post_load virtual void interface_post_load() ATTR_COLD; - virtual void interface_clock_changed(); + virtual void interface_clock_changed(bool sync_on_new_clock_domain); virtual void interface_debug_setup(); private: diff --git a/src/emu/device.ipp b/src/emu/device.ipp index 820f81093d0..e633ead4bda 100644 --- a/src/emu/device.ipp +++ b/src/emu/device.ipp @@ -75,6 +75,11 @@ inline void device_delegate_helper::set_tag(device_finder<DeviceClass, Required> } // namespace emu::detail +template <typename... T> +inline emu_timer *device_t::timer_alloc(T &&... args) +{ + return machine().scheduler().timer_alloc(timer_expired_delegate(std::forward<T>(args)...)); +} template <typename Format, typename... Params> inline void device_t::popmessage(Format &&fmt, Params &&... args) const @@ -88,7 +93,7 @@ inline void device_t::logerror(Format &&fmt, Params &&... args) const { if (m_machine != nullptr && m_machine->allow_logging()) { - g_profiler.start(PROFILER_LOGERROR); + auto profile = g_profiler.start(PROFILER_LOGERROR); // dump to the buffer m_string_buffer.clear(); @@ -98,8 +103,6 @@ inline void device_t::logerror(Format &&fmt, Params &&... args) const m_string_buffer.put('\0'); m_machine->strlog(&m_string_buffer.vec()[0]); - - g_profiler.stop(); } } diff --git a/src/emu/diexec.cpp b/src/emu/diexec.cpp index 49dee5f650e..715f0c38459 100644 --- a/src/emu/diexec.cpp +++ b/src/emu/diexec.cpp @@ -68,9 +68,8 @@ device_execute_interface::device_execute_interface(const machine_config &mconfig , m_divshift(0) , m_cycles_per_second(0) , m_attoseconds_per_cycle(0) + , m_spin_end_timer(nullptr) { - memset(&m_localtime, 0, sizeof(m_localtime)); - // configure the fast accessor assert(!device.interfaces().m_execute); device.interfaces().m_execute = this; @@ -164,7 +163,7 @@ void device_execute_interface::spin_until_time(const attotime &duration) suspend_until_trigger(TRIGGER_SUSPENDTIME + timetrig, true); // then set a timer for it - m_scheduler->timer_set(duration, timer_expired_delegate(FUNC(device_execute_interface::timed_trigger_callback),this), TRIGGER_SUSPENDTIME + timetrig, this); + m_spin_end_timer->adjust(duration, TRIGGER_SUSPENDTIME + timetrig); timetrig = (timetrig + 1) % 256; } @@ -384,9 +383,16 @@ void device_execute_interface::interface_pre_start() m_profiler = profile_type(index + PROFILER_DEVICE_FIRST); m_inttrigger = index + TRIGGER_INT; - // allocate timers if we need them + // allocate a timed-interrupt timer if we need it if (m_timed_interrupt_period != attotime::zero) m_timedint_timer = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::trigger_periodic_interrupt), this)); + + // allocate a timer for triggering the end of spin-until conditions + m_spin_end_timer = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::timed_trigger_callback), this)); + + // allocate input-pulse timers if we have input lines + for (u32 i = 0; i < MAX_INPUT_LINES; i++) + m_pulse_end_timers[i] = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this)); } @@ -475,7 +481,7 @@ void device_execute_interface::interface_post_reset() // information for this device //------------------------------------------------- -void device_execute_interface::interface_clock_changed() +void device_execute_interface::interface_clock_changed(bool sync_on_new_clock_domain) { // a clock of zero disables the device if (device().clock() == 0) @@ -492,6 +498,10 @@ void device_execute_interface::interface_clock_changed() m_cycles_per_second = clocks_to_cycles(device().clock()); m_attoseconds_per_cycle = HZ_TO_ATTOSECONDS(m_cycles_per_second); + // resynchronize the localtime to the clock domain when asked to + if (sync_on_new_clock_domain) + m_localtime = attotime::from_ticks(m_localtime.as_ticks(device().clock())+1, device().clock()); + // update the device's divisor s64 attos = m_attoseconds_per_cycle; m_divshift = 0; @@ -508,17 +518,12 @@ void device_execute_interface::interface_clock_changed() //------------------------------------------------- -// standard_irq_callback_member - IRQ acknowledge +// standard_irq_callback - IRQ acknowledge // callback; handles HOLD_LINE case and signals // to the debugger //------------------------------------------------- -IRQ_CALLBACK_MEMBER( device_execute_interface::standard_irq_callback_member ) -{ - return device.execute().standard_irq_callback(irqline); -} - -int device_execute_interface::standard_irq_callback(int irqline) +int device_execute_interface::standard_irq_callback(int irqline, offs_t pc) { // get the default vector and acknowledge the interrupt if needed int vector = m_input[irqline].default_irq_callback(); @@ -531,7 +536,7 @@ int device_execute_interface::standard_irq_callback(int irqline) // notify the debugger if (device().machine().debug_flags & DEBUG_FLAG_ENABLED) - device().debug()->interrupt_hook(irqline); + device().debug()->interrupt_hook(irqline, pc); return vector; } @@ -615,7 +620,7 @@ void device_execute_interface::pulse_input_line(int irqline, const attotime &dur set_input_line(irqline, ASSERT_LINE); attotime target_time = local_time() + duration; - m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline); + m_pulse_end_timers[irqline]->adjust(target_time - m_scheduler->time(), irqline); } } @@ -682,7 +687,7 @@ if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_execute->device().tag(), m_linen if (event_index >= std::size(m_queue)) { m_qindex--; - empty_event_queue(nullptr,0); + empty_event_queue(0); event_index = m_qindex++; m_execute->device().logerror("Exceeded pending input line event queue on device '%s'!\n", m_execute->device().tag()); } @@ -696,7 +701,7 @@ if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_execute->device().tag(), m_linen // if this is the first one, set the timer if (event_index == 0) - m_execute->scheduler().synchronize(timer_expired_delegate(FUNC(device_execute_interface::device_input::empty_event_queue),this), 0, this); + m_execute->scheduler().synchronize(timer_expired_delegate(FUNC(device_execute_interface::device_input::empty_event_queue),this)); } } diff --git a/src/emu/diexec.h b/src/emu/diexec.h index 065248a9046..51973ad19cc 100644 --- a/src/emu/diexec.h +++ b/src/emu/diexec.h @@ -161,10 +161,10 @@ public: void abort_timeslice() noexcept; // input and interrupt management - void set_input_line(int linenum, int state) { m_input[linenum].set_state_synced(state); } - void set_input_line_vector(int linenum, int vector) { m_input[linenum].set_vector(vector); } - void set_input_line_and_vector(int linenum, int state, int vector) { m_input[linenum].set_state_synced(state, vector); } - int input_state(int linenum) const { return m_input[linenum].m_curstate; } + void set_input_line(int linenum, int state) { assert(device().started()); m_input[linenum].set_state_synced(state); } + void set_input_line_vector(int linenum, int vector) { assert(device().started()); m_input[linenum].set_vector(vector); } + void set_input_line_and_vector(int linenum, int state, int vector) { assert(device().started()); m_input[linenum].set_state_synced(state, vector); } + int input_state(int linenum) const { assert(device().started()); return m_input[linenum].m_curstate; } void pulse_input_line(int irqline, const attotime &duration); // suspend/resume @@ -216,13 +216,12 @@ protected: virtual void interface_post_start() override; virtual void interface_pre_reset() override; virtual void interface_post_reset() override; - virtual void interface_clock_changed() override; + virtual void interface_clock_changed(bool sync_on_new_clock_domain) override; // for use by devcpu for now... int current_input_state(unsigned i) const { return m_input[i].m_curstate; } void set_icountptr(int &icount) { assert(!m_icountptr); m_icountptr = &icount; } - IRQ_CALLBACK_MEMBER(standard_irq_callback_member); - int standard_irq_callback(int irqline); + int standard_irq_callback(int irqline, offs_t pc); // debugger hooks bool debugger_enabled() const { return bool(device().machine().debug_flags & DEBUG_FLAG_ENABLED); } @@ -304,7 +303,9 @@ private: // cycle counting and executing profile_type m_profiler; // profiler tag +protected: // TODO: decide whether to bring up the wait-state methods int * m_icountptr; // pointer to the icount +private: int m_cycles_running; // number of cycles we are executing int m_cycles_stolen; // number of cycles we artificially stole @@ -324,6 +325,9 @@ private: u32 m_cycles_per_second; // cycles per second, adjusted for multipliers attoseconds_t m_attoseconds_per_cycle; // attoseconds per adjusted clock cycle + emu_timer * m_spin_end_timer; // timer for triggering the end of spin_until_time + emu_timer * m_pulse_end_timers[MAX_INPUT_LINES]; // timer for ending input-line pulses + // callbacks TIMER_CALLBACK_MEMBER(timed_trigger_callback) { trigger(param); } diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 031ed46eb30..59d1523a6b1 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -11,49 +11,20 @@ #include "emu.h" #include "emuopts.h" +#include "fileio.h" #include "romload.h" #include "softlist.h" #include "softlist_dev.h" -#include "ui/uimain.h" - #include "corestr.h" #include "opresolv.h" +#include "path.h" #include "zippath.h" #include <algorithm> -#include <cctype> #include <cstring> #include <regex> - - -//************************************************************************** -// DEVICE CONFIG IMAGE INTERFACE -//************************************************************************** -const image_device_type_info device_image_interface::m_device_info_array[] = - { - { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */ - { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */ - { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */ - { IO_HARDDISK, "harddisk", "hard" }, /* 3 */ - { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */ - { IO_CASSETTE, "cassette", "cass" }, /* 5 */ - { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */ - { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */ - { IO_PRINTER, "printout", "prin" }, /* 8 */ - { IO_SERIAL, "serial", "serl" }, /* 9 */ - { IO_PARALLEL, "parallel", "parl" }, /* 10 */ - { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */ - { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */ - { IO_MEMCARD, "memcard", "memc" }, /* 13 */ - { IO_CDROM, "cdrom", "cdrm" }, /* 14 */ - { IO_MAGTAPE, "magtape", "magt" }, /* 15 */ - { IO_ROM, "romimage", "rom" }, /* 16 */ - { IO_MIDIIN, "midiin", "min" }, /* 17 */ - { IO_MIDIOUT, "midiout", "mout" }, /* 18 */ - { IO_PICTURE, "picture", "pic" }, /* 19 */ - { IO_VIDEO, "vidfile", "vid" } /* 20 */ - }; +#include <sstream> //************************************************************************** @@ -94,15 +65,18 @@ image_device_format::~image_device_format() device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "image") - , m_err() , m_file() , m_mame_file() + , m_default_region(-1) + , m_current_region(-1) , m_software_part_ptr(nullptr) + , m_sequence_counter(0) , m_readonly(false) , m_created(false) , m_create_format(0) , m_create_args(nullptr) , m_user_loadable(true) + , m_must_be_loaded(false) , m_is_loading(false) , m_is_reset_and_loading(false) { @@ -117,6 +91,17 @@ device_image_interface::~device_image_interface() { } +//------------------------------------------------- +// add_region - register a region that may +// have a chd image +//------------------------------------------------- +void device_image_interface::add_region(std::string name, bool is_default) +{ + if (is_default) + m_default_region = m_possible_preset_regions.size(); + m_possible_preset_regions.push_back(name); +} + //------------------------------------------------- // interface_config_complete - perform any @@ -130,57 +115,134 @@ void device_image_interface::interface_config_complete() update_names(); } - //------------------------------------------------- -// find_device_type - search through list of -// device types to extract data +// check_preset_images - lookup the CHDs from the +// region(s), if any //------------------------------------------------- -const image_device_type_info *device_image_interface::find_device_type(iodevice_t type) +void device_image_interface::check_preset_images() { - for (const image_device_type_info &info : m_device_info_array) + if (!m_possible_preset_regions.empty()) { - if (info.m_type == type) - return &info; + for(const auto &r : m_possible_preset_regions) + m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r)); + if (m_default_region != -1 && m_preset_images[m_default_region]) + m_current_region = m_default_region; + else + { + for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++); + if (m_current_region == int(m_preset_images.size())) + fatalerror("%s: No configured region has an image\n", device().tag()); + } + set_image_tag(); + set_user_loadable(false); + } + else + { + std::string tag = device().owner()->tag(); + auto *const chd = device().machine().rom_load().get_disk_handle(tag); + if (chd) + { + m_possible_preset_regions.emplace_back(std::move(tag)); + m_preset_images.push_back(chd); + m_current_region = 0; + set_image_tag(); + set_user_loadable(false); + } } - return nullptr; } //------------------------------------------------- -// device_typename - retrieves device type name +// has_preset_images - does the device have an +// image to retrieve through current_image_* //------------------------------------------------- -const char *device_image_interface::device_typename(iodevice_t type) +bool device_image_interface::has_preset_images() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_name : "unknown"; + return !m_possible_preset_regions.empty(); } //------------------------------------------------- -// device_brieftypename - retrieves device -// brief type name +// has_preset_images - does the device have +// multiple preset images with user selection //------------------------------------------------- -const char *device_image_interface::device_brieftypename(iodevice_t type) +bool device_image_interface::has_preset_images_selection() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_shortname : "unk"; + int icount = 0; + for (const auto *f : m_preset_images) + if (f) + icount ++; + return icount > 1; } + //------------------------------------------------- -// device_typeid - retrieves device type id +// preset_images_list -- generate the list of +// available image names //------------------------------------------------- -iodevice_t device_image_interface::device_typeid(const char *name) +std::vector<std::string> device_image_interface::preset_images_list() const { - for (const image_device_type_info &info : m_device_info_array) - { - if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname)) - return info.m_type; - } - return (iodevice_t)-1; + std::vector<std::string> result; + for (unsigned int i = 0; i != m_preset_images.size(); i++) + if (m_preset_images[i]) + result.push_back(m_possible_preset_regions[i]); + return result; +} + +//------------------------------------------------- +// current_preset_image_id -- current image id, +// recomputed to ignore non-present images. +// returns -1 if not in preset mode +//------------------------------------------------- + +int device_image_interface::current_preset_image_id() const +{ + if (m_current_region == -1) + return -1; + int id = 0; + for (int i = 0; i != m_current_region; i++) + if (m_preset_images[i]) + id++; + return id; +} + +//------------------------------------------------- +// current_preset_image_chd -- return the chd of +// the current active image, nullptr if non +//------------------------------------------------- + +chd_file *device_image_interface::current_preset_image_chd() const +{ + if (m_current_region == -1) + return nullptr; + return m_preset_images[m_current_region]; +} + +//------------------------------------------------- +// switch_preset_image -- change of preset image +//------------------------------------------------- + +void device_image_interface::switch_preset_image(int id) +{ + for (unsigned int i = 0; i != m_preset_images.size(); i++) + if (m_preset_images[i]) + { + if(!id) + { + call_unload(); + m_current_region = i; + call_load(); + break; + } + id--; + } + + return; } + //------------------------------------------------- // set_image_filename - specifies the filename of // an image @@ -194,9 +256,9 @@ void device_image_interface::set_image_filename(std::string_view filename) // find the last "path separator" auto iter = std::find_if( - m_image_name.rbegin(), - m_image_name.rend(), - [](char c) { return (c == '\\') || (c == '/') || (c == ':'); }); + m_image_name.rbegin(), + m_image_name.rend(), + [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); }); if (iter != m_image_name.rend()) m_basename.assign(iter.base(), m_image_name.end()); @@ -209,6 +271,20 @@ void device_image_interface::set_image_filename(std::string_view filename) m_filetype = core_filename_extract_extension(m_basename, true); } +//------------------------------------------------- +// set_image_tag - specifies the filename of +// an image as the device tag +//------------------------------------------------- + +void device_image_interface::set_image_tag() +{ + m_image_name = device().owner()->tag(); + m_working_directory = ""; + m_basename = ""; + m_basename_noext = ""; + m_filetype = ""; +} + //------------------------------------------------- // is_filetype - check if the filetype matches @@ -216,14 +292,24 @@ void device_image_interface::set_image_filename(std::string_view filename) bool device_image_interface::is_filetype(std::string_view candidate_filetype) const { - return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(), - [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); + return util::streqlower(m_filetype, candidate_filetype); } -/**************************************************************************** - CREATION FORMATS -****************************************************************************/ +//------------------------------------------------- +// add_media_change_notifier - subscribe for +// media change notifications +//------------------------------------------------- + +util::notifier_subscription device_image_interface::add_media_change_notifier(delegate<void (media_change_event)> &&n) +{ + return m_media_change_notifier.subscribe(std::move(n)); +} + + +//*************************************************************************** +// CREATION FORMATS +//*************************************************************************** //------------------------------------------------- // device_get_named_creatable_format - @@ -231,10 +317,10 @@ bool device_image_interface::is_filetype(std::string_view candidate_filetype) co // image creation by name //------------------------------------------------- -const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept +const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept { - for (auto &format : m_formatlist) - if (format->name() == format_name) + for (const auto &format : m_formatlist) + if (std::string_view(format->name()) == format_name) return format.get(); return nullptr; } @@ -261,22 +347,9 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri } -/**************************************************************************** - ERROR HANDLING -****************************************************************************/ - -//------------------------------------------------- -// image_clear_error - clear out any specified -// error -//------------------------------------------------- - -void device_image_interface::clear_error() -{ - m_err.clear(); - m_err_message.clear(); -} - - +//*************************************************************************** +// ERROR HANDLING +//*************************************************************************** //------------------------------------------------- // error - returns the error text for an image @@ -298,7 +371,10 @@ std::error_category const &image_category() noexcept "Internal error"sv, "Unsupported operation"sv, "Invalid image"sv, + "Invalid image length"sv, "File already open"sv, + "Unrecognized software item"sv, + "Invalid software item"sv, "Unspecified error"sv }; if ((0 <= condition) && (std::size(s_messages) > condition)) return std::string(s_messages[condition]); @@ -310,50 +386,6 @@ std::error_category const &image_category() noexcept return s_image_category_instance; } -std::string_view device_image_interface::error() -{ - if (m_err && m_err_message.empty()) - m_err_message = m_err.message(); - return m_err_message; -} - - - -//------------------------------------------------- -// seterror - specifies an error on an image -//------------------------------------------------- - -void device_image_interface::seterror(std::error_condition err, const char *message) -{ - clear_error(); - m_err = err; - if (message) - m_err_message = message; -} - - - -//------------------------------------------------- -// message - used to display a message while -// loading -//------------------------------------------------- - -void device_image_interface::message(const char *format, ...) -{ - va_list args; - char buffer[256]; - - /* format the message */ - va_start(args, format); - vsnprintf(buffer, std::size(buffer), format, args); - va_end(args); - - /* display the popup for a standard amount of time */ - device().machine().ui().popup_time(5, "%s: %s", - basename(), - buffer); -} - //------------------------------------------------- // software_entry - return a pointer to the @@ -370,14 +402,13 @@ const software_info *device_image_interface::software_entry() const noexcept // get_software_region //------------------------------------------------- -u8 *device_image_interface::get_software_region(const char *tag) +u8 *device_image_interface::get_software_region(std::string_view tag) { if (!loaded_through_softlist()) return nullptr; - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->base() : nullptr; + memory_region *const region = device().memregion(tag); + return region ? region->base() : nullptr; } @@ -385,11 +416,13 @@ u8 *device_image_interface::get_software_region(const char *tag) // image_get_software_region_length //------------------------------------------------- -u32 device_image_interface::get_software_region_length(const char *tag) +u32 device_image_interface::get_software_region_length(std::string_view tag) { - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->bytes() : 0; + if (!loaded_through_softlist()) + return 0; + + memory_region *const region = device().memregion(tag); + return region ? region->bytes() : 0; } @@ -397,7 +430,7 @@ u32 device_image_interface::get_software_region_length(const char *tag) // image_get_feature //------------------------------------------------- -const char *device_image_interface::get_feature(const char *feature_name) const +const char *device_image_interface::get_feature(std::string_view feature_name) const { return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name); } @@ -407,7 +440,7 @@ const char *device_image_interface::get_feature(const char *feature_name) const // load_software_region - //------------------------------------------------- -bool device_image_interface::load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr) +std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr<u8[]> &ptr) { size_t size = get_software_region_length(tag); @@ -415,9 +448,10 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p { ptr = std::make_unique<u8[]>(size); memcpy(ptr.get(), get_software_region(tag), size); + return std::error_condition(); } - - return size > 0; + else + return image_error::UNSUPPORTED; } @@ -428,48 +462,30 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p // to be loaded // **************************************************************************** -bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) +std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) { // reset the hash; we want to override existing data hashes.reset(); // figure out the size, and "cap" the skip bytes u64 size; - if (file.length(size)) - return false; + std::error_condition filerr = file.length(size); + if (filerr) + return filerr; skip_bytes = u32(std::min<u64>(skip_bytes, size)); - // seek to the beginning - file.seek(skip_bytes, SEEK_SET); // TODO: check error return - u64 position = skip_bytes; - - // keep on reading hashes - hashes.begin(types); - while (position < size) - { - uint8_t buffer[8192]; - - // read bytes - const size_t count = size_t(std::min<u64>(size - position, sizeof(buffer))); - size_t actual_count; - const std::error_condition filerr = file.read(buffer, count, actual_count); - if (filerr || !actual_count) - return false; - position += actual_count; - - // and compute the hashes - hashes.buffer(buffer, actual_count); - } - hashes.end(); + // and compute the hashes + size_t actual_count; + filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types); + if (filerr) + return filerr; - // cleanup - file.seek(0, SEEK_SET); // TODO: check error return - return true; + return std::error_condition(); } -bool device_image_interface::image_checkhash() +std::error_condition device_image_interface::image_checkhash() { // only calculate CRC if it hasn't been calculated, and the open_mode is read only u32 crcval; @@ -477,26 +493,25 @@ bool device_image_interface::image_checkhash() { // do not cause a linear read of 600 megs please // TODO: use SHA1 in the CHD header as the hash - if (image_type() == IO_CDROM) - return true; + if (image_is_chd_type()) + return std::error_condition(); // Skip calculating the hash when we have an image mounted through a software list if (loaded_through_softlist()) - return true; + return std::error_condition(); // run the hash - if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL)) - return false; + return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL); } - return true; + return std::error_condition(); } -util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const +util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const { // calculate the hash util::hash_collection hash; - if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) + if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) hash.reset(); return hash; } @@ -514,33 +529,6 @@ u32 device_image_interface::crc() } -//------------------------------------------------- -// support_command_line_image_creation - do we -// want to support image creation from the front -// end command line? -//------------------------------------------------- - -bool device_image_interface::support_command_line_image_creation() const noexcept -{ - bool result; - switch (image_type()) - { - case IO_PRINTER: - case IO_SERIAL: - case IO_PARALLEL: - // going by the assumption that these device image types should support this - // behavior; ideally we'd get rid of IO_* and just push this to the specific - // devices - result = true; - break; - default: - result = false; - break; - } - return result; -} - - // **************************************************************************** // Battery functions // @@ -619,34 +607,6 @@ void device_image_interface::battery_save(const void *buffer, int length) } -//------------------------------------------------- -// uses_file_extension - update configuration -// based on completed device setup -//------------------------------------------------- - -bool device_image_interface::uses_file_extension(const char *file_extension) const -{ - bool result = false; - - if (file_extension[0] == '.') - file_extension++; - - /* find the extensions */ - std::string extensions(file_extensions()); - char *ext = strtok((char*)extensions.c_str(),","); - while (ext != nullptr) - { - if (!core_stricmp(ext, file_extension)) - { - result = true; - break; - } - ext = strtok (nullptr, ","); - } - return result; -} - - // *************************************************************************** // IMAGE LOADING // *************************************************************************** @@ -712,15 +672,20 @@ std::vector<u32> device_image_interface::determine_open_plan(bool is_create) { std::vector<u32> open_plan; - // emit flags into a vector - if (!is_create && is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE); - if (!is_create && !is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_WRITE); - if (!is_create && is_readable()) - open_plan.push_back(OPEN_FLAG_READ); - if (is_create && is_writeable() && is_creatable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + if (!is_create) + { + if (is_writeable()) + open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE); + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ); + } + else if (is_writeable() && is_creatable()) + { + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + else + open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + } return open_plan; } @@ -772,9 +737,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp // load_software - software image loading //------------------------------------------------- -bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) +std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) { - bool retval = false; + std::error_condition retval; int warningcount = 0; for (const rom_entry *region = start; region; region = rom_next_region(region)) { @@ -786,7 +751,7 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st { const software_info *const swinfo = swlist.find(std::string(swname)); if (!swinfo) - return false; + return image_error::NOSOFTWARE; if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); @@ -816,14 +781,31 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st else filerr = m_mame_file->open(romp->name()); if (filerr) + { m_mame_file.reset(); + std::ostringstream msg; + util::stream_format(msg, + "%s: error opening image file %s: %s (%s:%d)", + device().tag(), romp->name(), + filerr.message(), + filerr.category().name(), + filerr.value()); + if (!searchpath.empty()) + { + msg << " (tried in"; + for (auto const &path : searchpath) + msg << ' ' << path; + msg << ')'; + } + osd_printf_error("%s\n", std::move(msg).str()); + } warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata())); if (!filerr) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (!filerr) - retval = true; + if (filerr) + retval = filerr; break; // load first item for start } @@ -841,16 +823,16 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st // load_internal - core image loading //------------------------------------------------- -image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) +std::pair<std::error_condition, std::string> device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) { + std::pair<std::error_condition, std::string> err; + // first unload the image unload(); - // clear any possible error messages - clear_error(); - // we are now loading m_is_loading = true; + m_sequence_counter++; // record the filename set_image_filename(path); @@ -858,50 +840,47 @@ image_init_result device_image_interface::load_internal(std::string_view path, b if (core_opens_image_file()) { // determine open plan - std::vector<u32> open_plan = determine_open_plan(is_create); + std::vector<u32> const open_plan = determine_open_plan(is_create); // attempt to open the file in various ways for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++) { // open the file - m_err = load_image_by_path(*iter, path); - if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied)) - goto done; + err.first = load_image_by_path(*iter, path); + if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied)) + break; } // did we fail to find the file? - if (!m_file) - { - m_err = std::errc::no_such_file_or_directory; - goto done; - } + if (!err.first && !m_file) + err.first = std::errc::no_such_file_or_directory; } - // call device load or create - m_create_format = create_format; - m_create_args = create_args; - - if (!init_phase()) + if (!err.first) { - m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL; - if (m_err) - goto done; + // call device load or create + m_create_format = create_format; + m_create_args = create_args; + + if (!init_phase()) + err = finish_load(); } - // success! -done: - if (m_err) + if (err.first) { - if (!init_phase()) - { - if (device().machine().phase() == machine_phase::RUNNING) - device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); - else - osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); - } + osd_printf_error( + !err.second.empty() + ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n") + : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"), + path, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); clear(); } - return m_err ? image_init_result::FAIL : image_init_result::PASS; + + return err; } @@ -909,13 +888,13 @@ done: // load - load an image into MAME //------------------------------------------------- -image_init_result device_image_interface::load(std::string_view path) +std::pair<std::error_condition, std::string> device_image_interface::load(std::string_view path) { // is this a reset on load item? if (is_reset_on_load() && !init_phase()) { reset_and_load(path); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } return load_internal(path, false, 0, nullptr); @@ -926,26 +905,26 @@ image_init_result device_image_interface::load(std::string_view path) // load_software - loads a softlist item by name //------------------------------------------------- -image_init_result device_image_interface::load_software(std::string_view software_identifier) +std::pair<std::error_condition, std::string> device_image_interface::load_software(std::string_view software_identifier) { // Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load if (is_reset_on_load() && !init_phase()) { reset_and_load(software_identifier); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } // Prepare to load unload(); - clear_error(); m_is_loading = true; // Check if there's a software list defined for this device and use that if we're not creating an image - bool softload = load_software_part(software_identifier); - if (!softload) + std::pair<std::error_condition, std::string> err; + err.first = load_software_part(software_identifier); + if (err.first) { m_is_loading = false; - return image_init_result::FAIL; + return err; } // set up softlist stuff @@ -955,9 +934,10 @@ image_init_result device_image_interface::load_software(std::string_view softwar m_image_name = m_full_software_name; m_basename = m_full_software_name; m_basename_noext = m_full_software_name; - m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr - ? std::string(core_filename_extract_extension(m_mame_file->filename(), true)) - : ""; + if (use_software_list_file_extension_for_filetype() && m_mame_file) + m_filetype = core_filename_extract_extension(m_mame_file->filename(), true); + else + m_filetype.clear(); // Copy some image information when we have been loaded through a software list software_info &swinfo = m_software_part_ptr->info(); @@ -967,16 +947,31 @@ image_init_result device_image_interface::load_software(std::string_view softwar fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); // set file type - std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) + std::string filename = (m_mame_file && m_mame_file->filename()) ? m_mame_file->filename() : ""; m_filetype = core_filename_extract_extension(filename, true); // call finish_load if necessary - if (init_phase() == false && (finish_load() != image_init_result::PASS)) - return image_init_result::FAIL; + if (!init_phase()) + { + err = finish_load(); + if (err.first) + { + osd_printf_error( + !err.second.empty() + ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n" + : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n", + software_identifier, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); + clear(); + } + } - return image_init_result::PASS; + return err; } @@ -985,53 +980,38 @@ image_init_result device_image_interface::load_software(std::string_view softwar // from core //------------------------------------------------- -image_init_result device_image_interface::finish_load() +std::pair<std::error_condition, std::string> device_image_interface::finish_load() { - image_init_result err = image_init_result::PASS; + std::pair<std::error_condition, std::string> err; if (m_is_loading) { - if (!image_checkhash()) - { - m_err = image_error::INVALIDIMAGE; - err = image_init_result::FAIL; - } + err.first = image_checkhash(); - if (err == image_init_result::PASS) + if (!err.first) { if (m_created) - { err = call_create(m_create_format, m_create_args); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } else - { - // using device load - err = call_load(); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } + err = call_load(); // using device load } } + m_is_loading = false; m_create_format = 0; m_create_args = nullptr; + if (!err.first) + m_media_change_notifier(media_change_event::LOADED); + return err; } //------------------------------------------------- -// create - create a image +// create - create an image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path) +std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path) { return create(path, nullptr, nullptr); } @@ -1041,13 +1021,14 @@ image_init_result device_image_interface::create(std::string_view path) // create - create a image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) +std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) { int format_index = 0; int cnt = 0; for (auto &format : m_formatlist) { - if (create_format == format.get()) { + if (create_format == format.get()) + { format_index = cnt; break; } @@ -1081,7 +1062,7 @@ void device_image_interface::reset_and_load(std::string_view path) // to an image //------------------------------------------------- -void device_image_interface::clear() +void device_image_interface::clear() noexcept { m_mame_file.reset(); m_file.reset(); @@ -1101,6 +1082,8 @@ void device_image_interface::clear() m_software_list_name.clear(); m_hash.reset(); + + m_sequence_counter++; } @@ -1112,10 +1095,15 @@ void device_image_interface::unload() { if (is_loaded() || loaded_through_softlist()) { + m_sequence_counter++; call_unload(); + clear(); + m_media_change_notifier(media_change_event::UNLOADED); + } + else + { + clear(); // just to make sure everything is reset } - clear(); - clear_error(); } @@ -1137,12 +1125,10 @@ const util::option_guide &device_image_interface::create_option_guide() const void device_image_interface::update_names() { - const char *inst_name = custom_instance_name(); - const char *brief_name = custom_brief_instance_name(); - if (inst_name == nullptr) - inst_name = device_typename(image_type()); - if (brief_name == nullptr) - brief_name = device_brieftypename(image_type()); + const char *inst_name = image_type_name(); + const char *brief_name = image_brief_type_name(); + assert(inst_name != nullptr); + assert(brief_name != nullptr); // count instances of the general image type, or device type if custom int count = 0; @@ -1151,19 +1137,21 @@ void device_image_interface::update_names() { if (this == &image) index = count; - const char *other_name = image.custom_instance_name(); - if (!other_name) - other_name = device_typename(image.image_type()); + const char *other_name = image.image_type_name(); + const char *other_brief_name = image.image_brief_type_name(); + assert(other_name != nullptr); + assert(other_brief_name != nullptr); - if (other_name == inst_name || !strcmp(other_name, inst_name)) + if (other_name == inst_name || !strcmp(other_name, inst_name) || + other_brief_name == brief_name || !strcmp(other_brief_name, brief_name)) count++; } - m_canonical_instance_name = string_format("%s%d", inst_name, index + 1); + m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1); if (count > 1) { m_instance_name = m_canonical_instance_name; - m_brief_instance_name = string_format("%s%d", brief_name, index + 1); + m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1); } else { @@ -1256,7 +1244,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c // sw_info and sw_part are also set. //------------------------------------------------- -bool device_image_interface::load_software_part(std::string_view identifier) +std::error_condition device_image_interface::load_software_part(std::string_view identifier) { // if no match has been found, we suggest similar shortnames software_list_device *swlist; @@ -1264,14 +1252,14 @@ bool device_image_interface::load_software_part(std::string_view identifier) if (m_software_part_ptr == nullptr) { software_list_device::display_matches(device().machine().config(), image_interface(), identifier); - return false; + return image_error::NOSOFTWARE; } // Load the software part const std::string &swname = m_software_part_ptr->info().shortname(); const rom_entry *start_entry = m_software_part_ptr->romdata().data(); const software_list_loader &loader = get_software_list_loader(); - bool result = loader.load_software(*this, *swlist, swname, start_entry); + std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry); // check compatibility switch (swlist->is_compatible(*m_software_part_ptr)) diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 67d20c43402..aa9c991c955 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -17,11 +17,13 @@ #ifndef MAME_EMU_DIIMAGE_H #define MAME_EMU_DIIMAGE_H +#include "notifier.h" #include "utilfwd.h" #include <memory> #include <string> #include <system_error> +#include <utility> #include <vector> @@ -29,39 +31,15 @@ // TYPE DEFINITIONS //************************************************************************** -enum iodevice_t -{ - /* List of all supported devices. Refer to the device by these names only */ - IO_UNKNOWN, - IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ - IO_FLOPPY, /* 2 - Floppy Disk unit */ - IO_HARDDISK, /* 3 - Hard Disk unit */ - IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ - IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ - IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ - IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ - IO_PRINTER, /* 8 - Printer device */ - IO_SERIAL, /* 9 - Generic Serial Port */ - IO_PARALLEL, /* 10 - Generic Parallel Port */ - IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ - IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ - IO_MEMCARD, /* 13 - Memory card */ - IO_CDROM, /* 14 - optical CD-ROM disc */ - IO_MAGTAPE, /* 15 - Magnetic tape */ - IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ - IO_MIDIIN, /* 17 - MIDI In port */ - IO_MIDIOUT, /* 18 - MIDI Out port */ - IO_PICTURE, /* 19 - A single-frame image */ - IO_VIDEO, /* 20 - A video file */ - IO_COUNT /* 21 - Total Number of IO_devices for searching */ -}; - enum class image_error : int { INTERNAL = 1, UNSUPPORTED, INVALIDIMAGE, + INVALIDLENGTH, ALREADYOPEN, + NOSOFTWARE, + BADSOFTWARE, UNSPECIFIED }; @@ -69,13 +47,6 @@ const std::error_category &image_category() noexcept; inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); } namespace std { template <> struct is_error_condition_enum<image_error> : public std::true_type { }; } -struct image_device_type_info -{ - iodevice_t m_type; - const char *m_name; - const char *m_shortname; -}; - class image_device_format { public: @@ -95,66 +66,56 @@ private: }; -enum class image_init_result { PASS, FAIL }; -enum class image_verify_result { PASS, FAIL }; - -//************************************************************************** -// MACROS -//************************************************************************** - -#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) - -#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) - - // ======================> device_image_interface // class representing interface-specific live image class device_image_interface : public device_interface { public: - typedef device_delegate<image_init_result (device_image_interface &)> load_delegate; - typedef device_delegate<void (device_image_interface &)> unload_delegate; + enum class media_change_event + { + LOADED, + UNLOADED + }; - typedef std::vector<std::unique_ptr<image_device_format>> formatlist_type; + using formatlist_type = std::vector<std::unique_ptr<image_device_format> >; // construction/destruction device_image_interface(const machine_config &mconfig, device_t &device); virtual ~device_image_interface(); - static const char *device_typename(iodevice_t type); - static const char *device_brieftypename(iodevice_t type); - static iodevice_t device_typeid(const char *name); - - virtual image_init_result call_load() { return image_init_result::PASS; } - virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } + virtual std::pair<std::error_condition, std::string> call_load() { return std::make_pair(std::error_condition(), std::string()); } + virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); } virtual void call_unload() { } virtual std::string call_display() { return std::string(); } virtual u32 unhashed_header_length() const noexcept { return 0; } virtual bool core_opens_image_file() const noexcept { return true; } - virtual iodevice_t image_type() const noexcept = 0; + virtual bool image_is_chd_type() const noexcept { return false; } virtual bool is_readable() const noexcept = 0; virtual bool is_writeable() const noexcept = 0; virtual bool is_creatable() const noexcept = 0; - virtual bool must_be_loaded() const noexcept = 0; virtual bool is_reset_on_load() const noexcept = 0; - virtual bool support_command_line_image_creation() const noexcept; + virtual bool support_command_line_image_creation() const noexcept { return false; } virtual const char *image_interface() const noexcept { return nullptr; } virtual const char *file_extensions() const noexcept = 0; virtual const util::option_guide &create_option_guide() const; - virtual const char *custom_instance_name() const noexcept { return nullptr; } - virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } + virtual const char *image_type_name() const noexcept = 0; + virtual const char *image_brief_type_name() const noexcept = 0; + + // Set block device image regions for arcade systems + void add_region(std::string name, bool is_default = false); + bool has_preset_images() const; + bool has_preset_images_selection() const; + std::vector<std::string> preset_images_list() const; + int current_preset_image_id() const; + void switch_preset_image(int id); + chd_file *current_preset_image_chd() const; + void check_preset_images(); const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } - const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; + const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept; const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } - std::string_view error(); - void seterror(std::error_condition err, const char *message); - void message(const char *format, ...) ATTR_PRINTF(2,3); - bool exists() const noexcept { return !m_image_name.empty(); } // get image file path/name @@ -165,9 +126,15 @@ public: bool is_filetype(std::string_view candidate_filetype) const; bool is_open() const noexcept { return bool(m_file); } - util::core_file &image_core_file() const noexcept { return *m_file; } + util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; } bool is_readonly() const noexcept { return m_readonly; } + u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc + util::notifier_subscription add_media_change_notifier(delegate<void (media_change_event)> &&n); + template <typename T> + util::notifier_subscription add_media_change_notifier(T &&n) + { return add_media_change_notifier(delegate<void (media_change_event)>(std::forward<T>(n))); } + // image file I/O wrappers // TODO: move away from using these and let implementations use the I/O interface directly // FIXME: don't swallow errors @@ -181,15 +148,13 @@ public: u32 fread(void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->read(buffer, length, actual); + auto const [err, actual] = read(*m_file, buffer, length); return actual; } u32 fwrite(const void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->write(buffer, length, actual); + auto const [err, actual] = write(*m_file, buffer, length); return actual; } std::error_condition fseek(s64 offset, int whence) @@ -204,32 +169,6 @@ public: m_file->tell(result); return result; } - int fgetc() - { - char ch; - if (fread(&ch, 1) != 1) - ch = '\0'; - return ch; - } - char *fgets(char *buffer, u32 length) - { - check_for_file(); - return m_file->gets(buffer, length); - } - bool image_feof() - { - check_for_file(); - return m_file->eof(); - } - const void *ptr() - { - check_for_file(); - return m_file->buffer(); - } - - // allocate and read into buffers - u32 fread(std::unique_ptr<u8 []> &ptr, u32 length) { ptr = std::make_unique<u8 []>(length); return fread(ptr.get(), length); } - u32 fread(std::unique_ptr<u8 []> &ptr, u32 length, offs_t offset) { ptr = std::make_unique<u8 []>(length); return fread(ptr.get() + offset, length - offset); } // access to software list item information const software_info *software_entry() const noexcept; @@ -243,67 +182,62 @@ public: const std::string &working_directory() const { return m_working_directory; } // access to software list properties and ROM data areas - u8 *get_software_region(const char *tag); - u32 get_software_region_length(const char *tag); - const char *get_feature(const char *feature_name) const; - bool load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr); + u8 *get_software_region(std::string_view tag); + u32 get_software_region_length(std::string_view tag); + const char *get_feature(std::string_view feature_name) const; + std::error_condition load_software_region(std::string_view tag, std::unique_ptr<u8[]> &ptr); u32 crc(); - util::hash_collection& hash() { return m_hash; } - util::hash_collection calculate_hash_on_file(util::core_file &file) const; + util::hash_collection &hash() { return m_hash; } + util::hash_collection calculate_hash_on_file(util::random_read &file) const; void battery_load(void *buffer, int length, int fill); void battery_load(void *buffer, int length, const void *def_buffer); void battery_save(const void *buffer, int length); - const char *image_type_name() const { return device_typename(image_type()); } - const std::string &instance_name() const { return m_instance_name; } const std::string &brief_instance_name() const { return m_brief_instance_name; } const std::string &canonical_instance_name() const { return m_canonical_instance_name; } - bool uses_file_extension(const char *file_extension) const; const formatlist_type &formatlist() const { return m_formatlist; } // loads an image file - image_init_result load(std::string_view path); + std::pair<std::error_condition, std::string> load(std::string_view path); // loads a softlist item by name - image_init_result load_software(std::string_view software_identifier); + std::pair<std::error_condition, std::string> load_software(std::string_view software_identifier); - image_init_result finish_load(); + std::pair<std::error_condition, std::string> finish_load(); void unload(); - image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); - image_init_result create(std::string_view path); - bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); + std::pair<std::error_condition, std::string> create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); + std::pair<std::error_condition, std::string> create(std::string_view path); + std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); std::error_condition reopen_for_write(std::string_view path); - void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } + void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; } + void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; } bool user_loadable() const noexcept { return m_user_loadable; } + bool must_be_loaded() const noexcept { return m_must_be_loaded; } bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } const std::string &full_software_name() const noexcept { return m_full_software_name; } protected: - // interface-level overrides + // device_interface implementation virtual void interface_config_complete() override; virtual const software_list_loader &get_software_list_loader() const; - virtual const bool use_software_list_file_extension_for_filetype() const { return false; } + virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; } - image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); std::error_condition load_image_by_path(u32 open_flags, std::string_view path); - void clear(); - bool is_loaded() const { return m_file != nullptr; } + bool is_loaded() const noexcept { return m_file != nullptr; } - void set_image_filename(std::string_view filename); - - void clear_error(); + void set_image_tag(); void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } void make_readonly() noexcept { m_readonly = true; } - bool image_checkhash(); + std::error_condition image_checkhash(); const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; std::string software_get_default_slot(std::string_view default_card_slot) const; @@ -311,17 +245,21 @@ protected: void add_format(std::unique_ptr<image_device_format> &&format); void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); - // derived class overrides +private: + std::vector<u32> determine_open_plan(bool is_create); + void update_names(); + void set_image_filename(std::string_view filename); + void clear() noexcept; + std::pair<std::error_condition, std::string> load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); + std::error_condition load_software_part(std::string_view identifier); - // configuration - static const image_device_type_info *find_device_type(iodevice_t type); - static const image_device_type_info m_device_info_array[]; + bool init_phase() const; + static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - // error related info - std::error_condition m_err; - std::string m_err_message; + // loads an image or software items and resets - called internally when we + // load an is_reset_on_load() item + void reset_and_load(std::string_view path); -private: // variables that are only non-zero when an image is mounted util::core_file::ptr m_file; std::unique_ptr<emu_file> m_mame_file; @@ -330,29 +268,27 @@ private: std::string m_basename_noext; std::string m_filetype; + // preset images regions + std::vector<std::string> m_possible_preset_regions; + std::vector<chd_file *> m_preset_images; + int m_default_region, m_current_region; + // Software information std::string m_full_software_name; const software_part *m_software_part_ptr; std::string m_software_list_name; - std::vector<u32> determine_open_plan(bool is_create); - void update_names(); - bool load_software_part(std::string_view identifier); - - bool init_phase() const; - static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - - // loads an image or software items and resets - called internally when we - // load an is_reset_on_load() item - void reset_and_load(std::string_view path); - // creation info formatlist_type m_formatlist; // working directory; persists across mounts std::string m_working_directory; + // to notify interested parties when media changes + util::notifier<media_change_event> m_media_change_notifier; + // flags + u32 m_sequence_counter; bool m_readonly; bool m_created; @@ -370,6 +306,8 @@ private: // we want to disable command line cart loading... bool m_user_loadable; + bool m_must_be_loaded; + bool m_is_loading; bool m_is_reset_and_loading; @@ -378,4 +316,4 @@ private: // iterator typedef device_interface_enumerator<device_image_interface> image_interface_enumerator; -#endif /* MAME_EMU_DIIMAGE_H */ +#endif // MAME_EMU_DIIMAGE_H diff --git a/src/emu/dimemory.cpp b/src/emu/dimemory.cpp index aa438fd22c0..81958b4f571 100644 --- a/src/emu/dimemory.cpp +++ b/src/emu/dimemory.cpp @@ -66,9 +66,10 @@ void device_memory_interface::set_addrmap(int spacenum, address_map_constructor // translation is supported //------------------------------------------------- -bool device_memory_interface::memory_translate(int spacenum, int intention, offs_t &address) +bool device_memory_interface::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { // by default it maps directly + target_space = &space(spacenum); return true; } diff --git a/src/emu/dimemory.h b/src/emu/dimemory.h index 119ec9bc6f9..14cd4d48ae2 100644 --- a/src/emu/dimemory.h +++ b/src/emu/dimemory.h @@ -19,34 +19,6 @@ #include <type_traits> - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// Translation intentions -constexpr int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch -constexpr int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged -constexpr int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects) - -constexpr int TRANSLATE_READ = 0; // translate for read -constexpr int TRANSLATE_WRITE = 1; // translate for write -constexpr int TRANSLATE_FETCH = 2; // translate for instruction fetch -constexpr int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK); -constexpr int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK); -constexpr int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK); -constexpr int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK); -constexpr int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK); -constexpr int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK); - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> device_memory_interface - class device_memory_interface : public device_interface { friend class device_scheduler; @@ -57,6 +29,13 @@ class device_memory_interface : public device_interface template <typename T, typename U> using is_unrelated_interface = std::bool_constant<emu::detail::is_device_interface<T>::value && !is_related_class<T, U>::value >; public: + // Translation intentions for the translate() call + enum { + TR_READ, + TR_WRITE, + TR_FETCH + }; + // construction/destruction device_memory_interface(const machine_config &mconfig, device_t &device); virtual ~device_memory_interface(); @@ -85,7 +64,7 @@ public: address_space &space(int index = 0) const { assert(index >= 0 && index < int(m_addrspace.size()) && m_addrspace[index]); return *m_addrspace[index]; } // address translation - bool translate(int spacenum, int intention, offs_t &address) { return memory_translate(spacenum, intention, address); } + bool translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { return memory_translate(spacenum, intention, address, target_space); } // deliberately ambiguous functions; if you have the memory interface // just use it @@ -110,7 +89,7 @@ protected: virtual space_config_vector memory_space_config() const = 0; // optional operation overrides - virtual bool memory_translate(int spacenum, int intention, offs_t &address); + virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space); // interface-level overrides virtual void interface_config_complete() override; diff --git a/src/emu/dinetwork.cpp b/src/emu/dinetwork.cpp index 69cc7e9235f..bbc5ee3054d 100644 --- a/src/emu/dinetwork.cpp +++ b/src/emu/dinetwork.cpp @@ -1,14 +1,23 @@ // license:BSD-3-Clause // copyright-holders:Carl, Miodrag Milanovic + #include "emu.h" +#include "dinetwork.h" + #include "osdnet.h" -device_network_interface::device_network_interface(const machine_config &mconfig, device_t &device, float bandwidth) +#include <algorithm> + + +device_network_interface::device_network_interface(const machine_config &mconfig, device_t &device, u32 bandwidth, u32 mtu) : device_interface(device, "network") + , m_poll_timer(nullptr) + , m_send_timer(nullptr) + , m_recv_timer(nullptr) { - m_promisc = false; - m_bandwidth = bandwidth; - set_mac("\0\0\0\0\0\0"); + // Convert to Mibps to Bps + m_bandwidth = bandwidth << (20 - 3); + m_mtu = mtu; m_intf = -1; m_loopback_control = false; } @@ -17,15 +26,23 @@ device_network_interface::~device_network_interface() { } -void device_network_interface::interface_pre_start() +void device_network_interface::interface_post_start() { + m_poll_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::poll_device), this)); m_send_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::send_complete), this)); m_recv_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::recv_complete), this)); + + device().save_item(NAME(m_loopback_control)); } -void device_network_interface::interface_post_start() +void device_network_interface::interface_post_load() { - device().save_item(NAME(m_loopback_control)); + if (!m_dev) + m_poll_timer->reset(); + else if (!m_loopback_control && !m_recv_timer->enabled()) + start_net_device(); + else + stop_net_device(); } int device_network_interface::send(u8 *buf, int len, int fcs) @@ -44,7 +61,7 @@ int device_network_interface::send(u8 *buf, int len, int fcs) if (result) { // schedule receive complete callback - m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result); + m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result); } } else if (m_dev) @@ -56,11 +73,30 @@ int device_network_interface::send(u8 *buf, int len, int fcs) } // schedule transmit complete callback - m_send_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result); + m_send_timer->adjust(attotime::from_ticks(len, m_bandwidth), result); return result; } +TIMER_CALLBACK_MEMBER(device_network_interface::poll_device) +{ + m_dev->poll(); +} + +void device_network_interface::start_net_device() +{ + // Set device polling time to transfer time for one MTU + m_dev->start(); + const attotime interval = attotime::from_hz(m_bandwidth / m_mtu); + m_poll_timer->adjust(attotime::zero, 0, interval); +} + +void device_network_interface::stop_net_device() +{ + m_poll_timer->reset(); + m_dev->stop(); +} + TIMER_CALLBACK_MEMBER(device_network_interface::send_complete) { send_complete_cb(param); @@ -81,10 +117,10 @@ void device_network_interface::recv_cb(u8 *buf, int len) { // stop receiving more data from the network if (m_dev) - m_dev->stop(); + stop_net_device(); // schedule receive complete callback - m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result); + m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result); } } @@ -94,27 +130,36 @@ TIMER_CALLBACK_MEMBER(device_network_interface::recv_complete) // start receiving data from the network again if (m_dev && !m_loopback_control) - m_dev->start(); + start_net_device(); } void device_network_interface::set_promisc(bool promisc) { m_promisc = promisc; - if(m_dev) m_dev->set_promisc(promisc); + if (m_dev) + m_dev->set_promisc(promisc); } -void device_network_interface::set_mac(const char *mac) +void device_network_interface::set_mac(const u8 *mac) { - memcpy(m_mac, mac, 6); - if(m_dev) m_dev->set_mac(m_mac); + std::copy_n(mac, std::size(m_mac), std::begin(m_mac)); + if (m_dev) + m_dev->set_mac(&m_mac[0]); } void device_network_interface::set_interface(int id) { - if(m_dev) - m_dev->stop(); - m_dev.reset(open_netdev(id, this, (int)(m_bandwidth*1000000/8.0f/1500))); - if(!m_dev) { + if (m_dev) + stop_net_device(); + + m_dev.reset(open_netdev(id, *this)); + if (m_dev) + { + if (!m_loopback_control) + start_net_device(); + } + else + { device().logerror("Network interface %d not found\n", id); id = -1; } @@ -131,8 +176,8 @@ void device_network_interface::set_loopback(bool loopback) if (m_dev) { if (loopback) - m_dev->stop(); + stop_net_device(); else if (!m_recv_timer->enabled()) - m_dev->start(); + start_net_device(); } } diff --git a/src/emu/dinetwork.h b/src/emu/dinetwork.h index 99909e93905..522f8b8d041 100644 --- a/src/emu/dinetwork.h +++ b/src/emu/dinetwork.h @@ -3,30 +3,31 @@ #ifndef MAME_EMU_DINETWORK_H #define MAME_EMU_DINETWORK_H -class osd_netdev; +#include "interface/nethandler.h" -class device_network_interface : public device_interface + +class osd_network_device; + +class device_network_interface : public device_interface, public osd::network_handler { public: - device_network_interface(const machine_config &mconfig, device_t &device, float bandwidth); + device_network_interface(const machine_config &mconfig, device_t &device, u32 bandwidth, u32 mtu = 1500); virtual ~device_network_interface(); - void interface_pre_start() override; - void interface_post_start() override; + void interface_post_start() override ATTR_COLD; + void interface_post_load() override ATTR_COLD; - void set_interface(int id); + void set_interface(int id) ATTR_COLD; void set_promisc(bool promisc); - void set_mac(const char *mac); + void set_mac(const u8 *mac); void set_loopback(bool loopback); - const char *get_mac() const { return m_mac; } - bool get_promisc() const { return m_promisc; } int get_interface() const { return m_intf; } int send(u8 *buf, int len, int fcs = 0); // TODO: de-virtualise this when existing devices implement delayed receive - virtual void recv_cb(u8 *buf, int len); + virtual void recv_cb(u8 *buf, int len) override; // delayed transmit/receive handlers virtual void send_complete_cb(int result) {} @@ -34,16 +35,25 @@ public: virtual void recv_complete_cb(int result) {} protected: - TIMER_CALLBACK_MEMBER(send_complete); - TIMER_CALLBACK_MEMBER(recv_complete); + bool has_net_device() const noexcept { return bool(m_dev); } - bool m_promisc; - char m_mac[6]; - float m_bandwidth; - std::unique_ptr<osd_netdev> m_dev; + // bandwidth in bytes per second + u32 m_bandwidth; + // maximum transmission unit, used for device polling time + u32 m_mtu; int m_intf; bool m_loopback_control; +private: + TIMER_CALLBACK_MEMBER(poll_device); + TIMER_CALLBACK_MEMBER(send_complete); + TIMER_CALLBACK_MEMBER(recv_complete); + + void start_net_device(); + void stop_net_device(); + + std::unique_ptr<osd_network_device> m_dev; + emu_timer *m_poll_timer; emu_timer *m_send_timer; emu_timer *m_recv_timer; }; diff --git a/src/emu/dinvram.cpp b/src/emu/dinvram.cpp index c2ba7408849..7a3ec7f658f 100644 --- a/src/emu/dinvram.cpp +++ b/src/emu/dinvram.cpp @@ -20,8 +20,9 @@ // device_nvram_interface - constructor //------------------------------------------------- -device_nvram_interface::device_nvram_interface(const machine_config &mconfig, device_t &device) +device_nvram_interface::device_nvram_interface(const machine_config &mconfig, device_t &device, bool backup_enabled) : device_interface(device, "nvram") + , m_backup_enabled(backup_enabled) { } diff --git a/src/emu/dinvram.h b/src/emu/dinvram.h index fb02a9c6e14..0efcc9d1054 100644 --- a/src/emu/dinvram.h +++ b/src/emu/dinvram.h @@ -30,21 +30,28 @@ class device_nvram_interface : public device_interface { public: // construction/destruction - device_nvram_interface(const machine_config &mconfig, device_t &device); + device_nvram_interface(const machine_config &mconfig, device_t &device, bool backup_enabled = true); virtual ~device_nvram_interface(); + // configuration + void nvram_enable_backup(bool enabled) { assert(!device().started()); m_backup_enabled = enabled; } + // public accessors... for now void nvram_reset() { nvram_default(); } - void nvram_load(emu_file &file) { nvram_read(file); } - void nvram_save(emu_file &file) { nvram_write(file); } - bool nvram_can_save() { return nvram_can_write(); } + bool nvram_load(util::read_stream &file) { return nvram_read(file); } + bool nvram_save(util::write_stream &file) { return nvram_write(file); } + bool nvram_backup_enabled() const noexcept { return m_backup_enabled; } + bool nvram_can_save() const { return m_backup_enabled && nvram_can_write(); } protected: // derived class overrides virtual void nvram_default() = 0; - virtual void nvram_read(emu_file &file) = 0; - virtual void nvram_write(emu_file &file) = 0; - virtual bool nvram_can_write() { return true; } + virtual bool nvram_read(util::read_stream &file) = 0; + virtual bool nvram_write(util::write_stream &file) = 0; + virtual bool nvram_can_write() const { return true; } + +private: + bool m_backup_enabled; }; // iterator diff --git a/src/emu/dipalette.h b/src/emu/dipalette.h index 1e84b2848e8..5d7f6b30506 100644 --- a/src/emu/dipalette.h +++ b/src/emu/dipalette.h @@ -43,8 +43,8 @@ class device_palette_interface : public device_interface public: // getters - u32 entries() const { return palette_entries(); } - u32 indirect_entries() const { return palette_indirect_entries(); } + u32 entries() const noexcept { return palette_entries(); } + u32 indirect_entries() const noexcept { return palette_indirect_entries(); } palette_t *palette() const { return m_palette; } const pen_t &pen(int index) const { return m_pens[index]; } const pen_t *pens() const { return m_pens; } @@ -53,8 +53,8 @@ public: double pen_contrast(pen_t pen) const { return m_palette->entry_contrast(pen); } pen_t black_pen() const { return m_black_pen; } pen_t white_pen() const { return m_white_pen; } - bool shadows_enabled() const { return palette_shadows_enabled(); } - bool hilights_enabled() const { return palette_hilights_enabled(); } + bool shadows_enabled() const noexcept { return palette_shadows_enabled(); } + bool hilights_enabled() const noexcept { return palette_hilights_enabled(); } // setters void set_pen_color(pen_t pen, rgb_t rgb) { m_palette->entry_set_color(pen, rgb); } @@ -92,10 +92,10 @@ protected: virtual void interface_post_stop() override; // configuration-related overrides - virtual u32 palette_entries() const = 0; - virtual u32 palette_indirect_entries() const { return 0; } - virtual bool palette_shadows_enabled() const { return false; } - virtual bool palette_hilights_enabled() const { return false; } + virtual u32 palette_entries() const noexcept = 0; + virtual u32 palette_indirect_entries() const noexcept { return 0; } + virtual bool palette_shadows_enabled() const noexcept { return false; } + virtual bool palette_hilights_enabled() const noexcept { return false; } private: // internal helpers diff --git a/src/emu/dipty.h b/src/emu/dipty.h index 9fc1ddbc7e1..d2e92f14969 100644 --- a/src/emu/dipty.h +++ b/src/emu/dipty.h @@ -27,7 +27,7 @@ public: bool is_open() const; - ssize_t read(u8 *rx_chars , size_t count) const; + ssize_t read(u8 *rx_chars, size_t count) const; void write(u8 tx_char) const; bool is_slave_connected() const; diff --git a/src/emu/dirom.h b/src/emu/dirom.h index 8243400c547..72d844f8b0e 100644 --- a/src/emu/dirom.h +++ b/src/emu/dirom.h @@ -22,6 +22,7 @@ public: template <typename... T> void set_map(T &&... args) { set_addrmap(0, std::forward<T>(args)...); } template <typename T> void set_device_rom_tag(T &&tag) { m_rom_region.set_tag(std::forward<T>(tag)); } + template <typename T> void set_space(T &&tag, int spacenum) { m_rom_space.set_tag(tag, spacenum); } u8 read_byte(offs_t addr) { return m_rom_cache.read_byte(addr); } u16 read_word(offs_t addr) { return m_rom_cache.read_word(addr); } @@ -32,13 +33,15 @@ public: void set_rom_bank(int bank); protected: - virtual void rom_bank_updated() = 0; + virtual void rom_bank_pre_change() { } + virtual void rom_bank_post_change() { } virtual space_config_vector memory_space_config() const override; void override_address_width(u8 width); private: optional_memory_region m_rom_region; + optional_address_space m_rom_space; address_space_config m_rom_config; typename memory_access<AddrWidth, DataWidth, AddrShift, Endian>::cache m_rom_cache; diff --git a/src/emu/dirom.ipp b/src/emu/dirom.ipp index 24697a0fbba..d41da70a618 100644 --- a/src/emu/dirom.ipp +++ b/src/emu/dirom.ipp @@ -9,6 +9,7 @@ template<int AddrWidth, int DataWidth, int AddrShift, endianness_t Endian> device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::device_rom_interface(const machine_config &mconfig, device_t &device) : device_memory_interface(mconfig, device), m_rom_region(device, DEVICE_SELF), + m_rom_space(device, finder_base::DUMMY_TAG, -1), m_rom_config("rom", Endian, 8 << DataWidth, AddrWidth, AddrShift), m_bank(device, "bank"), m_cur_bank(-1) @@ -45,9 +46,10 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::set_rom_bank } if (m_cur_bank != bank) { + rom_bank_pre_change(); m_cur_bank = bank; m_bank->set_entry(bank); - rom_bank_updated(); + rom_bank_post_change(); } } @@ -108,6 +110,11 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::interface_pr { device_memory_interface::interface_pre_start(); + if(m_rom_space.spacenum() != -1) { + m_rom_space->cache(m_rom_cache); + return; + } + if(!has_space(0)) return; diff --git a/src/emu/dirtc.cpp b/src/emu/dirtc.cpp index f3c61dede01..bf1a9366578 100644 --- a/src/emu/dirtc.cpp +++ b/src/emu/dirtc.cpp @@ -30,6 +30,7 @@ static const int DAYS_PER_MONTH[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, device_rtc_interface::device_rtc_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "rtc") + , m_use_utc(false) { } @@ -78,8 +79,9 @@ void device_rtc_interface::set_time(bool update, int year, int month, int day, i void device_rtc_interface::set_current_time(const system_time &systime) { - set_time(true, systime.local_time.year, systime.local_time.month + 1, systime.local_time.mday, systime.local_time.weekday + 1, - systime.local_time.hour, systime.local_time.minute, systime.local_time.second); + const system_time::full_time &time = m_use_utc ? systime.utc_time : systime.local_time; + set_time(true, time.year, time.month + 1, time.mday, time.weekday + 1, + time.hour, time.minute, time.second); } diff --git a/src/emu/dirtc.h b/src/emu/dirtc.h index 89a08deb830..e741cfc2628 100644 --- a/src/emu/dirtc.h +++ b/src/emu/dirtc.h @@ -47,8 +47,11 @@ public: device_rtc_interface(const machine_config &mconfig, device_t &device); virtual ~device_rtc_interface(); + // use UTC instead of local time when syncing at startup + void set_use_utc(bool use_utc) { m_use_utc = use_utc; } + void set_time(bool update, int year, int month, int day, int day_of_week, int hour, int minute, int second); - void set_current_time(const system_time &systime); + virtual void set_current_time(const system_time &systime); bool has_battery() const { return rtc_battery_backed(); } @@ -72,6 +75,8 @@ protected: virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) = 0; int m_register[7]; + + bool m_use_utc; }; // iterator diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp index 21da108c045..e88aaafc3ca 100644 --- a/src/emu/diserial.cpp +++ b/src/emu/diserial.cpp @@ -10,9 +10,9 @@ #include "emu.h" #include "diserial.h" -#define LOG_SETUP (1 << 1U) -#define LOG_TX (1 << 2U) -#define LOG_RX (1 << 3U) +#define LOG_SETUP (1U << 1) +#define LOG_TX (1U << 2) +#define LOG_RX (1U << 3) #define VERBOSE (0) #define LOG_OUTPUT_FUNC device().logerror @@ -138,7 +138,7 @@ void device_serial_interface::rcv_edge() } } -WRITE_LINE_MEMBER(device_serial_interface::tx_clock_w) +void device_serial_interface::tx_clock_w(int state) { if(state != m_tra_clock_state) { m_tra_clock_state = state; @@ -147,7 +147,7 @@ WRITE_LINE_MEMBER(device_serial_interface::tx_clock_w) } } -WRITE_LINE_MEMBER(device_serial_interface::rx_clock_w) +void device_serial_interface::rx_clock_w(int state) { if(state != m_rcv_clock_state) { m_rcv_clock_state = state; @@ -156,7 +156,7 @@ WRITE_LINE_MEMBER(device_serial_interface::rx_clock_w) } } -WRITE_LINE_MEMBER(device_serial_interface::clock_w) +void device_serial_interface::clock_w(int state) { tx_clock_w(state); rx_clock_w(state); @@ -216,19 +216,21 @@ void device_serial_interface::receive_register_reset() } } -WRITE_LINE_MEMBER(device_serial_interface::rx_w) +void device_serial_interface::rx_w(int state) { m_rcv_line = state; - if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) + if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) return; receive_register_update_bit(state); - if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) + if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) { LOGMASKED(LOG_RX, "Receiver is synchronized\n"); - if(m_rcv_clock && !(m_rcv_rate.is_never())) - // make start delay just a bit longer to make sure we are called after the sender - m_rcv_clock->adjust(((m_rcv_rate*3)/2), 0, m_rcv_rate); - else if(m_start_bit_hack_for_external_clocks) + if (m_rcv_clock && !(m_rcv_rate.is_never())) + { + // make start delay half a cycle longer to make sure we are called after the sender + m_rcv_clock->adjust(m_rcv_rate*2, 0, m_rcv_rate); + } + else if (m_start_bit_hack_for_external_clocks) m_rcv_bit_count_received--; } return; @@ -261,7 +263,7 @@ void device_serial_interface::receive_register_update_bit(int bit) /* yes */ if (bit==0) { - LOGMASKED(LOG_RX, "Receiver saw start bit\n"); + LOGMASKED(LOG_RX, "Receiver saw start bit (%s)\n", device().machine().time().to_string()); /* seen start bit! */ /* not waiting for start bit now! */ @@ -274,10 +276,9 @@ void device_serial_interface::receive_register_update_bit(int bit) } } } - else - if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) + else if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED) { - LOGMASKED(LOG_RX, "Received bit %d as %d\n", m_rcv_bit_count_received, bit); + LOGMASKED(LOG_RX, "Received bit %d as %d (%s)\n", m_rcv_bit_count_received, bit, device().machine().time().to_string()); m_rcv_bit_count_received++; if (!bit && (m_rcv_bit_count_received > (m_rcv_bit_count - m_df_stop_bit_count))) @@ -312,6 +313,7 @@ void device_serial_interface::receive_register_extract() data &= ~(0xff<<m_df_word_length); m_rcv_byte_received = data; + LOGMASKED(LOG_RX, "Receive data 0x%02x\n", m_rcv_byte_received); if(m_df_parity == PARITY_NONE) return; @@ -437,9 +439,9 @@ u8 device_serial_interface::transmit_register_get_data_bit() bit = (m_tra_register_data>>(m_tra_bit_count-1-m_tra_bit_count_transmitted))&1; if (m_tra_bit_count_transmitted < m_df_start_bit_count) - LOGMASKED(LOG_TX, "Transmitting start bit as %d\n", m_tra_bit_count_transmitted, bit); + LOGMASKED(LOG_TX, "Transmitting start bit %d as %d (%s)\n", m_tra_bit_count_transmitted, bit, device().machine().time().to_string()); else - LOGMASKED(LOG_TX, "Transmitting bit %d as %d\n", m_tra_bit_count_transmitted - m_df_start_bit_count, bit); + LOGMASKED(LOG_TX, "Transmitting bit %d as %d (%s)\n", m_tra_bit_count_transmitted - m_df_start_bit_count, bit, device().machine().time().to_string()); m_tra_bit_count_transmitted++; /* have all bits of this stream formatted byte been sent? */ diff --git a/src/emu/diserial.h b/src/emu/diserial.h index 62b13c028a1..aab03940206 100644 --- a/src/emu/diserial.h +++ b/src/emu/diserial.h @@ -76,10 +76,10 @@ public: device_serial_interface(const machine_config &mconfig, device_t &device); virtual ~device_serial_interface(); - DECLARE_WRITE_LINE_MEMBER(rx_w); - DECLARE_WRITE_LINE_MEMBER(tx_clock_w); - DECLARE_WRITE_LINE_MEMBER(rx_clock_w); - DECLARE_WRITE_LINE_MEMBER(clock_w); + void rx_w(int state); + void tx_clock_w(int state); + void rx_clock_w(int state); + void clock_w(int state); protected: void set_data_frame(int start_bit_count, int data_bit_count, parity_t parity, stop_bits_t stop_bits); diff --git a/src/emu/dislot.cpp b/src/emu/dislot.cpp index e30cd41d46f..43d2ed96cdd 100644 --- a/src/emu/dislot.cpp +++ b/src/emu/dislot.cpp @@ -8,9 +8,10 @@ #include "emu.h" #include "emuopts.h" + +#include "corestr.h" +#include "path.h" #include "zippath.h" -#include <algorithm> -#include <cctype> device_slot_interface::device_slot_interface(const machine_config &mconfig, device_t &device) : @@ -27,7 +28,7 @@ device_slot_interface::~device_slot_interface() } -device_slot_interface::slot_option::slot_option(const char *name, const device_type &devtype, bool selectable) : +device_slot_interface::slot_option::slot_option(const char *name, device_type devtype, bool selectable) : m_name(name), m_devtype(devtype), m_selectable(selectable), @@ -46,7 +47,7 @@ void device_slot_interface::interface_validity_check(validity_checker &valid) co } -device_slot_interface::slot_option &device_slot_interface::option_add(const char *name, const device_type &devtype) +device_slot_interface::slot_option &device_slot_interface::option_add(const char *name, device_type devtype) { if (!name || !*name) throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag()); @@ -59,7 +60,7 @@ device_slot_interface::slot_option &device_slot_interface::option_add(const char } -device_slot_interface::slot_option &device_slot_interface::option_add_internal(const char *name, const device_type &devtype) +device_slot_interface::slot_option &device_slot_interface::option_add_internal(const char *name, device_type devtype) { if (!name || !*name) throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag()); @@ -72,6 +73,42 @@ device_slot_interface::slot_option &device_slot_interface::option_add_internal(c } +device_slot_interface::slot_option &device_slot_interface::option_replace(const char *name, device_type devtype) +{ + if (!name || !*name) + throw emu_fatalerror("slot '%s' attempt to replace option without name\n", device().tag()); + + auto search = m_options.find(name); + if (search == m_options.end()) + throw emu_fatalerror("slot '%s' attempt to replace nonexistent option '%s'\n", device().tag(), name); + + return (search->second = std::make_unique<slot_option>(name, devtype, true))->clock(m_default_clock); +} + + +device_slot_interface::slot_option &device_slot_interface::option_replace_internal(const char *name, device_type devtype) +{ + if (!name || !*name) + throw emu_fatalerror("slot '%s' attempt to replace option without name\n", device().tag()); + + auto search = m_options.find(name); + if (search == m_options.end()) + throw emu_fatalerror("slot '%s' attempt to replace nonexistent option '%s'\n", device().tag(), name); + + return (search->second = std::make_unique<slot_option>(name, devtype, false))->clock(m_default_clock); +} + + +void device_slot_interface::option_remove(const char *name) +{ + if (!name || !*name) + throw emu_fatalerror("slot '%s' attempt to remove option without name\n", device().tag()); + + if (m_options.erase(name) == 0) + throw emu_fatalerror("slot '%s' attempt to remove nonexistent option '%s'\n", device().tag(), name); +} + + device_slot_interface::slot_option *device_slot_interface::config_option(const char *name) { auto const search = m_options.find(name); @@ -134,6 +171,5 @@ bool get_default_card_software_hook::hashfile_extrainfo(std::string &extrainfo) bool get_default_card_software_hook::is_filetype(std::string_view candidate_filetype) const { - return std::equal(m_file_type.begin(), m_file_type.end(), candidate_filetype.begin(), candidate_filetype.end(), - [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); + return util::streqlower(m_file_type, candidate_filetype); } diff --git a/src/emu/dislot.h b/src/emu/dislot.h index 97d314028a2..f6e1f86fcb3 100644 --- a/src/emu/dislot.h +++ b/src/emu/dislot.h @@ -46,10 +46,10 @@ public: class slot_option { public: - slot_option(char const *name, device_type const &devtype, bool selectable); + slot_option(char const *name, device_type devtype, bool selectable); char const *name() const { return m_name; } - device_type const &devtype() const { return m_devtype; } + device_type devtype() const { return m_devtype; } bool selectable() const { return m_selectable; } char const *default_bios() const { return m_default_bios; } std::function<void (device_t *)> const &machine_config() const { return m_machine_config; } @@ -83,7 +83,7 @@ public: /// \param [in] fixed True to mark the slot as fixed, or false to /// mark it user-configurable. /// \sa fixed - void set_fixed(bool fixed) { m_fixed = fixed; } + device_slot_interface &set_fixed(bool fixed) { m_fixed = fixed; return *this; } /// \brief Set the default option /// @@ -97,12 +97,12 @@ public: /// valid for the lifetime of the device (or until another default /// option is configured). /// \sa default_option - void set_default_option(const char *option) { m_default_option = option; } + device_slot_interface &set_default_option(const char *option) { m_default_option = option; return *this; } /// \brief Clear options /// /// This removes all previously added options. - void option_reset() { m_options.clear(); } + device_slot_interface &option_reset() { m_options.clear(); return *this; } /// \brief Add a user-selectable option /// @@ -116,7 +116,7 @@ public: /// description is used in the user interface. /// \return A reference to the added option for additional /// configuration. - slot_option &option_add(char const *option, const device_type &devtype); + slot_option &option_add(char const *option, device_type devtype); /// \brief Add an internal option /// @@ -130,7 +130,11 @@ public: /// description is used in the user interface. /// \return A reference to the added option for additional /// configuration. - slot_option &option_add_internal(const char *option, const device_type &devtype); + slot_option &option_add_internal(const char *option, device_type devtype); + + slot_option &option_replace(const char *option, device_type devtype); + slot_option &option_replace_internal(const char *option, device_type devtype); + void option_remove(const char *option); void set_option_default_bios(const char *option, const char *default_bios) { config_option(option)->default_bios(default_bios); } template <typename T> void set_option_machine_config(const char *option, T &&machine_config) { config_option(option)->machine_config(std::forward<T>(machine_config)); } @@ -162,7 +166,7 @@ public: device_t *get_card_device() const { return m_card_device; } void set_card_device(device_t *dev) { m_card_device = dev; } const char *slot_name() const { return device().tag() + 1; } - slot_option &option_set(const char *tag, const device_type &devtype) { m_default_option = tag; m_fixed = true; return option_add_internal(tag, devtype); } + slot_option &option_set(const char *tag, device_type devtype) { m_default_option = tag; m_fixed = true; return option_add_internal(tag, devtype); } protected: device_slot_interface(machine_config const &mconfig, device_t &device); diff --git a/src/emu/distate.cpp b/src/emu/distate.cpp index 0d94c4dcf81..76ede23dfe2 100644 --- a/src/emu/distate.cpp +++ b/src/emu/distate.cpp @@ -101,7 +101,7 @@ device_state_entry &device_state_entry::formatstr(const char *_format) // set the DSF_CUSTOM_STRING flag by formatting with a nullptr string m_flags &= ~DSF_CUSTOM_STRING; - format(nullptr); + format(nullptr, 0); return *this; } @@ -127,9 +127,7 @@ void device_state_entry::format_from_mask() // make up a format based on the mask if (m_datamask == 0) throw emu_fatalerror("%s state entry requires a nonzero mask\n", m_symbol); - int width = 0; - for (u64 tempmask = m_datamask; tempmask != 0; tempmask >>= 4) - width++; + int width = (63 - count_leading_zeros_64(m_datamask)) / 4 + 1; m_format = string_format("%%0%dX", width); } @@ -201,12 +199,10 @@ double device_state_entry::entry_dvalue() const // pieces of indexed state as a string //------------------------------------------------- -std::string device_state_entry::format(const char *string, bool maxout) const +std::string device_state_entry::format(const char *string, u64 result, bool maxout) const { - std::string dest; - u64 result = entry_value() & m_datamask; - // parse the format + std::string dest; bool leadzero = false; bool percent = false; bool explicitsign = false; @@ -400,7 +396,7 @@ std::string device_state_entry::to_string() const custom = string_format("%-12G", entry_dvalue()); // ask the entry to format itself - return format(custom.c_str()); + return format(custom.c_str(), value()); } @@ -412,7 +408,7 @@ std::string device_state_entry::to_string() const int device_state_entry::max_length() const { // ask the entry to format itself maximally - return format("", true).length(); + return format("", 0, true).length(); } diff --git a/src/emu/distate.h b/src/emu/distate.h index f0cf04eadeb..b4727c259f4 100644 --- a/src/emu/distate.h +++ b/src/emu/distate.h @@ -104,10 +104,10 @@ protected: private: // helpers void format_from_mask(); - std::string format(const char *string, bool maxout = false) const; + std::string format(const char *string, u64 result, bool maxout = false) const; // statics - static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values + static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values // public state description device_state_interface *m_device_state; // link to parent device state @@ -286,12 +286,14 @@ class device_state_interface : public device_interface friend class device_state_entry; public: + using entrylist_type = std::vector<std::unique_ptr<device_state_entry> >; + // construction/destruction device_state_interface(const machine_config &mconfig, device_t &device); virtual ~device_state_interface(); // configuration access - const std::vector<std::unique_ptr<device_state_entry>> &state_entries() const { return m_state_list; } + const entrylist_type &state_entries() const { return m_state_list; } // state getters u64 state_int(int index) const { const device_state_entry *entry = state_find_entry(index); return (entry == nullptr) ? 0 : entry->value(); } @@ -357,13 +359,12 @@ protected: virtual void interface_post_start() override; // constants - static constexpr int FAST_STATE_MIN = -4; // range for fast state - static constexpr int FAST_STATE_MAX = 256; // lookups + static constexpr int FAST_STATE_MIN = -4; // range for fast state + static constexpr int FAST_STATE_MAX = 256; // lookups // state - std::vector<std::unique_ptr<device_state_entry>> m_state_list; // head of state list - device_state_entry * m_fast_state[FAST_STATE_MAX + 1 - FAST_STATE_MIN]; - // fast access to common entries + entrylist_type m_state_list; // head of state list + device_state_entry *m_fast_state[FAST_STATE_MAX + 1 - FAST_STATE_MIN]; // fast access to common entries }; // iterator diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp index 41a0aa96aad..ec0469cac02 100644 --- a/src/emu/divtlb.cpp +++ b/src/emu/divtlb.cpp @@ -68,7 +68,7 @@ void device_vtlb_interface::interface_validity_check(validity_checker &valid) co const address_space_config *spaceconfig = intf->space_config(m_space); if (spaceconfig == nullptr) osd_printf_error("No memory address space configuration found for space %d\n", m_space); - else if ((1 << spaceconfig->page_shift()) <= VTLB_FLAGS_MASK || spaceconfig->logaddr_width() <= spaceconfig->page_shift()) + else if ((1 << spaceconfig->page_shift()) <= FLAGS_MASK || spaceconfig->logaddr_width() <= spaceconfig->page_shift()) osd_printf_error("Invalid page shift %d for VTLB\n", spaceconfig->page_shift()); } } @@ -142,11 +142,10 @@ void device_vtlb_interface::interface_pre_reset() // response to an unmapped access //------------------------------------------------- -bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) +bool device_vtlb_interface::vtlb_fill(offs_t address, offs_t taddress, int intention) { offs_t tableindex = address >> m_pageshift; vtlb_entry entry = m_table[tableindex]; - offs_t taddress; #if PRINTF_TLB osd_printf_debug("vtlb_fill: %08X(%X) ... ", address, intention); @@ -164,18 +163,8 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) return false; } - // ask the CPU core to translate for us - taddress = address; - if (!device().memory().translate(m_space, intention, taddress)) - { -#if PRINTF_TLB - osd_printf_debug("failed: no translation\n"); -#endif - return false; - } - // if this is the first successful translation for this address, allocate a new entry - if ((entry & VTLB_FLAGS_MASK) == 0) + if ((entry & FLAGS_MASK) == 0) { int liveindex = m_dynindex; @@ -196,7 +185,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) // form a new blank entry entry = (taddress >> m_pageshift) << m_pageshift; - entry |= VTLB_FLAG_VALID; + entry |= FLAG_VALID; #if PRINTF_TLB osd_printf_debug("success (%08X), new entry\n", taddress); @@ -207,7 +196,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) else { assert((entry >> m_pageshift) == (taddress >> m_pageshift)); - assert(entry & VTLB_FLAG_VALID); + assert(entry & FLAG_VALID); #if PRINTF_TLB osd_printf_debug("success (%08X), existing entry\n", taddress); @@ -215,7 +204,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention) } // add the intention to the list of valid intentions and store - entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)); + entry |= 1 << intention; m_table[tableindex] = entry; return true; } @@ -256,7 +245,7 @@ void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address m_refcnt[tableindex]++; // store the raw value, making sure the "fixed" flag is set - value |= VTLB_FLAG_FIXED; + value |= FLAG_FIXED; m_fixedpages[entrynum] = numpages; for (pagenum = 0; pagenum < numpages; pagenum++) m_table[tableindex + pagenum] = value + (pagenum << m_pageshift); @@ -283,7 +272,7 @@ void device_vtlb_interface::vtlb_dynload(u32 index, offs_t address, vtlb_entry v m_dynindex = (m_dynindex + 1) % m_dynamic; // is entry already live? - if (!(entry & VTLB_FLAG_VALID)) + if (!(entry & FLAG_VALID)) { // if an entry already exists at this index, free it if (m_live[liveindex] != 0) @@ -294,7 +283,7 @@ void device_vtlb_interface::vtlb_dynload(u32 index, offs_t address, vtlb_entry v } // form a new blank entry entry = (address >> m_pageshift) << m_pageshift; - entry |= VTLB_FLAG_VALID | value; + entry |= FLAG_VALID | value; #if PRINTF_TLB osd_printf_debug("success (%08X), new entry\n", address); @@ -356,7 +345,7 @@ void device_vtlb_interface::vtlb_flush_address(offs_t address) // the linear VTLB lookup table //------------------------------------------------- -const vtlb_entry *device_vtlb_interface::vtlb_table() const +const device_vtlb_interface::vtlb_entry *device_vtlb_interface::vtlb_table() const { return m_table_base; } diff --git a/src/emu/divtlb.h b/src/emu/divtlb.h index c64bca0a21c..13adbd4a4ce 100644 --- a/src/emu/divtlb.h +++ b/src/emu/divtlb.h @@ -13,38 +13,35 @@ #pragma once - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -constexpr u32 VTLB_FLAGS_MASK = 0xff; - -constexpr u32 VTLB_READ_ALLOWED = 0x01; /* (1 << TRANSLATE_READ) */ -constexpr u32 VTLB_WRITE_ALLOWED = 0x02; /* (1 << TRANSLATE_WRITE) */ -constexpr u32 VTLB_FETCH_ALLOWED = 0x04; /* (1 << TRANSLATE_FETCH) */ -constexpr u32 VTLB_FLAG_VALID = 0x08; -constexpr u32 VTLB_USER_READ_ALLOWED = 0x10; /* (1 << TRANSLATE_READ_USER) */ -constexpr u32 VTLB_USER_WRITE_ALLOWED = 0x20; /* (1 << TRANSLATE_WRITE_USER) */ -constexpr u32 VTLB_USER_FETCH_ALLOWED = 0x40; /* (1 << TRANSLATE_FETCH_USER) */ -constexpr u32 VTLB_FLAG_FIXED = 0x80; - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* represents an entry in the VTLB */ -typedef u32 vtlb_entry; - - -// ======================> device_vtlb_interface - class device_vtlb_interface : public device_interface { public: + using vtlb_entry = u32; + + // Translation type flags + // TR_READ/WRITE/FETCH come from device_memory_interface + enum { + TR_UREAD = 4, + TR_UWRITE = 5, + TR_UFETCH = 6, + + TR_TYPE = 3, + TR_USER = 4 + }; + + enum { + FLAGS_MASK = 0xff, + + READ_ALLOWED = 0x01, /* (1 << TR_READ) */ + WRITE_ALLOWED = 0x02, /* (1 << TR_WRITE) */ + FETCH_ALLOWED = 0x04, /* (1 << TR_FETCH) */ + FLAG_VALID = 0x08, + USER_READ_ALLOWED = 0x10, /* (1 << TR_UREAD) */ + USER_WRITE_ALLOWED = 0x20, /* (1 << TR_UWRITE) */ + USER_FETCH_ALLOWED = 0x40, /* (1 << TR_UFETCH) */ + FLAG_FIXED = 0x80 + }; + // construction/destruction device_vtlb_interface(const machine_config &mconfig, device_t &device, int space); virtual ~device_vtlb_interface(); @@ -54,7 +51,7 @@ public: void set_vtlb_fixed_entries(int entries) { m_fixed = entries; } // filling - bool vtlb_fill(offs_t address, int intention); + bool vtlb_fill(offs_t address, offs_t taddress, int intention); void vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value); void vtlb_dynload(u32 index, offs_t address, vtlb_entry value); diff --git a/src/emu/drawgfxt.ipp b/src/emu/drawgfxt.ipp index 4d756497102..4277bf21634 100644 --- a/src/emu/drawgfxt.ipp +++ b/src/emu/drawgfxt.ipp @@ -421,7 +421,7 @@ while (0) template <typename BitmapType, typename FunctionClass> inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, FunctionClass pixel_op) { - g_profiler.start(PROFILER_DRAWGFX); + auto profile = g_profiler.start(PROFILER_DRAWGFX); do { assert(dest.valid()); assert(dest.cliprect().contains(cliprect)); @@ -551,14 +551,13 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec } } } while (0); - g_profiler.stop(); } template <typename BitmapType, typename PriorityType, typename FunctionClass> inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, PriorityType &priority, FunctionClass pixel_op) { - g_profiler.start(PROFILER_DRAWGFX); + auto profile = g_profiler.start(PROFILER_DRAWGFX); do { assert(dest.valid()); assert(priority.valid()); @@ -695,7 +694,6 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec } } } while (0); - g_profiler.stop(); } @@ -724,7 +722,7 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec template <typename BitmapType, typename FunctionClass> inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, FunctionClass pixel_op) { - g_profiler.start(PROFILER_DRAWGFX); + auto profile = g_profiler.start(PROFILER_DRAWGFX); do { assert(dest.valid()); assert(dest.cliprect().contains(cliprect)); @@ -830,14 +828,13 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli } } } while (0); - g_profiler.stop(); } template <typename BitmapType, typename PriorityType, typename FunctionClass> inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, PriorityType &priority, FunctionClass pixel_op) { - g_profiler.start(PROFILER_DRAWGFX); + auto profile = g_profiler.start(PROFILER_DRAWGFX); do { assert(dest.valid()); assert(priority.valid()); @@ -877,10 +874,7 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli // compute final pixel in Y and exit if we are entirely clipped s32 destendy = desty + dstheight - 1; if (desty > cliprect.bottom() || destendy < cliprect.top()) - { - g_profiler.stop(); return; - } // apply top clip s32 srcy = 0; @@ -950,7 +944,6 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli } } } while (0); - g_profiler.stop(); } @@ -975,7 +968,7 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli template <typename BitmapType, typename FunctionClass> inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, FunctionClass pixel_op) { - g_profiler.start(PROFILER_COPYBITMAP); + auto profile = g_profiler.start(PROFILER_COPYBITMAP); do { assert(dest.valid()); assert(src.valid()); @@ -1108,14 +1101,13 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, } } } while (0); - g_profiler.stop(); } template <typename BitmapType, typename PriorityType, typename FunctionClass> inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, PriorityType &priority, FunctionClass pixel_op) { - g_profiler.start(PROFILER_COPYBITMAP); + auto profile = g_profiler.start(PROFILER_COPYBITMAP); do { assert(dest.valid()); assert(src.valid()); @@ -1255,7 +1247,6 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, } } } while (0); - g_profiler.stop(); } @@ -1283,7 +1274,7 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, template <typename BitmapType, typename FunctionClass> inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool wraparound, FunctionClass pixel_op) { - g_profiler.start(PROFILER_COPYBITMAP); + auto profile = g_profiler.start(PROFILER_COPYBITMAP); assert(dest.valid()); assert(dest.valid()); @@ -1293,10 +1284,7 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons // ignore empty/invalid cliprects if (cliprect.empty()) - { - g_profiler.stop(); return; - } // compute fixed-point 16.16 size of the source bitmap u32 srcfixwidth = src.width() << 16; @@ -1537,14 +1525,13 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons } } } - g_profiler.stop(); } template <typename BitmapType, typename PriorityType, typename FunctionClass> inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool wraparound, PriorityType &priority, FunctionClass pixel_op) { - g_profiler.start(PROFILER_COPYBITMAP); + auto profile = g_profiler.start(PROFILER_COPYBITMAP); assert(dest.valid()); assert(dest.valid()); @@ -1555,10 +1542,7 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons // ignore empty/invalid cliprects if (cliprect.empty()) - { - g_profiler.stop(); return; - } // compute fixed-point 16.16 size of the source bitmap u32 srcfixwidth = src.width() << 16; @@ -1811,7 +1795,6 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons } } } - g_profiler.stop(); } diff --git a/src/emu/driver.cpp b/src/emu/driver.cpp index 04c6489aae3..9b0dd9c5e59 100644 --- a/src/emu/driver.cpp +++ b/src/emu/driver.cpp @@ -67,7 +67,6 @@ void driver_device::static_set_callback(device_t &device, callback_type type, dr void driver_device::empty_init() { - driver_init(); } @@ -82,16 +81,6 @@ std::vector<std::string> driver_device::searchpath() const //------------------------------------------------- -// driver_init - default implementation which -// does nothing -//------------------------------------------------- - -void driver_device::driver_init() -{ -} - - -//------------------------------------------------- // driver_start - default implementation which // does nothing //------------------------------------------------- @@ -260,10 +249,7 @@ void driver_device::device_reset_after_children() sound_reset(); - if (!m_callbacks[CB_VIDEO_RESET].isnull()) - m_callbacks[CB_VIDEO_RESET](); - else - video_reset(); + video_reset(); } @@ -328,16 +314,16 @@ void driver_device::updateflip() // flip_screen_set - set global flip //------------------------------------------------- -void driver_device::flip_screen_set(u32 on) +void driver_device::flip_screen_set(int state) { // normalize to all 1 - if (on) - on = ~0; + if (state) + state = 0xff; // if something's changed, handle it - if (m_flip_screen_x != on || m_flip_screen_y != on) + if (m_flip_screen_x != state || m_flip_screen_y != state) { - m_flip_screen_x = m_flip_screen_y = on; + m_flip_screen_x = m_flip_screen_y = state; updateflip(); } } @@ -347,16 +333,16 @@ void driver_device::flip_screen_set(u32 on) // flip_screen_x_set - set global horizontal flip //------------------------------------------------- -void driver_device::flip_screen_x_set(u32 on) +void driver_device::flip_screen_x_set(int state) { // normalize to all 1 - if (on) - on = ~0; + if (state) + state = 0xff; // if something's changed, handle it - if (m_flip_screen_x != on) + if (m_flip_screen_x != state) { - m_flip_screen_x = on; + m_flip_screen_x = state; updateflip(); } } @@ -366,16 +352,16 @@ void driver_device::flip_screen_x_set(u32 on) // flip_screen_y_set - set global vertical flip //------------------------------------------------- -void driver_device::flip_screen_y_set(u32 on) +void driver_device::flip_screen_y_set(int state) { // normalize to all 1 - if (on) - on = ~0; + if (state) + state = 0xff; // if something's changed, handle it - if (m_flip_screen_y != on) + if (m_flip_screen_y != state) { - m_flip_screen_y = on; + m_flip_screen_y = state; updateflip(); } } diff --git a/src/emu/driver.h b/src/emu/driver.h index 0656775ab7b..75e035d46c9 100644 --- a/src/emu/driver.h +++ b/src/emu/driver.h @@ -26,6 +26,9 @@ #define MCFG_MACHINE_START_OVERRIDE(_class, _func) \ driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_START, driver_callback_delegate(&_class::MACHINE_START_NAME(_func), this)); +#define MCFG_MACHINE_START_REMOVE() \ + driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_START, driver_callback_delegate()); + #define MCFG_MACHINE_RESET_OVERRIDE(_class, _func) \ driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_RESET, driver_callback_delegate(&_class::MACHINE_RESET_NAME(_func), this)); @@ -37,8 +40,8 @@ #define MCFG_VIDEO_START_OVERRIDE(_class, _func) \ driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_START, driver_callback_delegate(&_class::VIDEO_START_NAME(_func), this)); -#define MCFG_VIDEO_RESET_OVERRIDE(_class, _func) \ - driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_RESET, driver_callback_delegate(&_class::VIDEO_RESET_NAME(_func), this)); +#define MCFG_VIDEO_START_REMOVE() \ + driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_START, driver_callback_delegate()); @@ -61,11 +64,6 @@ #define DECLARE_VIDEO_START(name) void VIDEO_START_NAME(name)() ATTR_COLD #define VIDEO_START_MEMBER(cls,name) void cls::VIDEO_START_NAME(name)() -#define VIDEO_RESET_NAME(name) video_reset_##name -#define VIDEO_RESET_CALL_MEMBER(name) VIDEO_RESET_NAME(name)() -#define DECLARE_VIDEO_RESET(name) void VIDEO_RESET_NAME(name)() -#define VIDEO_RESET_MEMBER(cls,name) void cls::VIDEO_RESET_NAME(name)() - //************************************************************************** @@ -100,7 +98,6 @@ public: CB_MACHINE_START, CB_MACHINE_RESET, CB_VIDEO_START, - CB_VIDEO_RESET, CB_COUNT }; @@ -145,8 +142,6 @@ public: virtual std::vector<std::string> searchpath() const override; - virtual void driver_init(); - protected: // helpers called at startup virtual void driver_start(); @@ -168,12 +163,12 @@ protected: virtual void device_reset_after_children() override; // generic video - void flip_screen_set(u32 on); - void flip_screen_x_set(u32 on); - void flip_screen_y_set(u32 on); - u32 flip_screen() const { return m_flip_screen_x; } - u32 flip_screen_x() const { return m_flip_screen_x; } - u32 flip_screen_y() const { return m_flip_screen_y; } + void flip_screen_set(int state); + void flip_screen_x_set(int state); + void flip_screen_y_set(int state); + u8 flip_screen() const { return m_flip_screen_x; } // & m_flip_screen_y? + u8 flip_screen_x() const { return m_flip_screen_x; } + u8 flip_screen_y() const { return m_flip_screen_y; } private: // helpers @@ -185,8 +180,8 @@ private: driver_callback_delegate m_callbacks[CB_COUNT]; // start/reset callbacks // generic video - u8 m_flip_screen_x; - u8 m_flip_screen_y; + u8 m_flip_screen_x; + u8 m_flip_screen_y; }; diff --git a/src/emu/drivers/empty.cpp b/src/emu/drivers/empty.cpp index 23cf5443013..9b907214487 100644 --- a/src/emu/drivers/empty.cpp +++ b/src/emu/drivers/empty.cpp @@ -9,8 +9,11 @@ **************************************************************************/ #include "emu.h" + #include "emuopts.h" -#include "render.h" +#include "main.h" +#include "screen.h" + //************************************************************************** // DRIVER STATE diff --git a/src/emu/drivers/testcpu.cpp b/src/emu/drivers/testcpu.cpp index 574e6fc88b3..95e3d5a1ec2 100644 --- a/src/emu/drivers/testcpu.cpp +++ b/src/emu/drivers/testcpu.cpp @@ -38,7 +38,7 @@ public: } // timer callback; used to wrest control of the system - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override + TIMER_CALLBACK_MEMBER(timer_tick) { static const u32 sample_instructions[] = { @@ -101,7 +101,7 @@ public: m_cpu->ppcdrc_set_options(PPCDRC_COMPATIBLE_OPTIONS); // set a timer to go off right away - timer_set(attotime::zero); + timer_alloc(FUNC(timer_tick), this)->adjust(attotime::zero); } // dump the current CPU state diff --git a/src/emu/emu.h b/src/emu/emu.h index d648ee932de..679687f772d 100644 --- a/src/emu/emu.h +++ b/src/emu/emu.h @@ -18,6 +18,9 @@ #ifndef __EMU_H__ #define __EMU_H__ +// get forward declarations before anything else +#include "emufwd.h" + #include <list> #include <forward_list> #include <vector> @@ -34,17 +37,13 @@ #include "attotime.h" #include "profiler.h" -// http interface helpers -#include "http.h" - // commonly-referenced utilities imported from lib/util -#include "corealloc.h" +#include "corefile.h" +#include "delegate.h" +#include "hash.h" #include "palette.h" // emulator-specific utilities -#include "hash.h" -#include "fileio.h" -#include "delegate.h" #include "devdelegate.h" // memory and address spaces @@ -73,7 +72,6 @@ #include "divideo.h" #include "dinvram.h" #include "schedule.h" -#include "dinetwork.h" // machine and driver configuration #include "mconfig.h" @@ -81,7 +79,6 @@ #include "parameters.h" // the running machine -#include "main.h" #include "machine.h" #include "driver.h" diff --git a/src/emu/emucore.cpp b/src/emu/emucore.cpp index bc6139fe3cf..d9a314cfaa2 100644 --- a/src/emu/emucore.cpp +++ b/src/emu/emucore.cpp @@ -13,13 +13,13 @@ #include "emucore.h" #include "osdcore.h" -emu_fatalerror::emu_fatalerror(util::format_argument_pack<std::ostream> const &args) +emu_fatalerror::emu_fatalerror(util::format_argument_pack<char> const &args) : emu_fatalerror(0, args) { osd_break_into_debugger(m_text.c_str()); } -emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args) +emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<char> const &args) : m_text(util::string_format(args)) , m_code(_exitcode) { diff --git a/src/emu/emucore.h b/src/emu/emucore.h index 768fa8c7280..ca54f5208cd 100644 --- a/src/emu/emucore.h +++ b/src/emu/emucore.h @@ -13,35 +13,38 @@ #pragma once -// standard C includes -#include <cassert> -#include <cmath> -#include <cstdio> -#include <cstring> -#include <cstdlib> -#include <cstdarg> - // some cleanups for Solaris for things defined in stdlib.h #if defined(__sun__) && defined(__svr4__) #undef si_status #undef WWORD #endif -// standard C++ includes -#include <exception> -#include <string> -#include <type_traits> -#include <typeinfo> +// centralised forward declarations +#include "emufwd.h" -// core system includes -#include "osdcomm.h" +// common stuff from lib/util +#include "corealloc.h" #include "coretmpl.h" #include "bitmap.h" #include "endianness.h" #include "strformat.h" #include "vecstream.h" -#include "emufwd.h" +// common stuff from osd +#include "osdcomm.h" + +// standard C++ includes +#include <exception> +#include <string> +#include <type_traits> +#include <typeinfo> + +// standard C includes +#include <cassert> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> //************************************************************************** @@ -95,6 +98,9 @@ using util::DWORD_XOR_BE; using util::DWORD_XOR_LE; +// input ports support up to 32 bits each +typedef u32 ioport_value; + // pen_t is used to represent pixel values in bitmaps typedef u32 pen_t; @@ -193,73 +199,11 @@ constexpr int ROT270 = ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y; /// \} -// these are UTF-8 encoded strings for common characters -#define UTF8_NBSP "\xc2\xa0" /* non-breaking space */ - -#define UTF8_MULTIPLY "\xc3\x97" /* multiplication sign */ -#define UTF8_DIVIDE "\xc3\xb7" /* division sign */ -#define UTF8_SQUAREROOT "\xe2\x88\x9a" /* square root symbol */ -#define UTF8_PLUSMINUS "\xc2\xb1" /* plusminus symbol */ - -#define UTF8_POW_2 "\xc2\xb2" /* superscript 2 */ -#define UTF8_POW_X "\xcb\xa3" /* superscript x */ -#define UTF8_POW_Y "\xca\xb8" /* superscript y */ -#define UTF8_PRIME "\xca\xb9" /* prime symbol */ -#define UTF8_DEGREES "\xc2\xb0" /* degrees symbol */ - -#define UTF8_SMALL_PI "\xcf\x80" /* Greek small letter pi */ -#define UTF8_CAPITAL_SIGMA "\xce\xa3" /* Greek capital letter sigma */ -#define UTF8_CAPITAL_DELTA "\xce\x94" /* Greek capital letter delta */ - -#define UTF8_MACRON "\xc2\xaf" /* macron symbol */ -#define UTF8_NONSPACE_MACRON "\xcc\x84" /* nonspace macron, use after another char */ - -#define a_RING "\xc3\xa5" /* small a with a ring */ -#define a_UMLAUT "\xc3\xa4" /* small a with an umlaut */ -#define o_UMLAUT "\xc3\xb6" /* small o with an umlaut */ -#define u_UMLAUT "\xc3\xbc" /* small u with an umlaut */ -#define e_ACUTE "\xc3\xa9" /* small e with an acute */ -#define n_TILDE "\xc3\xb1" /* small n with a tilde */ - -#define A_RING "\xc3\x85" /* capital A with a ring */ -#define A_UMLAUT "\xc3\x84" /* capital A with an umlaut */ -#define O_UMLAUT "\xc3\x96" /* capital O with an umlaut */ -#define U_UMLAUT "\xc3\x9c" /* capital U with an umlaut */ -#define E_ACUTE "\xc3\x89" /* capital E with an acute */ -#define N_TILDE "\xc3\x91" /* capital N with a tilde */ - -#define UTF8_LEFT "\xe2\x86\x90" /* cursor left */ -#define UTF8_RIGHT "\xe2\x86\x92" /* cursor right */ -#define UTF8_UP "\xe2\x86\x91" /* cursor up */ -#define UTF8_DOWN "\xe2\x86\x93" /* cursor down */ - - //************************************************************************** // COMMON MACROS //************************************************************************** -// macro for defining a copy constructor and assignment operator to prevent copying -#define DISABLE_COPYING(TYPE) \ - TYPE(const TYPE &) = delete; \ - TYPE &operator=(const TYPE &) = delete - -// macro for declaring enumeration operators that increment/decrement like plain old C -#define DECLARE_ENUM_INCDEC_OPERATORS(TYPE) \ -inline TYPE &operator++(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) + 1); } \ -inline TYPE &operator--(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) - 1); } \ -inline TYPE operator++(TYPE &value, int) { TYPE const old(value); ++value; return old; } \ -inline TYPE operator--(TYPE &value, int) { TYPE const old(value); --value; return old; } - -// macro for declaring bitwise operators for an enumerated type -#define DECLARE_ENUM_BITWISE_OPERATORS(TYPE) \ -constexpr TYPE operator~(TYPE value) { return TYPE(~std::underlying_type_t<TYPE>(value)); } \ -constexpr TYPE operator&(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) & std::underlying_type_t<TYPE>(b)); } \ -constexpr TYPE operator|(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) | std::underlying_type_t<TYPE>(b)); } \ -inline TYPE &operator&=(TYPE &a, TYPE b) { return a = a & b; } \ -inline TYPE &operator|=(TYPE &a, TYPE b) { return a = a | b; } - - // this macro passes an item followed by a string version of itself as two consecutive parameters #define NAME(x) x, #x @@ -284,17 +228,19 @@ class emu_exception : public std::exception { }; class emu_fatalerror : public emu_exception { public: - emu_fatalerror(util::format_argument_pack<std::ostream> const &args); - emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args); + emu_fatalerror(emu_fatalerror const &) = default; + emu_fatalerror(emu_fatalerror &&) = default; + emu_fatalerror(util::format_argument_pack<char> const &args); + emu_fatalerror(int _exitcode, util::format_argument_pack<char> const &args); template <typename Format, typename... Params> - emu_fatalerror(Format const &fmt, Params &&... args) - : emu_fatalerror(static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...))) + emu_fatalerror(Format &&fmt, Params &&... args) + : emu_fatalerror(static_cast<util::format_argument_pack<char> const &>(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...))) { } template <typename Format, typename... Params> - emu_fatalerror(int _exitcode, Format const &fmt, Params &&... args) - : emu_fatalerror(_exitcode, static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...))) + emu_fatalerror(int _exitcode, Format &&fmt, Params &&... args) + : emu_fatalerror(_exitcode, static_cast<util::format_argument_pack<char> const &>(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...))) { } @@ -421,4 +367,11 @@ inline u64 d2u(double d) return u.vv; } + +//************************************************************************** +// USEFUL UTILITIES +//************************************************************************** + +using util::make_unique_clear; + #endif // MAME_EMU_EMUCORE_H diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index 8b8e59b9250..89e15e4c541 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -14,6 +14,8 @@ #pragma once +#include "utilfwd.h" + #include <type_traits> @@ -40,24 +42,6 @@ class osd_interface; //---------------------------------- -// lib/util -//---------------------------------- - -// declared in aviio.h -class avi_file; - -// declared in chd.h -class chd_file; - -// declared in unzip.h -namespace util { class archive_file; } - -// declared in xmlfile.h -namespace util::xml { class data_node; class file; } - - - -//---------------------------------- // emu //---------------------------------- @@ -98,6 +82,7 @@ class symbol_table; class debug_breakpoint; class debug_watchpoint; class debug_registerpoint; +class debug_exceptionpoint; // declared in debugger.h class debugger_manager; @@ -107,6 +92,7 @@ class devcb_base; template <typename Input, std::make_unsigned_t<Input> DefaultMask> class devcb_write; // declared in devfind.h +class device_resolver_base; class finder_base; template <class DeviceClass, bool Required> class device_finder; @@ -129,6 +115,9 @@ class device_image_interface; // declared in dimemory.h class device_memory_interface; +// declared in dinetwork.h +class device_network_interface; + // declared in dipalette.h class device_palette_interface; @@ -152,6 +141,12 @@ class memory_view; // declared in emuopts.h class emu_options; +// declared in fileio.h +class emu_file; + +// declared in http.h +class http_manager; + // declared in gamedrv.h class game_driver; @@ -181,8 +176,12 @@ class running_machine; // declared in mconfig.h namespace emu::detail { class machine_config_replace; } +struct internal_layout; class machine_config; +// declared in main.h +class machine_manager; + // declared in natkeyboard.h class natural_keyboard; @@ -198,6 +197,9 @@ class render_manager; class render_target; class render_texture; +// declared in rendertypes.h +struct render_bounds; + // declared in rendfont.h class render_font; diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index 3982debf2cc..679c2374e78 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -861,66 +861,98 @@ void address_space_installer::populate_map_entry(const address_map_entry &entry, install_view(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, *entry.m_view); break; } + + if (data.m_type == AMH_VIEW) + return; + + offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.addr_shift())) - 1; + + if (!entry.m_before_time.isnull()) { + auto d = entry.m_before_time; + d.resolve(); + if (readorwrite == read_or_write::READ) + install_read_before_time(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + else + install_write_before_time(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + } + + if (!entry.m_before_delay.isnull()) { + auto d = entry.m_before_delay; + d.resolve(); + if (readorwrite == read_or_write::READ) + install_read_before_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + else + install_write_before_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + } + + if (!entry.m_after_delay.isnull()) { + auto d = entry.m_after_delay; + d.resolve(); + if (readorwrite == read_or_write::READ) + install_read_after_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + else + install_write_after_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d); + } } -memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 32-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 32-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph) { fatalerror("Tryingw to install a 32-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph) +memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } @@ -984,7 +1016,7 @@ void memory_bank::set_entry(int entrynum) // validate if (entrynum < 0 || entrynum >= int(m_entries.size())) - throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum); + throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with out-of-range entry %d", m_tag, entrynum); if (m_entries[entrynum] == nullptr) throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag, entrynum); diff --git a/src/emu/emumem.h b/src/emu/emumem.h index 3d4d664469e..1b9b6363622 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -17,6 +17,8 @@ #ifndef MAME_EMU_EMUMEM_H #define MAME_EMU_EMUMEM_H +#include "notifier.h" + #include <optional> #include <set> #include <type_traits> @@ -50,6 +52,14 @@ enum class read_or_write }; +//************************************************************************** +// FORWARD DECLARATIONS +//************************************************************************** + +class handler_entry; +template<int Width, int AddrShift> class handler_entry_read_passthrough; +template<int Width, int AddrShift> class handler_entry_write_passthrough; + //************************************************************************** // TYPE DEFINITIONS @@ -90,7 +100,7 @@ struct memory_entry_context { struct memory_entry { offs_t start, end; - class handler_entry *entry; + handler_entry *entry; std::vector<memory_entry_context> context; }; @@ -163,9 +173,15 @@ using write32smo_delegate = device_delegate<void (u32)>; using write64smo_delegate = device_delegate<void (u64)>; +// =====================-> Wait states delegates + +using ws_time_delegate = device_delegate<u64 (offs_t, u64)>; +using ws_delay_delegate = device_delegate<u32 (offs_t)>; + + namespace emu::detail { -// TODO: replace with std::void_t when we move to C++17 +// TODO: work out why this doesn't work with clang and/or libc++ void_t but works with this C++14 work-alike template <typename... T> struct void_wrapper { using type = void; }; template <typename... T> using void_t = typename void_wrapper<T...>::type; @@ -233,15 +249,6 @@ template <typename T> using rw_delegate_type_t = typename rw_delegate_type<T>::t template <typename T> using rw_delegate_device_class_t = typename rw_delegate_type<T>::device_class; -template <typename T> -inline rw_delegate_type_t<T> make_delegate(device_t &base, char const *tag, T &&func, char const *name) -{ return rw_delegate_type_t<T>(base, tag, std::forward<T>(func), name); } - -template <typename T> -inline rw_delegate_type_t<T> make_delegate(rw_delegate_device_class_t<T> &object, T &&func, char const *name) -{ return rw_delegate_type_t<T>(object, std::forward<T>(func), name); } - - template <typename L> inline std::enable_if_t<std::is_constructible<read8_delegate, device_t &, L, const char *>::value, read8_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name) { return read8_delegate(owner, std::forward<L>(l), name); } @@ -436,14 +443,69 @@ inline std::enable_if_t<std::is_constructible<write64smo_delegate, device_t &, L { return write64smo_delegate(owner, std::forward<L>(l), name); } +// =====================-> delegate -> Width + +template <typename Delegate> struct handler_width; +template <typename Delegate> inline constexpr int handler_width_v = handler_width<Delegate>::value; +template <> struct handler_width<read8_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read8m_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read8s_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read8sm_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read8mo_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read8smo_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8m_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8s_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8sm_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8mo_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<write8smo_delegate> { static inline constexpr int value = 0; }; +template <> struct handler_width<read16_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read16m_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read16s_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read16sm_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read16mo_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read16smo_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16m_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16s_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16sm_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16mo_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<write16smo_delegate> { static inline constexpr int value = 1; }; +template <> struct handler_width<read32_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read32m_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read32s_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read32sm_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read32mo_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read32smo_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32m_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32s_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32sm_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32mo_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<write32smo_delegate> { static inline constexpr int value = 2; }; +template <> struct handler_width<read64_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<read64m_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<read64s_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<read64sm_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<read64mo_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<read64smo_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64m_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64s_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64sm_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64mo_delegate> { static inline constexpr int value = 3; }; +template <> struct handler_width<write64smo_delegate> { static inline constexpr int value = 3; }; + + // =====================-> Width -> types -template<int Width> struct handler_entry_size {}; -template<> struct handler_entry_size<0> { using uX = u8; }; -template<> struct handler_entry_size<1> { using uX = u16; }; -template<> struct handler_entry_size<2> { using uX = u32; }; -template<> struct handler_entry_size<3> { using uX = u64; }; +template <int Width> struct handler_entry_size; +template <int Width> using handler_entry_size_t = typename handler_entry_size<Width>::type; +template<> struct handler_entry_size<0> { using type = u8; }; +template<> struct handler_entry_size<1> { using type = u16; }; +template<> struct handler_entry_size<2> { using type = u32; }; +template<> struct handler_entry_size<3> { using type = u64; }; // =====================-> Address segmentation for the search tree @@ -465,9 +527,49 @@ constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift width + ashift; } + +// =====================-> Passthrough handler management structure + +class memory_passthrough_handler_impl +{ +public: + memory_passthrough_handler_impl(address_space &space) : m_space(space) {} + memory_passthrough_handler_impl(memory_passthrough_handler_impl const &) = delete; + + void remove(); + +private: + address_space &m_space; + std::unordered_set<handler_entry *> m_handlers; + + void add_handler(handler_entry *handler) { m_handlers.insert(handler); } + void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); } + + friend address_space; + template<int Width, int AddrShift> friend class ::handler_entry_read_passthrough; + template<int Width, int AddrShift> friend class ::handler_entry_write_passthrough; +}; + } // namespace emu::detail +namespace emu { + +template <typename T> +inline detail::rw_delegate_type_t<T> rw_delegate(device_t &base, char const *tag, T &&func, char const *name) +{ return detail::rw_delegate_type_t<T>(base, tag, std::forward<T>(func), name); } + +template <typename T> +inline detail::rw_delegate_type_t<T> rw_delegate(detail::rw_delegate_device_class_t<T> &object, T &&func, char const *name) +{ return detail::rw_delegate_type_t<T>(object, std::forward<T>(func), name); } + +template <typename D, bool Reqd, typename T> +inline detail::rw_delegate_type_t<T> rw_delegate(device_finder<D, Reqd> const &finder, T &&func, char const *name) +{ return detail::rw_delegate_type_t<T>(finder, std::forward<T>(func), name); } + +} // namespace emu + + // ======================> memory_units_descritor forwards declaration template<int Width, int AddrShift> class memory_units_descriptor; @@ -485,11 +587,14 @@ class handler_entry public: // Typing flags (low 16 bits are for the user) - static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler - static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers - static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support) - static constexpr u32 F_PASSTHROUGH = 0x00080000; // handler that passes through the request to another handler - static constexpr u32 F_VIEW = 0x00100000; // handler for a view (kinda like dispatch except not entirely) + static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler + static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers + static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support) + static constexpr u32 F_VIEW = 0x00080000; // handler for a view (kinda like dispatch except not entirely) + static constexpr u32 F_PT_BITS = 24; // position of the 4-bit priority for a passthrough handler. The highest the priority the earlier it is called in the chain. 0 = not passthrough + static constexpr u32 F_PT_REPLACE = 1 << F_PT_BITS; // a passthrough with a odd priority can only happen once in a path + + static constexpr u32 f_pt(u32 priority) { return (priority << F_PT_BITS); } // Start/end of range flags static constexpr u8 START = 1; @@ -519,7 +624,8 @@ public: inline bool is_dispatch() const { return m_flags & F_DISPATCH; } inline bool is_view() const { return m_flags & F_VIEW; } inline bool is_units() const { return m_flags & F_UNITS; } - inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; } + inline bool is_passthrough() const { return f_get_pt() != 0; } + inline u32 f_get_pt() const { return (m_flags >> F_PT_BITS) & 15; } virtual void dump_map(std::vector<memory_entry> &map) const; @@ -561,12 +667,10 @@ protected: // Provides the populate/read/get_ptr/lookup API -template<int Width, int AddrShift> class handler_entry_read_passthrough; - template<int Width, int AddrShift> class handler_entry_read : public handler_entry { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; @@ -580,7 +684,9 @@ public: ~handler_entry_read() {} virtual uX read(offs_t offset, uX mem_mask) const = 0; + virtual uX read_interruptible(offs_t offset, uX mem_mask) const = 0; virtual std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const = 0; + virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0; virtual void *get_ptr(offs_t offset) const; virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift> *&handler) const; @@ -596,7 +702,7 @@ public: virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift> *handler); virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift> *handler); - inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor) { + void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor) { start &= ~NATIVE_MASK; end |= NATIVE_MASK; std::vector<mapping> mappings; @@ -609,7 +715,7 @@ public: virtual void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift> &descriptor, u8 rkey, std::vector<mapping> &mappings); virtual void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor, std::vector<mapping> &mappings); - inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler) { + void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler) { start &= ~NATIVE_MASK; end |= NATIVE_MASK; std::vector<mapping> mappings; @@ -636,12 +742,10 @@ public: // Provides the populate/write/get_ptr/lookup API -template<int Width, int AddrShift> class handler_entry_write_passthrough; - template<int Width, int AddrShift> class handler_entry_write : public handler_entry { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; @@ -655,7 +759,9 @@ public: virtual ~handler_entry_write() {} virtual void write(offs_t offset, uX data, uX mem_mask) const = 0; + virtual void write_interruptible(offs_t offset, uX data, uX mem_mask) const = 0; virtual u16 write_flags(offs_t offset, uX data, uX mem_mask) const = 0; + virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0; virtual void *get_ptr(offs_t offset) const; virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift> *&handler) const; @@ -711,20 +817,21 @@ public: // =====================-> Passthrough handler management structure class memory_passthrough_handler { - template<int Width, int AddrShift> friend class handler_entry_read_passthrough; - template<int Width, int AddrShift> friend class handler_entry_write_passthrough; - public: - memory_passthrough_handler(address_space &space) : m_space(space) {} + memory_passthrough_handler() : m_impl() {} + memory_passthrough_handler(std::shared_ptr<emu::detail::memory_passthrough_handler_impl> const &impl) : m_impl(impl) {} - inline void remove(); + void remove() + { + auto impl(m_impl.lock()); + if (impl) + impl->remove(); + } private: - address_space &m_space; - std::unordered_set<handler_entry *> m_handlers; + std::weak_ptr<emu::detail::memory_passthrough_handler_impl> m_impl; - void add_handler(handler_entry *handler) { m_handlers.insert(handler); } - void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); } + friend class address_space; }; // =====================-> Forward declaration for address_space @@ -739,10 +846,10 @@ constexpr offs_t memory_offset_to_byte(offs_t offset, int AddrShift) { return Ad // ======================> generic read/write decomposition routines // generic direct read -template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> typename emu::detail::handler_entry_size<TargetWidth>::uX memory_read_generic(T rop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> emu::detail::handler_entry_size_t<TargetWidth> memory_read_generic(T rop, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask) { - using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX; - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using TargetType = emu::detail::handler_entry_size_t<TargetWidth>; + using NativeType = emu::detail::handler_entry_size_t<Width>; constexpr u32 TARGET_BYTES = 1 << TargetWidth; constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; @@ -873,9 +980,9 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al } // generic direct write -template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> data, emu::detail::handler_entry_size_t<TargetWidth> mask) { - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using NativeType = emu::detail::handler_entry_size_t<Width>; constexpr u32 TARGET_BYTES = 1 << TargetWidth; constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; @@ -995,11 +1102,12 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al } } } + // generic direct read with flags -template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> std::pair<typename emu::detail::handler_entry_size<TargetWidth>::uX, u16> memory_read_generic_flags(TF ropf, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> std::pair<emu::detail::handler_entry_size_t<TargetWidth>, u16> memory_read_generic_flags(TF ropf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask) { - using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX; - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using TargetType = emu::detail::handler_entry_size_t<TargetWidth>; + using NativeType = emu::detail::handler_entry_size_t<Width>; constexpr u32 TARGET_BYTES = 1 << TargetWidth; constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; @@ -1135,9 +1243,9 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al } // generic direct write with flags -template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 memory_write_generic_flags(TF wopf, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask) +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 memory_write_generic_flags(TF wopf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> data, emu::detail::handler_entry_size_t<TargetWidth> mask) { - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using NativeType = emu::detail::handler_entry_size_t<Width>; constexpr u32 TARGET_BYTES = 1 << TargetWidth; constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; @@ -1264,35 +1372,328 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al } } +//############################################## +// generic direct read flags lookup +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 lookup_memory_read_generic_flags(TF lropf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask) +{ + using NativeType = emu::detail::handler_entry_size_t<Width>; + + constexpr u32 TARGET_BYTES = 1 << TargetWidth; + constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; + constexpr u32 NATIVE_BYTES = 1 << Width; + constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; + constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; + + // equal to native size and aligned; simple pass-through to the native flags lookup + if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) + return lropf(address & ~NATIVE_MASK, mask); + + // if native size is larger, see if we can do a single masked flags lookup (guaranteed if we're aligned) + if (NATIVE_BYTES > TARGET_BYTES) + { + u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1))); + if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) + { + if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; + return lropf(address & ~NATIVE_MASK, (NativeType)mask << offsbits); + } + } + + // determine our alignment against the native boundaries, and mask the address + u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1)); + address &= ~NATIVE_MASK; + + // if we're here, and native size is larger or equal to the target, we need exactly 2 reads + if (NATIVE_BYTES >= TARGET_BYTES) + { + // little-endian case + if (Endian == ENDIANNESS_LITTLE) + { + // read flags from lower address + u16 flags = 0; + NativeType curmask = (NativeType)mask << offsbits; + if (curmask != 0) flags |= lropf(address, curmask); + + // read flags from upper address + offsbits = NATIVE_BITS - offsbits; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask); + return flags; + } + + // big-endian case + else + { + // left-justify the mask to the target type + constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); + u16 flags = 0; + NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; + NativeType curmask = ljmask >> offsbits; + + // read flags from lower address + if (curmask != 0) flags |= lropf(address, curmask); + offsbits = NATIVE_BITS - offsbits; + + // read flags from upper address + curmask = ljmask << offsbits; + if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask); + + // return the result + return flags; + } + } + + // if we're here, then we have 2 or more reads needed to get our final result + else + { + // compute the maximum number of loops; we do it this way so that there are + // a fixed number of loops for the compiler to unroll if it desires + constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; + u16 flags = 0; + + // little-endian case + if (Endian == ENDIANNESS_LITTLE) + { + // read flags from first address + NativeType curmask = mask << offsbits; + if (curmask != 0) flags |= lropf(address, curmask); + + // read flags from subsequent addresses + offsbits = NATIVE_BITS - offsbits; + for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) + { + address += NATIVE_STEP; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lropf(address, curmask); + offsbits += NATIVE_BITS; + } + + // if we're not aligned and we still have bits left, read flags from last address + if (!Aligned && offsbits < TARGET_BITS) + { + curmask = mask >> offsbits; + if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask); + } + } + + // big-endian case + else + { + // read flags from first address + offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); + NativeType curmask = mask >> offsbits; + if (curmask != 0) flags |= lropf(address, curmask); + + // read flags from subsequent addresses + for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) + { + offsbits -= NATIVE_BITS; + address += NATIVE_STEP; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lropf(address, curmask); + } + + // if we're not aligned and we still have bits left, read flags from the last address + if (!Aligned && offsbits != 0) + { + offsbits = NATIVE_BITS - offsbits; + curmask = mask << offsbits; + if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask); + } + } + return flags; + } +} + +// generic direct write flags lookup +template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 lookup_memory_write_generic_flags(TF lwopf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask) +{ + using NativeType = emu::detail::handler_entry_size_t<Width>; + + constexpr u32 TARGET_BYTES = 1 << TargetWidth; + constexpr u32 TARGET_BITS = 8 * TARGET_BYTES; + constexpr u32 NATIVE_BYTES = 1 << Width; + constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; + constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; + + // equal to native size and aligned; simple pass-through to the native flags lookup + if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0)) + return lwopf(address & ~NATIVE_MASK, mask); + + // if native size is larger, see if we can do a single masked flags lookup (guaranteed if we're aligned) + if (NATIVE_BYTES > TARGET_BYTES) + { + u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1))); + if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS)) + { + if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits; + return lwopf(address & ~NATIVE_MASK, (NativeType)mask << offsbits); + } + } + + // determine our alignment against the native boundaries, and mask the address + u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1)); + address &= ~NATIVE_MASK; + + // if we're here, and native size is larger or equal to the target, we need exactly 2 lookups + if (NATIVE_BYTES >= TARGET_BYTES) + { + // little-endian case + if (Endian == ENDIANNESS_LITTLE) + { + // lookup flags from lower address + u16 flags = 0; + NativeType curmask = (NativeType)mask << offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + + // lookup flags from upper address + offsbits = NATIVE_BITS - offsbits; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask); + return flags; + } + + // big-endian case + else + { + // left-justify the mask to the target type + u16 flags = 0; + constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0); + NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT; + + // lookup flags from lower address + NativeType curmask = ljmask >> offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + + // lookup falgs from upper address + offsbits = NATIVE_BITS - offsbits; + curmask = ljmask << offsbits; + if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask); + return flags; + } + } + + // if we're here, then we have 2 or more lookups needed to get our final result + else + { + // compute the maximum number of loops; we do it this way so that there are + // a fixed number of loops for the compiler to unroll if it desires + constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1; + u16 flags = 0; + + // little-endian case + if (Endian == ENDIANNESS_LITTLE) + { + // lookup flags from first address + NativeType curmask = mask << offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + + // lookup flags from subsequent addresses + offsbits = NATIVE_BITS - offsbits; + for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) + { + address += NATIVE_STEP; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + offsbits += NATIVE_BITS; + } + + // if we're not aligned and we still have bits left, lookup flags last address + if (!Aligned && offsbits < TARGET_BITS) + { + curmask = mask >> offsbits; + if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask); + } + } + + // big-endian case + else + { + // lookup flags from first address + offsbits = TARGET_BITS - (NATIVE_BITS - offsbits); + NativeType curmask = mask >> offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + + // lookup flags from subsequent addresses + for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++) + { + offsbits -= NATIVE_BITS; + address += NATIVE_STEP; + curmask = mask >> offsbits; + if (curmask != 0) flags |= lwopf(address, curmask); + } + + // if we're not aligned and we still have bits left, lookup falgs from the last address + if (!Aligned && offsbits != 0) + { + offsbits = NATIVE_BITS - offsbits; + curmask = mask << offsbits; + if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask); + } + } + return flags; + } +} + // ======================> Direct dispatching -template<int Level, int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX dispatch_read(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) +template<int Level, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> dispatch_read(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) { static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); return dispatch[(offset & mask) >> LowBits]->read(offset, mem_mask); } -template<int Level, int Width, int AddrShift> void dispatch_write(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) +template<int Level, int Width, int AddrShift> void dispatch_write(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) { static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); return dispatch[(offset & mask) >> LowBits]->write(offset, data, mem_mask); } -template<int Level, int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> dispatch_read_flags(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) +template<int Level, int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> dispatch_read_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) { static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); return dispatch[(offset & mask) >> LowBits]->read_flags(offset, mem_mask); } -template<int Level, int Width, int AddrShift> u16 dispatch_write_flags(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) +template<int Level, int Width, int AddrShift> u16 dispatch_write_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) { static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); return dispatch[(offset & mask) >> LowBits]->write_flags(offset, data, mem_mask); } +template<int Level, int Width, int AddrShift> u16 dispatch_lookup_read_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) +{ + static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); + return dispatch[(offset & mask) >> LowBits]->lookup_flags(offset, mem_mask); +} + + +template<int Level, int Width, int AddrShift> u16 dispatch_lookup_write_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) +{ + static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); + return dispatch[(offset & mask) >> LowBits]->lookup_flags(offset, mem_mask); +} + + + +template<int Level, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> dispatch_read_interruptible(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch) +{ + static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); + return dispatch[(offset & mask) >> LowBits]->read_interruptible(offset, mem_mask); +} + + +template<int Level, int Width, int AddrShift> void dispatch_write_interruptible(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch) +{ + static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift); + return dispatch[(offset & mask) >> LowBits]->write_interruptible(offset, data, mem_mask); +} + // ======================> memory_access_specific @@ -1304,7 +1705,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> class memory_ { friend class ::address_space; - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using NativeType = emu::detail::handler_entry_size_t<Width>; static constexpr u32 NATIVE_BYTES = 1 << Width; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; @@ -1322,10 +1723,12 @@ public: return *m_space; } - auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } - auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; } - auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } - auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; } + auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } + auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; } + auto lropf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_read_native_flags(offset, mask); }; } + auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } + auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; } + auto lwopf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_write_native_flags(offset, mask); }; } u8 read_byte(offs_t address) { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); } u16 read_word(offs_t address) { if constexpr(Width == 1) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 1, true>(rop(), address, 0xffff); } @@ -1384,6 +1787,42 @@ public: u16 write_qword_unaligned_flags(offs_t address, u64 data) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); } u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); } + u16 lookup_read_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(lropf(), address, 0xff); } + u16 lookup_read_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, 0xffff); } + u16 lookup_read_word_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, mask); } + u16 lookup_read_word_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, 0xffff); } + u16 lookup_read_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, mask); } + u16 lookup_read_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, 0xffffffff); } + u16 lookup_read_dword_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, mask); } + u16 lookup_read_dword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, 0xffffffff); } + u16 lookup_read_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, mask); } + u16 lookup_read_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, 0xffffffffffffffffU); } + u16 lookup_read_qword_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, mask); } + u16 lookup_read_qword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, 0xffffffffffffffffU); } + u16 lookup_read_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, mask); } + + u16 lookup_write_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(lwopf(), address, 0xff); } + u16 lookup_write_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, 0xffff); } + u16 lookup_write_word_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, mask); } + u16 lookup_write_word_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, 0xffff); } + u16 lookup_write_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, mask); } + u16 lookup_write_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, 0xffffffff); } + u16 lookup_write_dword_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, mask); } + u16 lookup_write_dword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, 0xffffffff); } + u16 lookup_write_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, mask); } + u16 lookup_write_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(lwopf(), address, 0xffffffffffffffffU); } + u16 lookup_write_qword_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wop(), address, mask); } + u16 lookup_write_qword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, 0xffffffffffffffffU); } + u16 lookup_write_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, mask); } + + NativeType read_interruptible(offs_t address, NativeType mask = ~NativeType(0)) { + return dispatch_read_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read); + } + + void write_interruptible(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) { + dispatch_write_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write); + } + private: address_space * m_space; @@ -1408,6 +1847,14 @@ private: return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write); } + u16 lookup_read_native_flags(offs_t address, NativeType mask = ~NativeType(0)) { + return dispatch_lookup_read_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read); + } + + u16 lookup_write_native_flags(offs_t address, NativeType mask = ~NativeType(0)) { + return dispatch_lookup_write_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_write); + } + void set(address_space *space, std::pair<const void *, const void *> rw); }; @@ -1420,7 +1867,7 @@ template<int Width, int AddrShift, endianness_t Endian> class memory_access_cach { friend class ::address_space; - using NativeType = typename emu::detail::handler_entry_size<Width>::uX; + using NativeType = emu::detail::handler_entry_size_t<Width>; static constexpr u32 NATIVE_BYTES = 1 << Width; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; @@ -1467,10 +1914,12 @@ public: return m_cache_r->get_ptr(address); } - auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } - auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; } - auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } - auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; } + auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } + auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; } + auto lropf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_read_native_flags(offset, mask); }; } + auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } + auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; } + auto lwopf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_write_native_flags(offset, mask); }; } u8 read_byte(offs_t address) { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); } u16 read_word(offs_t address) { if constexpr(Width == 1) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 1, true>(rop(), address, 0xffff); } @@ -1529,6 +1978,35 @@ public: u16 write_qword_unaligned_flags(offs_t address, u64 data) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); } u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); } + + u16 lookup_read_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(lropf(), address, 0xff); } + u16 lookup_read_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, 0xffff); } + u16 lookup_read_word_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, mask); } + u16 lookup_read_word_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, 0xffff); } + u16 lookup_read_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, mask); } + u16 lookup_read_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, 0xffffffff); } + u16 lookup_read_dword_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, mask); } + u16 lookup_read_dword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, 0xffffffff); } + u16 lookup_read_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, mask); } + u16 lookup_read_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, 0xffffffffffffffffU); } + u16 lookup_read_qword_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, mask); } + u16 lookup_read_qword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, 0xffffffffffffffffU); } + u16 lookup_read_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, mask); } + + u16 lookup_write_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(lwopf(), address, 0xff); } + u16 lookup_write_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, 0xffff); } + u16 lookup_write_word_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, mask); } + u16 lookup_write_word_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, 0xffff); } + u16 lookup_write_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, mask); } + u16 lookup_write_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, 0xffffffff); } + u16 lookup_write_dword_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, mask); } + u16 lookup_write_dword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, 0xffffffff); } + u16 lookup_write_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, mask); } + u16 lookup_write_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(lwopf(), address, 0xffffffffffffffffU); } + u16 lookup_write_qword_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wop(), address, mask); } + u16 lookup_write_qword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, 0xffffffffffffffffU); } + u16 lookup_write_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, mask); } + private: address_space * m_space; @@ -1543,10 +2021,14 @@ private: handler_entry_read <Width, AddrShift> *m_root_read; // decode tree roots handler_entry_write<Width, AddrShift> *m_root_write; + util::notifier_subscription m_subscription; + NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)); void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)); std::pair<NativeType, u16> read_native_flags(offs_t address, NativeType mask = ~NativeType(0)); u16 write_native_flags(offs_t address, NativeType data, NativeType mask = ~NativeType(0)); + u16 lookup_read_native_flags(offs_t address, NativeType mask = ~NativeType(0)); + u16 lookup_write_native_flags(offs_t address, NativeType mask = ~NativeType(0)); void set(address_space *space, std::pair<void *, void *> rw); }; @@ -1687,194 +2169,132 @@ public: virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; // install taps without mirroring - memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } - memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } - memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } - memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } - memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); } + memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } + memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); } // install taps with mirroring - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr); // install views void install_view(offs_t addrstart, offs_t addrend, memory_view &view) { install_view(addrstart, addrend, 0, view); } virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) = 0; + // install wait state handlers + void install_read_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_read_before_time(addrstart, addrend, 0, ws); } + virtual void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0; + void install_read_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_before_delay(addrstart, addrend, 0, ws); } + virtual void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + void install_read_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_after_delay(addrstart, addrend, 0, ws); } + virtual void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + + void install_write_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_write_before_time(addrstart, addrend, 0, ws); } + virtual void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0; + void install_write_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_before_delay(addrstart, addrend, 0, ws); } + virtual void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + void install_write_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_after_delay(addrstart, addrend, 0, ws); } + virtual void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + + void install_readwrite_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_readwrite_before_time(addrstart, addrend, 0, ws); } + virtual void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0; + void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_before_delay(addrstart, addrend, 0, ws); } + virtual void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_after_delay(addrstart, addrend, 0, ws); } + virtual void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0; + // install new-style delegate handlers (short form) - void install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - - void install_read_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - - void install_read_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - - void install_read_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - - void install_read_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - - void install_read_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } - void install_read_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); } - void install_write_handler(offs_t addrstart, offs_t addrend, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); } + template <typename R> + void install_read_handler(offs_t addrstart, offs_t addrend, R &&rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) + { install_read_handler(addrstart, addrend, 0, 0, 0, std::forward<R>(rhandler), unitmask, cswidth, flags); } + template <typename W> + void install_write_handler(offs_t addrstart, offs_t addrend, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) + { install_write_handler(addrstart, addrend, 0, 0, 0, std::forward<W>(whandler), unitmask, cswidth, flags); } + template <typename R, typename W> + void install_readwrite_handler(offs_t addrstart, offs_t addrend, R &&rhandler, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) + { install_readwrite_handler(addrstart, addrend, 0, 0, 0, std::forward<R>(rhandler), std::forward<W>(whandler), unitmask, cswidth, flags); } // install new-style delegate handlers (with mirror/mask) virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; - virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0; + + template <typename R, typename W> + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, R &&rhandler, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) + { + static_assert(emu::detail::handler_width_v<std::remove_reference_t<R> > == emu::detail::handler_width_v<std::remove_reference_t<W> >, "handler widths do not match"); + install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, std::forward<R>(rhandler), unitmask, cswidth, flags); + install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, std::forward<W>(whandler), unitmask, cswidth, flags); + } protected: virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, bool quiet) = 0; @@ -1918,11 +2338,6 @@ class address_space : public address_space_installer template<int Width, int AddrShift> friend class handler_entry_read_unmapped; template<int Width, int AddrShift> friend class handler_entry_write_unmapped; - struct notifier_t { - std::function<void (read_or_write)> m_notifier; - int m_id; - }; - protected: // construction/destruction address_space(memory_manager &manager, device_memory_interface &memory, int spacenum); @@ -1962,15 +2377,14 @@ public: v.set(this, get_specific_info()); } - int add_change_notifier(std::function<void (read_or_write)> n); - void remove_change_notifier(int id); + util::notifier_subscription add_change_notifier(delegate<void (read_or_write)> &&n); + template <typename T> util::notifier_subscription add_change_notifier(T &&n) { return add_change_notifier(delegate<void (read_or_write)>(std::forward<T>(n))); } void invalidate_caches(read_or_write mode) { if(u32(mode) & ~m_in_notification) { u32 old = m_in_notification; m_in_notification |= u32(mode); - for(const auto &n : m_notifiers) - n.m_notifier(mode); + m_notifiers(mode); m_in_notification = old; } } @@ -1980,8 +2394,10 @@ public: virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) = 0; u64 unmap() const { return m_unmap; } + void unmap_value_high() { m_unmap = ~0; } - memory_passthrough_handler *make_mph(); + std::shared_ptr<emu::detail::memory_passthrough_handler_impl> make_mph(memory_passthrough_handler *mph); + std::shared_ptr<emu::detail::memory_passthrough_handler_impl> get_default_mpl() { return m_default_mpl; } // debug helpers virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0; @@ -2024,36 +2440,6 @@ public: virtual void write_qword_unaligned(offs_t address, u64 data) = 0; virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; - // read accessors with flags - virtual std::pair<u8, u16> read_byte_flags(offs_t address) = 0; - virtual std::pair<u16, u16> read_word_flags(offs_t address) = 0; - virtual std::pair<u16, u16> read_word_flags(offs_t address, u16 mask) = 0; - virtual std::pair<u16, u16> read_word_unaligned_flags(offs_t address) = 0; - virtual std::pair<u16, u16> read_word_unaligned_flags(offs_t address, u16 mask) = 0; - virtual std::pair<u32, u16> read_dword_flags(offs_t address) = 0; - virtual std::pair<u32, u16> read_dword_flags(offs_t address, u32 mask) = 0; - virtual std::pair<u32, u16> read_dword_unaligned_flags(offs_t address) = 0; - virtual std::pair<u32, u16> read_dword_unaligned_flags(offs_t address, u32 mask) = 0; - virtual std::pair<u64, u16> read_qword_flags(offs_t address) = 0; - virtual std::pair<u64, u16> read_qword_flags(offs_t address, u64 mask) = 0; - virtual std::pair<u64, u16> read_qword_unaligned_flags(offs_t address) = 0; - virtual std::pair<u64, u16> read_qword_unaligned_flags(offs_t address, u64 mask) = 0; - - // write accessors with flags - virtual u16 write_byte_flags(offs_t address, u8 data) = 0; - virtual u16 write_word_flags(offs_t address, u16 data) = 0; - virtual u16 write_word_flags(offs_t address, u16 data, u16 mask) = 0; - virtual u16 write_word_unaligned_flags(offs_t address, u16 data) = 0; - virtual u16 write_word_unaligned_flags(offs_t address, u16 data, u16 mask) = 0; - virtual u16 write_dword_flags(offs_t address, u32 data) = 0; - virtual u16 write_dword_flags(offs_t address, u32 data, u32 mask) = 0; - virtual u16 write_dword_unaligned_flags(offs_t address, u32 data) = 0; - virtual u16 write_dword_unaligned_flags(offs_t address, u32 data, u32 mask) = 0; - virtual u16 write_qword_flags(offs_t address, u64 data) = 0; - virtual u16 write_qword_flags(offs_t address, u64 data, u64 mask) = 0; - virtual u16 write_qword_unaligned_flags(offs_t address, u64 data) = 0; - virtual u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) = 0; - // setup void prepare_map(); void prepare_device_map(address_map &map); @@ -2088,11 +2474,13 @@ protected: handler_entry *m_nop_r; handler_entry *m_nop_w; - std::vector<std::unique_ptr<memory_passthrough_handler>> m_mphs; + std::vector<std::shared_ptr<emu::detail::memory_passthrough_handler_impl>> m_mphs; - std::vector<notifier_t> m_notifiers; // notifier list for address map change - int m_notifier_id; // next notifier id + util::notifier<read_or_write> m_notifiers; // notifier list for address map change u32 m_in_notification; // notification(s) currently being done + + // passthrough handler used for wait states + std::shared_ptr<emu::detail::memory_passthrough_handler_impl> m_default_mpl; }; @@ -2379,9 +2767,9 @@ private: template<int Width, int AddrShift, endianness_t Endian> -typename emu::detail::handler_entry_size<Width>::uX +emu::detail::handler_entry_size_t<Width> emu::detail::memory_access_cache<Width, AddrShift, Endian>:: -read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX mask) +read_native(offs_t address, emu::detail::handler_entry_size_t<Width> mask) { address &= m_addrmask; check_address_r(address); @@ -2390,14 +2778,14 @@ read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX template<int Width, int AddrShift, endianness_t Endian> void emu::detail::memory_access_cache<Width, AddrShift, Endian>:: -write_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mask) +write_native(offs_t address, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mask) { address &= m_addrmask; check_address_w(address); m_cache_w->write(address, data, mask); } -void memory_passthrough_handler::remove() +inline void emu::detail::memory_passthrough_handler_impl::remove() { m_space.remove_passthrough(m_handlers); } @@ -2421,18 +2809,19 @@ set(address_space *space, std::pair<void *, void *> rw) m_space = space; m_addrmask = space->addrmask(); - space->add_change_notifier([this](read_or_write mode) { - if(u32(mode) & u32(read_or_write::READ)) { - m_addrend_r = 0; - m_addrstart_r = 1; - m_cache_r = nullptr; - } - if(u32(mode) & u32(read_or_write::WRITE)) { - m_addrend_w = 0; - m_addrstart_w = 1; - m_cache_w = nullptr; - } - }); + m_subscription = space->add_change_notifier( + [this] (read_or_write mode) { + if(u32(mode) & u32(read_or_write::READ)) { + m_addrend_r = 0; + m_addrstart_r = 1; + m_cache_r = nullptr; + } + if(u32(mode) & u32(read_or_write::WRITE)) { + m_addrend_w = 0; + m_addrstart_w = 1; + m_cache_w = nullptr; + } + }); m_root_read = (handler_entry_read <Width, AddrShift> *)(rw.first); m_root_write = (handler_entry_write<Width, AddrShift> *)(rw.second); diff --git a/src/emu/emumem_aspace.cpp b/src/emu/emumem_aspace.cpp index 5aeea17c11a..b0d00d6fca8 100644 --- a/src/emu/emumem_aspace.cpp +++ b/src/emu/emumem_aspace.cpp @@ -25,6 +25,7 @@ #include "emumem_hedw.h" #include "emumem_hep.h" #include "emumem_het.h" +#include "emumem_hws.h" //************************************************************************** @@ -48,58 +49,7 @@ template <typename Format, typename... Params> static void VPRINTF(Format &&, Pa // CONSTANTS //************************************************************************** -namespace { - -template <typename Delegate> struct handler_width; -template <> struct handler_width<read8_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read16_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read32_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read64_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; }; -} // anonymous namespace +using emu::detail::handler_width_v; //************************************************************************** @@ -112,7 +62,7 @@ template <> struct handler_width<write64smo_delegate> { static constexpr int val template<int Level, int Width, int AddrShift, endianness_t Endian> class address_space_specific : public address_space { - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; using NativeType = uX; using this_type = address_space_specific<Level, Width, AddrShift, Endian>; @@ -138,163 +88,127 @@ public: void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override; void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) override; + void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + + void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + + void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } using address_space::install_read_tap; using address_space::install_write_tap; using address_space::install_readwrite_tap; - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override; // construction/destruction address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum, int address_width) @@ -433,48 +347,26 @@ public: return dispatch_read<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read); } - std::pair<NativeType, u16> read_native_flags(offs_t offset, NativeType mask) - { - return dispatch_read_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read); - } - // mask-less native read NativeType read_native(offs_t offset) { return dispatch_read<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read); } - std::pair<NativeType, u16> read_native_flags(offs_t offset) - { - return dispatch_read_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read); - } - // native write void write_native(offs_t offset, NativeType data, NativeType mask) { dispatch_write<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write); } - u16 write_native_flags(offs_t offset, NativeType data, NativeType mask) - { - return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write); - } - // mask-less native write void write_native(offs_t offset, NativeType data) { dispatch_write<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write); } - u16 write_native_flags(offs_t offset, NativeType data) - { - return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write); - } - - auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } - auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; } - auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } - auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; } + auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; } + auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; } // virtual access to these functions u8 read_byte(offs_t address) override { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); } @@ -505,34 +397,6 @@ public: void write_qword_unaligned(offs_t address, u64 data) override { memory_write_generic<Width, AddrShift, Endian, 3, false>(wop(), address, data, 0xffffffffffffffffU); } void write_qword_unaligned(offs_t address, u64 data, u64 mask) override { memory_write_generic<Width, AddrShift, Endian, 3, false>(wop(), address, data, mask); } - std::pair<u8, u16> read_byte_flags(offs_t address) override { if constexpr(Width == 0) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(ropf(), address, 0xff); } - std::pair<u16, u16> read_word_flags(offs_t address) override { if constexpr(Width == 1) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(ropf(), address, 0xffff); } - std::pair<u16, u16> read_word_flags(offs_t address, u16 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(ropf(), address, mask); } - std::pair<u16, u16> read_word_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(ropf(), address, 0xffff); } - std::pair<u16, u16> read_word_unaligned_flags(offs_t address, u16 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(ropf(), address, mask); } - std::pair<u32, u16> read_dword_flags(offs_t address) override { if constexpr(Width == 2) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(ropf(), address, 0xffffffff); } - std::pair<u32, u16> read_dword_flags(offs_t address, u32 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(ropf(), address, mask); } - std::pair<u32, u16> read_dword_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(ropf(), address, 0xffffffff); } - std::pair<u32, u16> read_dword_unaligned_flags(offs_t address, u32 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(ropf(), address, mask); } - std::pair<u64, u16> read_qword_flags(offs_t address) override { if constexpr(Width == 3) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(ropf(), address, 0xffffffffffffffffU); } - std::pair<u64, u16> read_qword_flags(offs_t address, u64 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(ropf(), address, mask); } - std::pair<u64, u16> read_qword_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(ropf(), address, 0xffffffffffffffffU); } - std::pair<u64, u16> read_qword_unaligned_flags(offs_t address, u64 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(ropf(), address, mask); } - - u16 write_byte_flags(offs_t address, u8 data) override { if constexpr(Width == 0) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(wopf(), address, data, 0xff); } - u16 write_word_flags(offs_t address, u16 data) override { if constexpr(Width == 1) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(wopf(), address, data, 0xffff); } - u16 write_word_flags(offs_t address, u16 data, u16 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(wopf(), address, data, mask); } - u16 write_word_unaligned_flags(offs_t address, u16 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(wopf(), address, data, 0xffff); } - u16 write_word_unaligned_flags(offs_t address, u16 data, u16 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(wopf(), address, data, mask); } - u16 write_dword_flags(offs_t address, u32 data) override { if constexpr(Width == 2) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(wopf(), address, data, 0xffffffff); } - u16 write_dword_flags(offs_t address, u32 data, u32 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(wopf(), address, data, mask); } - u16 write_dword_unaligned_flags(offs_t address, u32 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(wopf(), address, data, 0xffffffff); } - u16 write_dword_unaligned_flags(offs_t address, u32 data, u32 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(wopf(), address, data, mask); } - u16 write_qword_flags(offs_t address, u64 data) override { if constexpr(Width == 3) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wopf(), address, data, 0xffffffffffffffffU); } - u16 write_qword_flags(offs_t address, u64 data, u64 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wopf(), address, data, mask); } - u16 write_qword_unaligned_flags(offs_t address, u64 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); } - u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); } - // static access to these functions static u8 read_byte_static(this_type &space, offs_t address) { return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); } @@ -564,7 +428,7 @@ private: osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); throw; } - install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r); + install_read_handler_helper<handler_width_v<READ> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r); } template<typename WRITE> @@ -575,24 +439,7 @@ private: osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); throw; } - install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w); - } - - template<typename READ, typename WRITE> - void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r, WRITE &handler_w) - { - static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match"); - try { handler_r.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - try { handler_w.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r, handler_w); + install_write_handler_helper<handler_width_v<WRITE> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w); } template<int AccessWidth, typename READ> @@ -659,50 +506,6 @@ private: invalidate_caches(read_or_write::WRITE); } } - - template<int AccessWidth, typename READ, typename WRITE> - void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, - const READ &handler_r, - const WRITE &handler_w) - { - if constexpr (Width < AccessWidth) { - fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); - } else { - VPRINTF("address_space::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmask, m_addrchars, addrmirror, - 8 << Width, 8 << AccessWidth, - handler_r.name(), handler_w.name(), data_width() / 4, unitmask); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - if constexpr (Width == AccessWidth) { - auto hand_r = new handler_entry_read_delegate <Width, AddrShift, READ>(this, flags, handler_r); - hand_r->set_address_info(nstart, nmask); - m_root_read ->populate(nstart, nend, nmirror, hand_r); - - auto hand_w = new handler_entry_write_delegate<Width, AddrShift, WRITE>(this, flags, handler_w); - hand_w->set_address_info(nstart, nmask); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } else { - auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, READ>(this, flags, handler_r); - memory_units_descriptor<Width, AddrShift> descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); - hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_read ->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_r->unref(); - - auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, WRITE>(this, flags, handler_w); - descriptor.set_subunit_handler(hand_w); - hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_w->unref(); - } - invalidate_caches(read_or_write::READWRITE); - } - } }; @@ -810,8 +613,8 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m m_spacenum(spacenum), m_log_unmap(true), m_name(memory.space_config(spacenum)->name()), - m_notifier_id(0), - m_in_notification(0) + m_in_notification(0), + m_default_mpl(make_mph(nullptr)) { } @@ -1084,73 +887,78 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ view.make_subdispatch(""); // Must be called after populate } -memory_passthrough_handler *address_space::make_mph() +std::shared_ptr<emu::detail::memory_passthrough_handler_impl> address_space::make_mph(memory_passthrough_handler *mph) { - m_mphs.emplace_back(std::make_unique<memory_passthrough_handler>(*this)); - return m_mphs.back().get(); + if (mph) + { + auto impl(mph->m_impl.lock()); + if (impl) + { + assert(&impl->m_space == this); + return impl; + } + } + return m_mphs.emplace_back(std::make_shared<emu::detail::memory_passthrough_handler_impl>(*this)); } //------------------------------------------------- // install_read_tap - install a read tap on the bus //------------------------------------------------- -template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = make_mph(); + auto impl = make_mph(mph); - auto handler = new handler_entry_read_tap<Width, AddrShift>(this, *mph, name, tap); + auto handler = new handler_entry_read_tap<Width, AddrShift>(this, *impl, name, tap); m_root_read->populate_passthrough(nstart, nend, nmirror, handler); handler->unref(); invalidate_caches(read_or_write::READ); - return mph; + return impl; } //------------------------------------------------- // install_write_tap - install a write tap on the bus //------------------------------------------------- -template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = make_mph(); + auto impl = make_mph(mph); - auto handler = new handler_entry_write_tap<Width, AddrShift>(this, *mph, name, tap); + auto handler = new handler_entry_write_tap<Width, AddrShift>(this, *impl, name, tap); m_root_write->populate_passthrough(nstart, nend, nmirror, handler); handler->unref(); invalidate_caches(read_or_write::WRITE); - return mph; + return impl; } //------------------------------------------------- // install_write_tap - install a read and a write tap on the bus //------------------------------------------------- -template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = make_mph(); + auto impl = make_mph(mph); - auto rhandler = new handler_entry_read_tap <Width, AddrShift>(this, *mph, name, tapr); + auto rhandler = new handler_entry_read_tap <Width, AddrShift>(this, *impl, name, tapr); m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler); rhandler->unref(); - auto whandler = new handler_entry_write_tap<Width, AddrShift>(this, *mph, name, tapw); + auto whandler = new handler_entry_write_tap<Width, AddrShift>(this, *impl, name, tapw); m_root_write->populate_passthrough(nstart, nend, nmirror, whandler); whandler->unref(); invalidate_caches(read_or_write::READWRITE); - return mph; + return impl; } @@ -1218,6 +1026,194 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passth //------------------------------------------------- +// install the wait state handlers +//------------------------------------------------- + + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_read_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_read_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_read_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); +} + + + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_write_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_write_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_write_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_readwrite_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_readwrite_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag()); + + VPRINTF("address_space::install_readwrite_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(this, *m_default_mpl, ws); + m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w); +} + + + + +//------------------------------------------------- // install_bank_generic - install a range as // mapping to a particular bank //------------------------------------------------- @@ -1291,19 +1287,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ // MEMORY MAPPING HELPERS //************************************************************************** -int address_space::add_change_notifier(std::function<void (read_or_write)> n) +util::notifier_subscription address_space::add_change_notifier(delegate<void (read_or_write)> &&n) { - int id = m_notifier_id++; - m_notifiers.emplace_back(notifier_t{ std::move(n), id }); - return id; -} - -void address_space::remove_change_notifier(int id) -{ - for(auto i = m_notifiers.begin(); i != m_notifiers.end(); i++) - if (i->m_id == id) { - m_notifiers.erase(i); - return; - } - fatalerror("Unknown notifier id %d, double remove?\n", id); + return m_notifiers.subscribe(std::move(n)); } diff --git a/src/emu/emumem_hea.h b/src/emu/emumem_hea.h index e8308a73960..9ee6f8c8a1e 100644 --- a/src/emu/emumem_hea.h +++ b/src/emu/emumem_hea.h @@ -8,7 +8,7 @@ template<int Width, int AddrShift> class handler_entry_read_address : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_address(address_space *space, u32 flags) : handler_entry_read<Width, AddrShift>(space, flags) {} ~handler_entry_read_address() = default; @@ -25,7 +25,7 @@ protected: template<int Width, int AddrShift> class handler_entry_write_address : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; diff --git a/src/emu/emumem_hedp.cpp b/src/emu/emumem_hedp.cpp index e3a58381585..b053f84c592 100644 --- a/src/emu/emumem_hedp.cpp +++ b/src/emu/emumem_hedp.cpp @@ -10,7 +10,7 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16_delegate>::value || std::is_same<R, read32_delegate>::value || std::is_same<R, read64_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(*this->m_space, ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift), mem_mask); } @@ -20,7 +20,7 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16m_delegate>::value || std::is_same<R, read32m_delegate>::value || std::is_same<R, read64m_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(*this->m_space, ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)); } @@ -30,7 +30,7 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16s_delegate>::value || std::is_same<R, read32s_delegate>::value || std::is_same<R, read64s_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift), mem_mask); } @@ -40,7 +40,7 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16sm_delegate>::value || std::is_same<R, read32sm_delegate>::value || std::is_same<R, read64sm_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)); } @@ -50,7 +50,7 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16mo_delegate>::value || std::is_same<R, read32mo_delegate>::value || std::is_same<R, read64mo_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(*this->m_space); } @@ -60,21 +60,31 @@ template<int Width, int AddrShift, typename READ> template<typename R> std::is_same<R, read16smo_delegate>::value || std::is_same<R, read32smo_delegate>::value || std::is_same<R, read64smo_delegate>::value, - typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const + emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const { return m_delegate(); } -template<int Width, int AddrShift, typename READ> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_delegate<Width, AddrShift, READ>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift, typename READ> emu::detail::handler_entry_size_t<Width> handler_entry_read_delegate<Width, AddrShift, READ>::read(offs_t offset, uX mem_mask) const { return read_impl<READ>(offset, mem_mask); } -template<int Width, int AddrShift, typename READ> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_delegate<Width, AddrShift, READ>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift, typename READ> emu::detail::handler_entry_size_t<Width> handler_entry_read_delegate<Width, AddrShift, READ>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return read_impl<READ>(offset, mem_mask); +} + +template<int Width, int AddrShift, typename READ> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_delegate<Width, AddrShift, READ>::read_flags(offs_t offset, uX mem_mask) const { return std::pair<uX, u16>(read_impl<READ>(offset, mem_mask), this->m_flags); } +template<int Width, int AddrShift, typename READ> u16 handler_entry_read_delegate<Width, AddrShift, READ>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift, typename READ> std::string handler_entry_read_delegate<Width, AddrShift, READ>::name() const { return m_delegate.name(); @@ -145,12 +155,22 @@ template<int Width, int AddrShift, typename WRITE> void handler_entry_write_dele write_impl<WRITE>(offset, data, mem_mask); } +template<int Width, int AddrShift, typename WRITE> void handler_entry_write_delegate<Width, AddrShift, WRITE>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + write_impl<WRITE>(offset, data, mem_mask); +} + template<int Width, int AddrShift, typename WRITE> u16 handler_entry_write_delegate<Width, AddrShift, WRITE>::write_flags(offs_t offset, uX data, uX mem_mask) const { write_impl<WRITE>(offset, data, mem_mask); return this->m_flags; } +template<int Width, int AddrShift, typename WRITE> u16 handler_entry_write_delegate<Width, AddrShift, WRITE>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift, typename WRITE> std::string handler_entry_write_delegate<Width, AddrShift, WRITE>::name() const { return m_delegate.name(); @@ -159,16 +179,26 @@ template<int Width, int AddrShift, typename WRITE> std::string handler_entry_wri -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_ioport<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_ioport<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { return m_port->read(); } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_ioport<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_ioport<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return m_port->read(); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_ioport<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { return std::pair<uX, u16>(m_port->read(), this->m_flags); } +template<int Width, int AddrShift> u16 handler_entry_read_ioport<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_read_ioport<Width, AddrShift>::name() const { return m_port->tag(); @@ -179,12 +209,22 @@ template<int Width, int AddrShift> void handler_entry_write_ioport<Width, AddrSh m_port->write(data, mem_mask); } +template<int Width, int AddrShift> void handler_entry_write_ioport<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + m_port->write(data, mem_mask); +} + template<int Width, int AddrShift> u16 handler_entry_write_ioport<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { m_port->write(data, mem_mask); return this->m_flags; } +template<int Width, int AddrShift> u16 handler_entry_write_ioport<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_write_ioport<Width, AddrShift>::name() const { return m_port->tag(); diff --git a/src/emu/emumem_hedp.h b/src/emu/emumem_hedp.h index 805521643c8..6b8563bd5b5 100644 --- a/src/emu/emumem_hedp.h +++ b/src/emu/emumem_hedp.h @@ -12,13 +12,15 @@ template<int Width, int AddrShift, typename READ> class handler_entry_read_delegate : public handler_entry_read_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_delegate(address_space *space, u16 flags, const READ &delegate) : handler_entry_read_address<Width, AddrShift>(space, flags), m_delegate(delegate) {} ~handler_entry_read_delegate() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -71,13 +73,15 @@ private: template<int Width, int AddrShift, typename WRITE> class handler_entry_write_delegate : public handler_entry_write_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_delegate(address_space *space, u16 flags, const WRITE &delegate) : handler_entry_write_address<Width, AddrShift>(space, flags), m_delegate(delegate) {} ~handler_entry_write_delegate() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -135,13 +139,15 @@ private: template<int Width, int AddrShift> class handler_entry_read_ioport : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_ioport(address_space *space, u16 flags, ioport_port *port) : handler_entry_read<Width, AddrShift>(space, flags), m_port(port) {} ~handler_entry_read_ioport() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -152,13 +158,15 @@ private: template<int Width, int AddrShift> class handler_entry_write_ioport : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_ioport(address_space *space, u16 flags, ioport_port *port) : handler_entry_write<Width, AddrShift>(space, flags), m_port(port) {} ~handler_entry_write_ioport() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; diff --git a/src/emu/emumem_hedr.h b/src/emu/emumem_hedr.h index 277cb2d1c27..e1e9aa98743 100644 --- a/src/emu/emumem_hedr.h +++ b/src/emu/emumem_hedr.h @@ -13,7 +13,7 @@ template<int HighBits, int Width, int AddrShift> class handler_entry_read_dispatch : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; using mapping = typename handler_entry_read<Width, AddrShift>::mapping; handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift> *handler); @@ -22,7 +22,9 @@ public: ~handler_entry_read_dispatch(); uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift> *&handler) const override; diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp index 3a192e33750..9994f251897 100644 --- a/src/emu/emumem_hedr.ipp +++ b/src/emu/emumem_hedr.ipp @@ -127,16 +127,26 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc } } -template<int HighBits, int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_dispatch<HighBits, Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read(offs_t offset, uX mem_mask) const { return dispatch_read<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch); } -template<int HighBits, int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return dispatch_read_interruptible<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch); +} + +template<int HighBits, int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { return dispatch_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch); } +template<int HighBits, int Width, int AddrShift> u16 handler_entry_read_dispatch<HighBits, Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return dispatch_lookup_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch); +} + template<int HighBits, int Width, int AddrShift> void *handler_entry_read_dispatch<HighBits, Width, AddrShift>::get_ptr(offs_t offset) const { return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); @@ -196,6 +206,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc cur->unref(); m_u_dispatch[entry] = subdispatch; subdispatch->populate_nomirror(start, end, ostart, oend, handler); + range_cut_before((entry << LowBits) - 1, entry); + range_cut_after((entry + 1) << LowBits, entry); } } @@ -271,6 +283,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc cur->unref(); m_u_dispatch[entry] = subdispatch; subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler); + range_cut_before((entry << LowBits) - 1, entry); + range_cut_after((entry + 1) << LowBits, entry); } } @@ -435,23 +449,64 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc } } - template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::passthrough_patch(handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift> *&target) { - handler_entry_read<Width, AddrShift> *original = target; - handler_entry_read<Width, AddrShift> *replacement = nullptr; + // Look in cache first for(const auto &p : mappings) - if(p.original == original) { - replacement = p.patched; - break; + if(p.original == target) { + p.patched->ref(); + target->unref(); + target = p.patched; + return; } - if(!replacement) { - replacement = handler->instantiate(original); + + handler_entry_read<Width, AddrShift> *original = target; + u32 target_priority = original->f_get_pt(); + u32 new_priority = handler->f_get_pt(); + + // 3 cases: new one on top, new one on bottom, or new one replaces old one + + if(!target_priority || new_priority > target_priority || (new_priority == target_priority && !(new_priority & 1))) { + // New one goes over the old one + // previous one is not passthrough (target_priority = 0) + // new one has higher priority + // both have the same priority, and the priority is even which means keep both + + // We instantiate the new one with the old one under it and put it in place and in the cache + + handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(original); mappings.emplace_back(mapping{ original, replacement }); - } else - replacement->ref(); - target->unref(); - target = replacement; + target->unref(); + target = replacement; + + } else if(new_priority == target_priority) { + // New one replaces the old one + // both have the same priority, and the priority is odd which means keep only the new one + + // We instantiate the new one with the old one's subtarget and put it in place and in the cache + + handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler()); + mappings.emplace_back(mapping{ original, replacement }); + target->unref(); + target = replacement; + + } else { + // New one goes under the old one + // both are passthrough and new one has lower priority + // + // This can be recursive, so do the passthrough patch on the subhandler, then instantiate the old one with the result + + handler_entry_read<Width, AddrShift> *recursive = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler(); + recursive->ref(); + + passthrough_patch(handler, mappings, recursive); + + handler_entry_read<Width, AddrShift> *replacement = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->instantiate(recursive); + mappings.emplace_back(mapping{ original, replacement }); + target->unref(); + target = replacement; + recursive->unref(); + } } template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings) diff --git a/src/emu/emumem_hedw.h b/src/emu/emumem_hedw.h index 4c4f0f36037..130293a73a4 100644 --- a/src/emu/emumem_hedw.h +++ b/src/emu/emumem_hedw.h @@ -13,7 +13,7 @@ template<int HighBits, int Width, int AddrShift> class handler_entry_write_dispatch : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; using mapping = typename handler_entry_write<Width, AddrShift>::mapping; handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write<Width, AddrShift> *handler); @@ -22,7 +22,9 @@ public: ~handler_entry_write_dispatch(); void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift> *&handler) const override; diff --git a/src/emu/emumem_hedw.ipp b/src/emu/emumem_hedw.ipp index d9c4ced36e4..37c09ccfe11 100644 --- a/src/emu/emumem_hedw.ipp +++ b/src/emu/emumem_hedw.ipp @@ -131,11 +131,21 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat dispatch_write<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch); } +template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + dispatch_write_interruptible<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch); +} + template<int HighBits, int Width, int AddrShift> u16 handler_entry_write_dispatch<HighBits, Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { return dispatch_write_flags<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch); } +template<int HighBits, int Width, int AddrShift> u16 handler_entry_write_dispatch<HighBits, Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return dispatch_lookup_write_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch); +} + template<int HighBits, int Width, int AddrShift> void *handler_entry_write_dispatch<HighBits, Width, AddrShift>::get_ptr(offs_t offset) const { return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); @@ -195,6 +205,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat cur->unref(); m_u_dispatch[entry] = subdispatch; subdispatch->populate_nomirror(start, end, ostart, oend, handler); + range_cut_before((entry << LowBits) - 1, entry); + range_cut_after((entry + 1) << LowBits, entry); } } @@ -270,6 +282,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat cur->unref(); m_u_dispatch[entry] = subdispatch; subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler); + range_cut_before((entry << LowBits) - 1, entry); + range_cut_after((entry + 1) << LowBits, entry); } } @@ -437,20 +451,63 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::passthrough_patch(handler_entry_write_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings, handler_entry_write<Width, AddrShift> *&target) { - handler_entry_write<Width, AddrShift> *original = target; - handler_entry_write<Width, AddrShift> *replacement = nullptr; + // Look in cache first for(const auto &p : mappings) - if(p.original == original) { - replacement = p.patched; - break; + if(p.original == target) { + p.patched->ref(); + target->unref(); + target = p.patched; + return; } - if(!replacement) { - replacement = handler->instantiate(original); + + handler_entry_write<Width, AddrShift> *original = target; + u32 target_priority = original->f_get_pt(); + u32 new_priority = handler->f_get_pt(); + + // 3 cases: new one on top, new one on bottom, or new one replaces old one + + if(!target_priority || new_priority > target_priority || (new_priority == target_priority && !(new_priority & 1))) { + // New one goes over the old one + // previous one is not passthrough (target_priority = 0) + // new one has higher priority + // both have the same priority, and the priority is even which means keep both + + // We instantiate the new one with the old one under it and put it in place and in the cache + + handler_entry_write<Width, AddrShift> *replacement = handler->instantiate(original); mappings.emplace_back(mapping{ original, replacement }); - } else - replacement->ref(); - target->unref(); - target = replacement; + target->unref(); + target = replacement; + + } else if(new_priority == target_priority) { + // New one replaces the old one + // both have the same priority, and the priority is odd which means keep only the new one + + // We instantiate the new one with the old one's subtarget and put it in place and in the cache + + handler_entry_write<Width, AddrShift> *replacement = handler->instantiate(static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->get_subhandler()); + mappings.emplace_back(mapping{ original, replacement }); + target->unref(); + target = replacement; + + } else { + // New one goes under the old one + // both are passthrough and new one has lower priority + // + // This can be recursive, so do the passthrough patch on the subhandler, then instantiate the old one with the result + + handler_entry_write<Width, AddrShift> *recursive = static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->get_subhandler(); + recursive->ref(); + + passthrough_patch(handler, mappings, recursive); + + handler_entry_write<Width, AddrShift> *replacement = static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->instantiate(recursive); + mappings.emplace_back(mapping{ original, replacement }); + target->unref(); + target = replacement; + recursive->unref(); + } + } template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings) diff --git a/src/emu/emumem_hem.cpp b/src/emu/emumem_hem.cpp index b835538c3dd..e69206d7653 100644 --- a/src/emu/emumem_hem.cpp +++ b/src/emu/emumem_hem.cpp @@ -5,16 +5,26 @@ #include "emumem_hea.h" #include "emumem_hem.h" -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_memory<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { return m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)]; } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_memory<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)]; +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_memory<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { return std::pair<uX, u16>(m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)], this->m_flags); } +template<int Width, int AddrShift> u16 handler_entry_read_memory<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> void *handler_entry_read_memory<Width, AddrShift>::get_ptr(offs_t offset) const { return m_base + (((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)); @@ -32,6 +42,12 @@ template<int Width, int AddrShift> void handler_entry_write_memory<Width, AddrSh m_base[off] = (m_base[off] & ~mem_mask) | (data & mem_mask); } +template<int Width, int AddrShift> void handler_entry_write_memory<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift); + m_base[off] = (m_base[off] & ~mem_mask) | (data & mem_mask); +} + template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift); @@ -39,11 +55,21 @@ template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShi return this->m_flags; } +template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<> void handler_entry_write_memory<0, 0>::write(offs_t offset, u8 data, u8 mem_mask) const { m_base[(offset - this->m_address_base) & this->m_address_mask] = data; } +template<> void handler_entry_write_memory<0, 0>::write_interruptible(offs_t offset, u8 data, u8 mem_mask) const +{ + m_base[(offset - this->m_address_base) & this->m_address_mask] = data; +} + template<> u16 handler_entry_write_memory<0, 0>::write_flags(offs_t offset, u8 data, u8 mem_mask) const { m_base[(offset - this->m_address_base) & this->m_address_mask] = data; @@ -64,16 +90,26 @@ template<int Width, int AddrShift> std::string handler_entry_write_memory<Width, -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_memory_bank<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory_bank<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { return static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)]; } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_memory_bank<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory_bank<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)]; +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_memory_bank<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { return std::pair<uX, u16>(static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)], this->m_flags); } +template<int Width, int AddrShift> u16 handler_entry_read_memory_bank<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> void *handler_entry_read_memory_bank<Width, AddrShift>::get_ptr(offs_t offset) const { return static_cast<uX *>(m_bank.base()) + (((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)); @@ -91,6 +127,12 @@ template<int Width, int AddrShift> void handler_entry_write_memory_bank<Width, A static_cast<uX *>(m_bank.base())[off] = (static_cast<uX *>(m_bank.base())[off] & ~mem_mask) | (data & mem_mask); } +template<int Width, int AddrShift> void handler_entry_write_memory_bank<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift); + static_cast<uX *>(m_bank.base())[off] = (static_cast<uX *>(m_bank.base())[off] & ~mem_mask) | (data & mem_mask); +} + template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift); @@ -98,11 +140,21 @@ template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, Ad return this->m_flags; } +template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<> void handler_entry_write_memory_bank<0, 0>::write(offs_t offset, u8 data, u8 mem_mask) const { static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data; } +template<> void handler_entry_write_memory_bank<0, 0>::write_interruptible(offs_t offset, u8 data, u8 mem_mask) const +{ + static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data; +} + template<> u16 handler_entry_write_memory_bank<0, 0>::write_flags(offs_t offset, u8 data, u8 mem_mask) const { static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data; diff --git a/src/emu/emumem_hem.h b/src/emu/emumem_hem.h index b5edc2c27dc..d4c8c145860 100644 --- a/src/emu/emumem_hem.h +++ b/src/emu/emumem_hem.h @@ -12,13 +12,15 @@ template<int Width, int AddrShift> class handler_entry_read_memory : public handler_entry_read_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_memory(address_space *space, u16 flags, void *base) : handler_entry_read_address<Width, AddrShift>(space, flags), m_base(reinterpret_cast<uX *>(base)) {} ~handler_entry_read_memory() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; std::string name() const override; @@ -30,13 +32,15 @@ private: template<int Width, int AddrShift> class handler_entry_write_memory : public handler_entry_write_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_memory(address_space *space, u16 flags, void *base) : handler_entry_write_address<Width, AddrShift>(space, flags), m_base(reinterpret_cast<uX *>(base)) {} ~handler_entry_write_memory() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; std::string name() const override; @@ -53,13 +57,15 @@ private: template<int Width, int AddrShift> class handler_entry_read_memory_bank : public handler_entry_read_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_memory_bank(address_space *space, u16 flags, memory_bank &bank) : handler_entry_read_address<Width, AddrShift>(space, flags), m_bank(bank) {} ~handler_entry_read_memory_bank() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; std::string name() const override; @@ -71,13 +77,15 @@ private: template<int Width, int AddrShift> class handler_entry_write_memory_bank : public handler_entry_write_address<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_memory_bank(address_space *space, u16 flags, memory_bank &bank) : handler_entry_write_address<Width, AddrShift>(space, flags), m_bank(bank) {} ~handler_entry_write_memory_bank() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; std::string name() const override; diff --git a/src/emu/emumem_hep.h b/src/emu/emumem_hep.h index 60fc422b72e..bc8616cea2b 100644 --- a/src/emu/emumem_hep.h +++ b/src/emu/emumem_hep.h @@ -8,9 +8,9 @@ template<int Width, int AddrShift> class handler_entry_read_passthrough : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; - handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {} + handler_entry_read_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio) : handler_entry_read<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(nullptr) {} ~handler_entry_read_passthrough(); virtual handler_entry_read_passthrough<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const = 0; @@ -20,18 +20,18 @@ public: void detach(const std::unordered_set<handler_entry *> &handlers) override; protected: - memory_passthrough_handler &m_mph; + emu::detail::memory_passthrough_handler_impl &m_mph; handler_entry_read<Width, AddrShift> *m_next; - handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_read<Width, AddrShift> *next) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } + handler_entry_read_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio, handler_entry_read<Width, AddrShift> *next) : handler_entry_read<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } }; template<int Width, int AddrShift> class handler_entry_write_passthrough : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; - handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {} + handler_entry_write_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio) : handler_entry_write<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(nullptr) {} ~handler_entry_write_passthrough(); virtual handler_entry_write_passthrough<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const = 0; @@ -41,8 +41,8 @@ public: void detach(const std::unordered_set<handler_entry *> &handlers) override; protected: - memory_passthrough_handler &m_mph; + emu::detail::memory_passthrough_handler_impl &m_mph; handler_entry_write<Width, AddrShift> *m_next; - handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_write<Width, AddrShift> *next) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } + handler_entry_write_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio, handler_entry_write<Width, AddrShift> *next) : handler_entry_write<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); } }; diff --git a/src/emu/emumem_het.cpp b/src/emu/emumem_het.cpp index 1360badd99c..23349659a48 100644 --- a/src/emu/emumem_het.cpp +++ b/src/emu/emumem_het.cpp @@ -5,7 +5,7 @@ #include "emumem_hep.h" #include "emumem_het.h" -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_tap<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_tap<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { this->ref(); @@ -16,7 +16,18 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt return data; } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_tap<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_tap<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + this->ref(); + + uX data = this->m_next->read_interruptible(offset, mem_mask); + m_tap(offset, data, mem_mask); + + this->unref(); + return data; +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_tap<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { this->ref(); @@ -27,6 +38,11 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry return pack; } +template<int Width, int AddrShift> u16 handler_entry_read_tap<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + template<int Width, int AddrShift> std::string handler_entry_read_tap<Width, AddrShift>::name() const { return '(' + m_name + ") " + this->m_next->name(); @@ -48,6 +64,16 @@ template<int Width, int AddrShift> void handler_entry_write_tap<Width, AddrShift this->unref(); } +template<int Width, int AddrShift> void handler_entry_write_tap<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + this->ref(); + + m_tap(offset, data, mem_mask); + this->m_next->write_interruptible(offset, data, mem_mask); + + this->unref(); +} + template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { this->ref(); @@ -59,6 +85,11 @@ template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift> return flags; } +template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + template<int Width, int AddrShift> std::string handler_entry_write_tap<Width, AddrShift>::name() const { return '(' + m_name + ") " + this->m_next->name(); diff --git a/src/emu/emumem_het.h b/src/emu/emumem_het.h index 2914605772b..97650c6cbe3 100644 --- a/src/emu/emumem_het.h +++ b/src/emu/emumem_het.h @@ -12,13 +12,15 @@ template<int Width, int AddrShift> class handler_entry_read_tap : public handler_entry_read_passthrough<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; - handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph), m_name(name), m_tap(std::move(tap)) {} + handler_entry_read_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 4), m_name(name), m_tap(std::move(tap)) {} ~handler_entry_read_tap() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -28,19 +30,21 @@ protected: std::string m_name; std::function<void (offs_t offset, uX &data, uX mem_mask)> m_tap; - handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_read<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, next), m_name(name), m_tap(tap) {} + handler_entry_read_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 4, next), m_name(name), m_tap(tap) {} }; template<int Width, int AddrShift> class handler_entry_write_tap : public handler_entry_write_passthrough<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; - handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph), m_name(name), m_tap(std::move(tap)) {} + handler_entry_write_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 4), m_name(name), m_tap(std::move(tap)) {} ~handler_entry_write_tap() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -50,7 +54,7 @@ protected: std::string m_name; std::function<void (offs_t offset, uX &data, uX mem_mask)> m_tap; - handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_write<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, next), m_name(name), m_tap(tap) {} + handler_entry_write_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 4, next), m_name(name), m_tap(tap) {} }; #endif // MAME_EMU_EMUMEM_HET_H diff --git a/src/emu/emumem_heu.cpp b/src/emu/emumem_heu.cpp index 3c05a1e04da..ada5d56d63a 100644 --- a/src/emu/emumem_heu.cpp +++ b/src/emu/emumem_heu.cpp @@ -75,7 +75,7 @@ template<int Width, int AddrShift> void handler_entry_read_units<Width, AddrShif } -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_units<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_units<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { this->ref(); @@ -104,7 +104,12 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt return result; } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_units<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_units<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return read(offset, mem_mask); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_units<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { this->ref(); @@ -137,7 +142,36 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry return std::make_pair(result, flags); } -template<int Width, int AddrShift> std::string handler_entry_read_units<Width, AddrShift>::m2r(typename emu::detail::handler_entry_size<Width>::uX mask) +template<int Width, int AddrShift> u16 handler_entry_read_units<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + this->ref(); + + u16 flags = 0; + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if (mem_mask & si.m_amask) { + offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset; + switch(si.m_width) { + case 0: + flags |= static_cast<handler_entry_read<0, 0> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + case 1: + flags |= static_cast<handler_entry_read<1, -1> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + case 2: + flags |= static_cast<handler_entry_read<2, -2> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + default: + abort(); + } + } + } + + this->unref(); + return flags; +} + +template<int Width, int AddrShift> std::string handler_entry_read_units<Width, AddrShift>::m2r(emu::detail::handler_entry_size_t<Width> mask) { constexpr u32 mbits = 8*sizeof(uX); u32 start, end; @@ -256,6 +290,11 @@ template<int Width, int AddrShift> void handler_entry_write_units<Width, AddrShi this->unref(); } +template<int Width, int AddrShift> void handler_entry_write_units<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + write(offset, data, mem_mask); +} + template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { this->ref(); @@ -285,8 +324,37 @@ template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShif return flags; } +template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + this->ref(); + + u16 flags = 0; + for (int index = 0; index < m_subunits; index++) { + const subunit_info &si = m_subunit_infos[index]; + if (mem_mask & si.m_amask) { + offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset; + switch(si.m_width) { + case 0: + flags |= static_cast<handler_entry_write<0, 0> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + case 1: + flags |= static_cast<handler_entry_write<1, -1> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + case 2: + flags |= static_cast<handler_entry_write<2, -2> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift); + break; + default: + abort(); + } + } + } + + this->unref(); + return flags; +} + -template<int Width, int AddrShift> std::string handler_entry_write_units<Width, AddrShift>::m2r(typename emu::detail::handler_entry_size<Width>::uX mask) +template<int Width, int AddrShift> std::string handler_entry_write_units<Width, AddrShift>::m2r(emu::detail::handler_entry_size_t<Width> mask) { constexpr u32 mbits = 8*sizeof(uX); u32 start, end; diff --git a/src/emu/emumem_heu.h b/src/emu/emumem_heu.h index 4b44a72db09..8573cc4e334 100644 --- a/src/emu/emumem_heu.h +++ b/src/emu/emumem_heu.h @@ -12,7 +12,7 @@ template<int Width, int AddrShift> class handler_entry_read_units : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, address_space *space); handler_entry_read_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, const handler_entry_read_units *src); @@ -20,7 +20,9 @@ public: ~handler_entry_read_units(); uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; @@ -54,7 +56,7 @@ private: template<int Width, int AddrShift> class handler_entry_write_units : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, address_space *space); handler_entry_write_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, const handler_entry_write_units<Width, AddrShift> *src); @@ -62,7 +64,9 @@ public: ~handler_entry_write_units(); void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; diff --git a/src/emu/emumem_heun.cpp b/src/emu/emumem_heun.cpp index 4caa177c195..5157c2c35df 100644 --- a/src/emu/emumem_heun.cpp +++ b/src/emu/emumem_heun.cpp @@ -5,7 +5,7 @@ #include "emumem_hea.h" #include "emumem_heun.h" -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_unmapped<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_unmapped<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) this->m_space->device().logerror(this->m_space->is_octal() @@ -17,7 +17,19 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt return this->m_space->unmap(); } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_unmapped<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_unmapped<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) + this->m_space->device().logerror(this->m_space->is_octal() + ? "%s: unmapped %s memory read from %0*o & %0*o\n" + : "%s: unmapped %s memory read from %0*X & %0*X\n", + this->m_space->m_manager.machine().describe_context(), this->m_space->name(), + this->m_space->addrchars(), offset, + 2 << Width, mem_mask); + return this->m_space->unmap(); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_unmapped<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) this->m_space->device().logerror(this->m_space->is_octal() @@ -29,6 +41,18 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry return std::pair<uX, u16>(this->m_space->unmap(), this->m_flags); } +template<int Width, int AddrShift> u16 handler_entry_read_unmapped<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) + this->m_space->device().logerror(this->m_space->is_octal() + ? "%s: unmapped %s memory read flags lookup from %0*o & %0*o\n" + : "%s: unmapped %s memory read flags lookup from %0*X & %0*X\n", + this->m_space->m_manager.machine().describe_context(), this->m_space->name(), + this->m_space->addrchars(), offset, + 2 << Width, mem_mask); + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_read_unmapped<Width, AddrShift>::name() const { return "unmapped"; @@ -47,6 +71,18 @@ template<int Width, int AddrShift> void handler_entry_write_unmapped<Width, Addr 2 << Width, mem_mask); } +template<int Width, int AddrShift> void handler_entry_write_unmapped<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask)const +{ + if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) + this->m_space->device().logerror(this->m_space->is_octal() + ? "%s: unmapped %s memory write to %0*o = %0*o & %0*o\n" + : "%s: unmapped %s memory write to %0*X = %0*X & %0*X\n", + this->m_space->m_manager.machine().describe_context(), this->m_space->name(), + this->m_space->addrchars(), offset, + 2 << Width, data, + 2 << Width, mem_mask); +} + template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask)const { if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) @@ -60,6 +96,18 @@ template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrS return this->m_flags; } +template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask)const +{ + if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled()) + this->m_space->device().logerror(this->m_space->is_octal() + ? "%s: unmapped %s write flags lookup from %0*o & %0*o\n" + : "%s: unmapped %s write flags lookup from %0*X & %0*X\n", + this->m_space->m_manager.machine().describe_context(), this->m_space->name(), + this->m_space->addrchars(), offset, + 2 << Width, mem_mask); + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_write_unmapped<Width, AddrShift>::name() const { return "unmapped"; @@ -68,16 +116,26 @@ template<int Width, int AddrShift> std::string handler_entry_write_unmapped<Widt -template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_nop<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_nop<Width, AddrShift>::read(offs_t offset, uX mem_mask) const { return this->m_space->unmap(); } -template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_nop<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_nop<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + return this->m_space->unmap(); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_nop<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const { return std::pair<uX, u16>(this->m_space->unmap(), this->m_flags); } +template<int Width, int AddrShift> u16 handler_entry_read_nop<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_read_nop<Width, AddrShift>::name() const { return "nop"; @@ -88,11 +146,20 @@ template<int Width, int AddrShift> void handler_entry_write_nop<Width, AddrShift { } +template<int Width, int AddrShift> void handler_entry_write_nop<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ +} + template<int Width, int AddrShift> u16 handler_entry_write_nop<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const { return this->m_flags; } +template<int Width, int AddrShift> u16 handler_entry_write_nop<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_flags; +} + template<int Width, int AddrShift> std::string handler_entry_write_nop<Width, AddrShift>::name() const { return "nop"; diff --git a/src/emu/emumem_heun.h b/src/emu/emumem_heun.h index e355bbe8177..69a97e84f37 100644 --- a/src/emu/emumem_heun.h +++ b/src/emu/emumem_heun.h @@ -12,13 +12,15 @@ template<int Width, int AddrShift> class handler_entry_read_unmapped : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_unmapped(address_space *space, u16 flags) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_UNMAP | flags) {} ~handler_entry_read_unmapped() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; }; @@ -26,13 +28,15 @@ public: template<int Width, int AddrShift> class handler_entry_write_unmapped : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_unmapped(address_space *space, u16 flags) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_UNMAP | flags) {} ~handler_entry_write_unmapped() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; }; @@ -46,13 +50,15 @@ public: template<int Width, int AddrShift> class handler_entry_read_nop : public handler_entry_read<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_read_nop(address_space *space, u16 flags) : handler_entry_read<Width, AddrShift>(space, flags) {} ~handler_entry_read_nop() = default; uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; }; @@ -60,13 +66,15 @@ public: template<int Width, int AddrShift> class handler_entry_write_nop : public handler_entry_write<Width, AddrShift> { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; handler_entry_write_nop(address_space *space, u16 flags) : handler_entry_write<Width, AddrShift>(space, flags) {} ~handler_entry_write_nop() = default; void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; std::string name() const override; }; diff --git a/src/emu/emumem_hws.cpp b/src/emu/emumem_hws.cpp new file mode 100644 index 00000000000..9aae20d9f4c --- /dev/null +++ b/src/emu/emumem_hws.cpp @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_hep.h" +#include "emumem_hws.h" + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_time<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +{ + return this->m_next->read(offset, mem_mask); +} + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_time<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + u64 tc = m_cpu.total_cycles(); + u64 ac = m_ws(offset, tc); + + if(ac < tc) + ac = tc; + + if(m_cpu.access_before_time(ac, tc)) + return 0; + + return this->m_next->read_interruptible(offset, mem_mask); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_before_time<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->read_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_read_before_time<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_read_before_time<Width, AddrShift>::name() const +{ + return util::string_format("(bt %s) %s", m_ws.name(), this->m_next->name()); +} + +template<int Width, int AddrShift> handler_entry_read_before_time<Width, AddrShift> *handler_entry_read_before_time<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const +{ + return new handler_entry_read_before_time<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + +template<int Width, int AddrShift> void handler_entry_write_before_time<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const +{ + this->m_next->write(offset, data, mem_mask); +} + +template<int Width, int AddrShift> void handler_entry_write_before_time<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + u64 tc = m_cpu.total_cycles(); + u64 ac = m_ws(offset, tc); + + if(ac < tc) + ac = tc; + + if(m_cpu.access_before_time(ac, tc)) + return; + this->m_next->write_interruptible(offset, data, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_write_before_time<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const +{ + return this->m_next->write_flags(offset, data, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_write_before_time<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_write_before_time<Width, AddrShift>::name() const +{ + return util::string_format("(bt %s) %s", m_ws.name(), this->m_next->name()); +} + + +template<int Width, int AddrShift> handler_entry_write_before_time<Width, AddrShift> *handler_entry_write_before_time<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const +{ + return new handler_entry_write_before_time<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + + +template class handler_entry_read_before_time<0, 1>; +template class handler_entry_read_before_time<0, 0>; +template class handler_entry_read_before_time<1, 3>; +template class handler_entry_read_before_time<1, 0>; +template class handler_entry_read_before_time<1, -1>; +template class handler_entry_read_before_time<2, 3>; +template class handler_entry_read_before_time<2, 0>; +template class handler_entry_read_before_time<2, -1>; +template class handler_entry_read_before_time<2, -2>; +template class handler_entry_read_before_time<3, 0>; +template class handler_entry_read_before_time<3, -1>; +template class handler_entry_read_before_time<3, -2>; +template class handler_entry_read_before_time<3, -3>; + +template class handler_entry_write_before_time<0, 1>; +template class handler_entry_write_before_time<0, 0>; +template class handler_entry_write_before_time<1, 3>; +template class handler_entry_write_before_time<1, 0>; +template class handler_entry_write_before_time<1, -1>; +template class handler_entry_write_before_time<2, 3>; +template class handler_entry_write_before_time<2, 0>; +template class handler_entry_write_before_time<2, -1>; +template class handler_entry_write_before_time<2, -2>; +template class handler_entry_write_before_time<3, 0>; +template class handler_entry_write_before_time<3, -1>; +template class handler_entry_write_before_time<3, -2>; +template class handler_entry_write_before_time<3, -3>; + + + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_delay<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +{ + return this->m_next->read(offset, mem_mask); +} + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_delay<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + if(m_cpu.access_before_delay(m_ws(offset), this)) + return 0; + + return this->m_next->read_interruptible(offset, mem_mask); +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_before_delay<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->read_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_read_before_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_read_before_delay<Width, AddrShift>::name() const +{ + return util::string_format("(bd %s) %s", m_ws.name(), this->m_next->name()); +} + +template<int Width, int AddrShift> handler_entry_read_before_delay<Width, AddrShift> *handler_entry_read_before_delay<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const +{ + return new handler_entry_read_before_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + +template<int Width, int AddrShift> void handler_entry_write_before_delay<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const +{ + this->m_next->write(offset, data, mem_mask); +} + +template<int Width, int AddrShift> void handler_entry_write_before_delay<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + if(m_cpu.access_before_delay(m_ws(offset), this)) + return; + this->m_next->write_interruptible(offset, data, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_write_before_delay<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const +{ + return this->m_next->write_flags(offset, data, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_write_before_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_write_before_delay<Width, AddrShift>::name() const +{ + return util::string_format("(bd %s) %s", m_ws.name(), this->m_next->name()); +} + + +template<int Width, int AddrShift> handler_entry_write_before_delay<Width, AddrShift> *handler_entry_write_before_delay<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const +{ + return new handler_entry_write_before_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + + +template class handler_entry_read_before_delay<0, 1>; +template class handler_entry_read_before_delay<0, 0>; +template class handler_entry_read_before_delay<1, 3>; +template class handler_entry_read_before_delay<1, 0>; +template class handler_entry_read_before_delay<1, -1>; +template class handler_entry_read_before_delay<2, 3>; +template class handler_entry_read_before_delay<2, 0>; +template class handler_entry_read_before_delay<2, -1>; +template class handler_entry_read_before_delay<2, -2>; +template class handler_entry_read_before_delay<3, 0>; +template class handler_entry_read_before_delay<3, -1>; +template class handler_entry_read_before_delay<3, -2>; +template class handler_entry_read_before_delay<3, -3>; + +template class handler_entry_write_before_delay<0, 1>; +template class handler_entry_write_before_delay<0, 0>; +template class handler_entry_write_before_delay<1, 3>; +template class handler_entry_write_before_delay<1, 0>; +template class handler_entry_write_before_delay<1, -1>; +template class handler_entry_write_before_delay<2, 3>; +template class handler_entry_write_before_delay<2, 0>; +template class handler_entry_write_before_delay<2, -1>; +template class handler_entry_write_before_delay<2, -2>; +template class handler_entry_write_before_delay<3, 0>; +template class handler_entry_write_before_delay<3, -1>; +template class handler_entry_write_before_delay<3, -2>; +template class handler_entry_write_before_delay<3, -3>; + + + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_after_delay<Width, AddrShift>::read(offs_t offset, uX mem_mask) const +{ + return this->m_next->read(offset, mem_mask); +} + +template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_after_delay<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const +{ + auto r = this->m_next->read_interruptible(offset, mem_mask); + m_cpu.access_after_delay(m_ws(offset)); + return r; +} + +template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_after_delay<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->read_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_read_after_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_read_after_delay<Width, AddrShift>::name() const +{ + return util::string_format("(ad %s) %s", m_ws.name(), this->m_next->name()); +} + +template<int Width, int AddrShift> handler_entry_read_after_delay<Width, AddrShift> *handler_entry_read_after_delay<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const +{ + return new handler_entry_read_after_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + +template<int Width, int AddrShift> void handler_entry_write_after_delay<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const +{ + this->m_next->write(offset, data, mem_mask); +} + +template<int Width, int AddrShift> void handler_entry_write_after_delay<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const +{ + this->m_next->write_interruptible(offset, data, mem_mask); + m_cpu.access_after_delay(m_ws(offset)); +} + +template<int Width, int AddrShift> u16 handler_entry_write_after_delay<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const +{ + return this->m_next->write_flags(offset, data, mem_mask); +} + +template<int Width, int AddrShift> u16 handler_entry_write_after_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const +{ + return this->m_next->lookup_flags(offset, mem_mask); +} + +template<int Width, int AddrShift> std::string handler_entry_write_after_delay<Width, AddrShift>::name() const +{ + return util::string_format("(ad %s) %s", m_ws.name(), this->m_next->name()); +} + + +template<int Width, int AddrShift> handler_entry_write_after_delay<Width, AddrShift> *handler_entry_write_after_delay<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const +{ + return new handler_entry_write_after_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws); +} + + + +template class handler_entry_read_after_delay<0, 1>; +template class handler_entry_read_after_delay<0, 0>; +template class handler_entry_read_after_delay<1, 3>; +template class handler_entry_read_after_delay<1, 0>; +template class handler_entry_read_after_delay<1, -1>; +template class handler_entry_read_after_delay<2, 3>; +template class handler_entry_read_after_delay<2, 0>; +template class handler_entry_read_after_delay<2, -1>; +template class handler_entry_read_after_delay<2, -2>; +template class handler_entry_read_after_delay<3, 0>; +template class handler_entry_read_after_delay<3, -1>; +template class handler_entry_read_after_delay<3, -2>; +template class handler_entry_read_after_delay<3, -3>; + +template class handler_entry_write_after_delay<0, 1>; +template class handler_entry_write_after_delay<0, 0>; +template class handler_entry_write_after_delay<1, 3>; +template class handler_entry_write_after_delay<1, 0>; +template class handler_entry_write_after_delay<1, -1>; +template class handler_entry_write_after_delay<2, 3>; +template class handler_entry_write_after_delay<2, 0>; +template class handler_entry_write_after_delay<2, -1>; +template class handler_entry_write_after_delay<2, -2>; +template class handler_entry_write_after_delay<3, 0>; +template class handler_entry_write_after_delay<3, -1>; +template class handler_entry_write_after_delay<3, -2>; +template class handler_entry_write_after_delay<3, -3>; diff --git a/src/emu/emumem_hws.h b/src/emu/emumem_hws.h new file mode 100644 index 00000000000..baaad6c7a07 --- /dev/null +++ b/src/emu/emumem_hws.h @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef MAME_EMU_EMUMEM_HWS_H +#define MAME_EMU_EMUMEM_HWS_H + +#pragma once + +// handler_entry_read_before_time/handler_entry_write_before_time +// handler_entry_read_before_delay/handler_entry_write_before_delay +// handler_entry_read_after_delay/handler_entry_write_after_delay + +// handlers which handle the different wait state cases + +template<int Width, int AddrShift> class handler_entry_read_before_time : public handler_entry_read_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_read_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_time_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_read_before_time() = default; + + uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; + std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_read_before_time<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override; + +protected: + ws_time_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_read_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_time_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + +template<int Width, int AddrShift> class handler_entry_write_before_time : public handler_entry_write_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_write_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_time_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_write_before_time() = default; + + void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; + u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_write_before_time<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override; + +protected: + ws_time_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_write_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_time_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + + + +template<int Width, int AddrShift> class handler_entry_read_before_delay : public handler_entry_read_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_read_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_read_before_delay() = default; + + uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; + std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_read_before_delay<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override; + +protected: + ws_delay_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_read_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + +template<int Width, int AddrShift> class handler_entry_write_before_delay : public handler_entry_write_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_write_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 11), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_write_before_delay() = default; + + void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; + u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_write_before_delay<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override; + +protected: + ws_delay_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_write_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 11, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + + + +template<int Width, int AddrShift> class handler_entry_read_after_delay : public handler_entry_read_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_read_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 9), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_read_after_delay() = default; + + uX read(offs_t offset, uX mem_mask) const override; + uX read_interruptible(offs_t offset, uX mem_mask) const override; + std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_read_after_delay<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override; + +protected: + ws_delay_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_read_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 9, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + +template<int Width, int AddrShift> class handler_entry_write_after_delay : public handler_entry_write_passthrough<Width, AddrShift> +{ +public: + using uX = emu::detail::handler_entry_size_t<Width>; + + handler_entry_write_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 9), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} + ~handler_entry_write_after_delay() = default; + + void write(offs_t offset, uX data, uX mem_mask) const override; + void write_interruptible(offs_t offset, uX data, uX mem_mask) const override; + u16 write_flags(offs_t offset, uX data, uX mem_mask) const override; + u16 lookup_flags(offs_t offset, uX mem_mask) const override; + + std::string name() const override; + + handler_entry_write_after_delay<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override; + +protected: + ws_delay_delegate m_ws; + cpu_device &m_cpu; + + handler_entry_write_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 9, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {} +}; + +#endif // MAME_EMU_EMUMEM_HWS_H diff --git a/src/emu/emumem_mud.cpp b/src/emu/emumem_mud.cpp index b8fed565eea..4c52b5a1301 100644 --- a/src/emu/emumem_mud.cpp +++ b/src/emu/emumem_mud.cpp @@ -35,7 +35,7 @@ template<> u8 mask_to_ukey<u64>(u64 mask) (mask & 0x00000000000000ff ? 0x01 : 0x00); } -template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::memory_units_descriptor(u8 access_width, endianness_t access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, typename emu::detail::handler_entry_size<Width>::uX unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian) +template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::memory_units_descriptor(u8 access_width, endianness_t access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, emu::detail::handler_entry_size_t<Width> unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian) { u32 bits_per_access = 8 << access_width; constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0; @@ -86,7 +86,7 @@ template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::me generate(m_keymap[i], unitmask, umasks[i], cswidth, bits_per_access, base_shift, shift, active_count); } -template<int Width, int AddrShift> void memory_units_descriptor<Width, AddrShift>::generate(u8 ukey, typename emu::detail::handler_entry_size<Width>::uX gumask, typename emu::detail::handler_entry_size<Width>::uX umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count) +template<int Width, int AddrShift> void memory_units_descriptor<Width, AddrShift>::generate(u8 ukey, emu::detail::handler_entry_size_t<Width> gumask, emu::detail::handler_entry_size_t<Width> umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count) { auto &entries = m_entries_for_key[ukey]; diff --git a/src/emu/emumem_mud.h b/src/emu/emumem_mud.h index 12c8cf92eb5..4a8b6509aa0 100644 --- a/src/emu/emumem_mud.h +++ b/src/emu/emumem_mud.h @@ -5,7 +5,7 @@ template<int Width, int AddrShift> class memory_units_descriptor { public: - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; struct entry { uX m_amask; diff --git a/src/emu/emumem_mview.cpp b/src/emu/emumem_mview.cpp index 06007c7d0b5..2456cadc7f9 100644 --- a/src/emu/emumem_mview.cpp +++ b/src/emu/emumem_mview.cpp @@ -25,6 +25,7 @@ #include "emumem_hedw.h" #include "emumem_hep.h" #include "emumem_het.h" +#include "emumem_hws.h" #define VERBOSE 0 @@ -37,58 +38,7 @@ template <typename Format, typename... Params> static void VPRINTF(Format &&fmt, template <typename Format, typename... Params> static void VPRINTF(Format &&, Params &&...) {} #endif -namespace { - -template <typename Delegate> struct handler_width; -template <> struct handler_width<read8_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; }; -template <> struct handler_width<read16_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; }; -template <> struct handler_width<read32_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; }; -template <> struct handler_width<read64_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; }; -template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; }; -} // anonymous namespace +using emu::detail::handler_width_v; address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs_t end) { @@ -98,7 +48,7 @@ address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs template<int Level, int Width, int AddrShift> class memory_view_entry_specific : public memory_view::memory_view_entry { - using uX = typename emu::detail::handler_entry_size<Width>::uX; + using uX = emu::detail::handler_entry_size_t<Width>; using NativeType = uX; // constants describing the native size @@ -126,9 +76,9 @@ public: using address_space_installer::install_write_tap; using address_space_installer::install_readwrite_tap; - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override; virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, bool quiet) override; virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, void *baseptr) override; @@ -137,156 +87,119 @@ public: virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, std::string rtag, std::string wtag) override; virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask, int cswidth, u16 flags) override; + void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + + void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + + void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override; + void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; + void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override; void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); } void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); } template<typename READ> void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r) @@ -296,7 +209,7 @@ public: osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); throw; } - install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r); + install_read_handler_helper<handler_width_v<READ> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r); } template<typename WRITE> @@ -307,24 +220,7 @@ public: osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); throw; } - install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w); - } - - template<typename READ, typename WRITE> - void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r, WRITE &handler_w) - { - static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match"); - try { handler_r.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - try { handler_w.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r, handler_w); + install_write_handler_helper<handler_width_v<WRITE> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w); } template<int AccessWidth, typename READ> @@ -339,6 +235,9 @@ public: 8 << Width, 8 << AccessWidth, handler_r.name(), data_width() / 4, unitmask); + r()->select_u(m_id); + w()->select_u(m_id); + offs_t nstart, nend, nmask, nmirror; u64 nunitmask; int ncswidth; @@ -372,6 +271,9 @@ public: 8 << Width, 8 << AccessWidth, handler_w.name(), data_width() / 4, unitmask); + r()->select_u(m_id); + w()->select_u(m_id); + offs_t nstart, nend, nmask, nmirror; u64 nunitmask; int ncswidth; @@ -391,50 +293,6 @@ public: invalidate_caches(read_or_write::WRITE); } } - - template<int AccessWidth, typename READ, typename WRITE> - void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, - const READ &handler_r, - const WRITE &handler_w) - { - if constexpr (Width < AccessWidth) { - fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); - } else { - VPRINTF("memory_view::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmask, m_addrchars, addrmirror, - 8 << Width, 8 << AccessWidth, - handler_r.name(), handler_w.name(), data_width() / 4, unitmask); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - if constexpr (Width == AccessWidth) { - auto hand_r = new handler_entry_read_delegate <Width, AddrShift, READ>(m_view.m_space, flags, handler_r); - hand_r->set_address_info(nstart, nmask); - r() ->populate(nstart, nend, nmirror, hand_r); - - auto hand_w = new handler_entry_write_delegate<Width, AddrShift, WRITE>(m_view.m_space, flags, handler_w); - hand_w->set_address_info(nstart, nmask); - w()->populate(nstart, nend, nmirror, hand_w); - } else { - auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, READ>(m_view.m_space, flags, handler_r); - memory_units_descriptor<Width, AddrShift> descriptor(AccessWidth, endianness(), hand_r, nstart, nend, nmask, nunitmask, ncswidth); - hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - r() ->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_r->unref(); - - auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, WRITE>(m_view.m_space, flags, handler_w); - descriptor.set_subunit_handler(hand_w); - hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - w()->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_w->unref(); - } - invalidate_caches(read_or_write::READWRITE); - } - } }; namespace { @@ -578,7 +436,7 @@ void memory_view::memory_view_entry::prepare_map_generic(address_map &map, bool if (!allow_alloc) fatalerror("Trying to create memory in range %X-%X too late\n", entry.m_addrstart, entry.m_addrend); - entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend); + entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend, key()); } } } @@ -645,8 +503,8 @@ memory_view::~memory_view() void memory_view::register_state() { - m_device.machine().save().save_item(&m_device, "view", m_name.c_str(), 0, NAME(m_cur_slot)); - m_device.machine().save().save_item(&m_device, "view", m_name.c_str(), 0, NAME(m_cur_id)); + m_device.machine().save().save_item(&m_device, "view", m_device.subtag(m_name).c_str(), 0, NAME(m_cur_slot)); + m_device.machine().save().save_item(&m_device, "view", m_device.subtag(m_name).c_str(), 0, NAME(m_cur_id)); m_device.machine().save().register_postload(save_prepost_delegate(NAME([this]() { m_handler_read->select_a(m_cur_id); m_handler_write->select_a(m_cur_id); }))); } @@ -898,70 +756,71 @@ template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Le view.make_subdispatch(key()); // Must be called after populate } -template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_range_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = m_view.m_space->make_mph(); + auto impl = m_view.m_space->make_mph(mph); r()->select_u(m_id); w()->select_u(m_id); - auto handler = new handler_entry_read_tap<Width, AddrShift>(m_view.m_space, *mph, name, tap); + auto handler = new handler_entry_read_tap<Width, AddrShift>(m_view.m_space, *impl, name, tap); r()->populate_passthrough(nstart, nend, nmirror, handler); handler->unref(); invalidate_caches(read_or_write::READ); - return mph; + return impl; } -template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_range_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = m_view.m_space->make_mph(); + auto impl = m_view.m_space->make_mph(mph); r()->select_u(m_id); w()->select_u(m_id); - auto handler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *mph, name, tap); + auto handler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *impl, name, tap); w()->populate_passthrough(nstart, nend, nmirror, handler); handler->unref(); invalidate_caches(read_or_write::WRITE); - return mph; + return impl; } -template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) +template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) { offs_t nstart, nend, nmask, nmirror; check_range_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if (!mph) - mph = m_view.m_space->make_mph(); + auto impl = m_view.m_space->make_mph(mph); r()->select_u(m_id); w()->select_u(m_id); - auto rhandler = new handler_entry_read_tap <Width, AddrShift>(m_view.m_space, *mph, name, tapr); + auto rhandler = new handler_entry_read_tap <Width, AddrShift>(m_view.m_space, *impl, name, tapr); r() ->populate_passthrough(nstart, nend, nmirror, rhandler); rhandler->unref(); - auto whandler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *mph, name, tapw); + auto whandler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *impl, name, tapw); w()->populate_passthrough(nstart, nend, nmirror, whandler); whandler->unref(); invalidate_caches(read_or_write::READWRITE); - return mph; + return impl; } template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth, u16 flags) { check_range_address("install_device_delegate", addrstart, addrend); + + r()->select_u(m_id); + w()->select_u(m_id); + address_map map(*m_view.m_space, addrstart, addrend, unitmask, cswidth, flags, m_view.m_device, delegate); map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift()); prepare_device_map(map); @@ -1008,6 +867,215 @@ template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Le invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); } + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_read_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_read_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_read_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); +} + + + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_write_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_write_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_write_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_readwrite_before_time(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_readwrite_before_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + +template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) +{ + auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device); + if (!cpu) + fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag()); + if (!cpu->cpu_is_interruptible()) + fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag()); + + VPRINTF("memory_view::install_readwrite_after_delay(%*x-%*x mirror=%*x ws=%s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, ws.name()); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + r()->select_u(m_id); + w()->select_u(m_id); + + auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + r()->populate_passthrough(nstart, nend, nmirror, hand_r); + auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws); + w()->populate_passthrough(nstart, nend, nmirror, hand_w); +} + + template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, memory_bank *rbank, memory_bank *wbank) { VPRINTF("memory_view::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index 8959c00da03..18b37734465 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -10,11 +10,15 @@ #include "emu.h" #include "emuopts.h" + #include "drivenum.h" -#include "softlist_dev.h" #include "hashfile.h" +#include "main.h" +#include "softlist_dev.h" +// lib/util #include "corestr.h" +#include "path.h" #include <stack> @@ -26,201 +30,202 @@ const options_entry emu_options::s_option_entries[] = { // unadorned options - only a single one supported at the moment - { OPTION_SYSTEMNAME, nullptr, OPTION_STRING, nullptr }, - { OPTION_SOFTWARENAME, nullptr, OPTION_STRING, nullptr }, + { OPTION_SYSTEMNAME, nullptr, core_options::option_type::STRING, nullptr }, + { OPTION_SOFTWARENAME, nullptr, core_options::option_type::STRING, nullptr }, // config options - { nullptr, nullptr, OPTION_HEADER, "CORE CONFIGURATION OPTIONS" }, - { OPTION_READCONFIG ";rc", "1", OPTION_BOOLEAN, "enable loading of configuration files" }, - { OPTION_WRITECONFIG ";wc", "0", OPTION_BOOLEAN, "write configuration to (driver).ini on exit" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE CONFIGURATION OPTIONS" }, + { OPTION_READCONFIG ";rc", "1", core_options::option_type::BOOLEAN, "enable loading of configuration files" }, + { OPTION_WRITECONFIG ";wc", "0", core_options::option_type::BOOLEAN, "write configuration to (driver).ini on exit" }, // search path options - { nullptr, nullptr, OPTION_HEADER, "CORE SEARCH PATH OPTIONS" }, - { OPTION_PLUGINDATAPATH, ".", OPTION_STRING, "path to base folder for plugin data (read/write)" }, - { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", OPTION_STRING, "path to ROM sets and hard disk images" }, - { OPTION_HASHPATH ";hash_directory;hash", "hash", OPTION_STRING, "path to software definition files" }, - { OPTION_SAMPLEPATH ";sp", "samples", OPTION_STRING, "path to audio sample sets" }, - { OPTION_ARTPATH, "artwork", OPTION_STRING, "path to artwork files" }, - { OPTION_CTRLRPATH, "ctrlr", OPTION_STRING, "path to controller definitions" }, - { OPTION_INIPATH, ".;ini;ini/presets", OPTION_STRING, "path to ini files" }, - { OPTION_FONTPATH, ".", OPTION_STRING, "path to font files" }, - { OPTION_CHEATPATH, "cheat", OPTION_STRING, "path to cheat files" }, - { OPTION_CROSSHAIRPATH, "crosshair", OPTION_STRING, "path to crosshair files" }, - { OPTION_PLUGINSPATH, "plugins", OPTION_STRING, "path to plugin files" }, - { OPTION_LANGUAGEPATH, "language", OPTION_STRING, "path to UI translation files" }, - { OPTION_SWPATH, "software", OPTION_STRING, "path to loose software" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE SEARCH PATH OPTIONS" }, + { OPTION_PLUGINDATAPATH, ".", core_options::option_type::PATH, "path to base folder for plugin data (read/write)" }, + { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", core_options::option_type::MULTIPATH, "path to ROM sets and hard disk images" }, + { OPTION_HASHPATH ";hash_directory;hash", "hash", core_options::option_type::MULTIPATH, "path to software definition files" }, + { OPTION_SAMPLEPATH ";sp", "samples", core_options::option_type::MULTIPATH, "path to audio sample sets" }, + { OPTION_ARTPATH, "artwork", core_options::option_type::MULTIPATH, "path to artwork files" }, + { OPTION_CTRLRPATH, "ctrlr", core_options::option_type::MULTIPATH, "path to controller definitions" }, + { OPTION_INIPATH, ".;ini;ini/presets", core_options::option_type::MULTIPATH, "path to ini files" }, + { OPTION_FONTPATH, ".", core_options::option_type::MULTIPATH, "path to font files" }, + { OPTION_CHEATPATH, "cheat", core_options::option_type::MULTIPATH, "path to cheat files" }, + { OPTION_CROSSHAIRPATH, "crosshair", core_options::option_type::MULTIPATH, "path to crosshair files" }, + { OPTION_PLUGINSPATH, "plugins", core_options::option_type::MULTIPATH, "path to plugin files" }, + { OPTION_LANGUAGEPATH, "language", core_options::option_type::MULTIPATH, "path to UI translation files" }, + { OPTION_SWPATH, "software", core_options::option_type::MULTIPATH, "path to loose software" }, // output directory options - { nullptr, nullptr, OPTION_HEADER, "CORE OUTPUT DIRECTORY OPTIONS" }, - { OPTION_CFG_DIRECTORY, "cfg", OPTION_STRING, "directory to save configurations" }, - { OPTION_NVRAM_DIRECTORY, "nvram", OPTION_STRING, "directory to save NVRAM contents" }, - { OPTION_INPUT_DIRECTORY, "inp", OPTION_STRING, "directory to save input device logs" }, - { OPTION_STATE_DIRECTORY, "sta", OPTION_STRING, "directory to save states" }, - { OPTION_SNAPSHOT_DIRECTORY, "snap", OPTION_STRING, "directory to save/load screenshots" }, - { OPTION_DIFF_DIRECTORY, "diff", OPTION_STRING, "directory to save hard drive image difference files" }, - { OPTION_COMMENT_DIRECTORY, "comments", OPTION_STRING, "directory to save debugger comments" }, - { OPTION_SHARE_DIRECTORY, "share", OPTION_STRING, "directory to share with emulated machines" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE OUTPUT DIRECTORY OPTIONS" }, + { OPTION_CFG_DIRECTORY, "cfg", core_options::option_type::PATH, "directory to save configurations" }, + { OPTION_NVRAM_DIRECTORY, "nvram", core_options::option_type::PATH, "directory to save NVRAM contents" }, + { OPTION_INPUT_DIRECTORY, "inp", core_options::option_type::PATH, "directory to save input device logs" }, + { OPTION_STATE_DIRECTORY, "sta", core_options::option_type::PATH, "directory to save states" }, + { OPTION_SNAPSHOT_DIRECTORY, "snap", core_options::option_type::PATH, "directory to save/load screenshots" }, + { OPTION_DIFF_DIRECTORY, "diff", core_options::option_type::PATH, "directory to save hard drive image difference files" }, + { OPTION_COMMENT_DIRECTORY, "comments", core_options::option_type::PATH, "directory to save debugger comments" }, + { OPTION_SHARE_DIRECTORY, "share", core_options::option_type::PATH, "directory to share with emulated machines" }, // state/playback options - { nullptr, nullptr, OPTION_HEADER, "CORE STATE/PLAYBACK OPTIONS" }, - { OPTION_STATE, nullptr, OPTION_STRING, "saved state to load" }, - { OPTION_AUTOSAVE, "0", OPTION_BOOLEAN, "automatically restore state on start and save on exit for supported systems" }, - { OPTION_REWIND, "0", OPTION_BOOLEAN, "enable rewind savestates" }, - { OPTION_REWIND_CAPACITY "(1-2048)", "100", OPTION_INTEGER, "rewind buffer size in megabytes" }, - { OPTION_PLAYBACK ";pb", nullptr, OPTION_STRING, "playback an input file" }, - { OPTION_RECORD ";rec", nullptr, OPTION_STRING, "record an input file" }, - { OPTION_EXIT_AFTER_PLAYBACK, "0", OPTION_BOOLEAN, "close the program at the end of playback" }, - - { OPTION_MNGWRITE, nullptr, OPTION_STRING, "optional filename to write a MNG movie of the current session" }, - { OPTION_AVIWRITE, nullptr, OPTION_STRING, "optional filename to write an AVI movie of the current session" }, - { OPTION_WAVWRITE, nullptr, OPTION_STRING, "optional filename to write a WAV file of the current session" }, - { OPTION_SNAPNAME, "%g/%i", OPTION_STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" }, - { OPTION_SNAPSIZE, "auto", OPTION_STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " }, - { OPTION_SNAPVIEW, "auto", OPTION_STRING, "snapshot/movie view - 'auto' for default, or 'native' for per-screen pixel-aspect views" }, - { OPTION_SNAPBILINEAR, "1", OPTION_BOOLEAN, "specify if the snapshot/movie should have bilinear filtering applied" }, - { OPTION_STATENAME, "%g", OPTION_STRING, "override of the default state subfolder naming; %g == gamename" }, - { OPTION_BURNIN, "0", OPTION_BOOLEAN, "create burn-in snapshots for each screen" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE STATE/PLAYBACK OPTIONS" }, + { OPTION_STATE, nullptr, core_options::option_type::STRING, "saved state to load" }, + { OPTION_AUTOSAVE, "0", core_options::option_type::BOOLEAN, "automatically restore state on start and save on exit for supported systems" }, + { OPTION_REWIND, "0", core_options::option_type::BOOLEAN, "enable rewind savestates" }, + { OPTION_REWIND_CAPACITY "(1-2048)", "100", core_options::option_type::INTEGER, "rewind buffer size in megabytes" }, + { OPTION_PLAYBACK ";pb", nullptr, core_options::option_type::STRING, "playback an input file" }, + { OPTION_RECORD ";rec", nullptr, core_options::option_type::STRING, "record an input file" }, + { OPTION_EXIT_AFTER_PLAYBACK, "0", core_options::option_type::BOOLEAN, "close the program at the end of playback" }, + + { OPTION_MNGWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a MNG movie of the current session" }, + { OPTION_AVIWRITE, nullptr, core_options::option_type::PATH, "optional filename to write an AVI movie of the current session" }, + { OPTION_WAVWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a WAV file of the current session" }, + { OPTION_SNAPNAME, "%g/%i", core_options::option_type::STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" }, + { OPTION_SNAPSIZE, "auto", core_options::option_type::STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " }, + { OPTION_SNAPVIEW, "auto", core_options::option_type::STRING, "snapshot/movie view - 'auto' for default, or 'native' for per-screen pixel-aspect views" }, + { OPTION_SNAPBILINEAR, "1", core_options::option_type::BOOLEAN, "specify if the snapshot/movie should have bilinear filtering applied" }, + { OPTION_STATENAME, "%g", core_options::option_type::STRING, "override of the default state subfolder naming; %g == gamename" }, + { OPTION_BURNIN, "0", core_options::option_type::BOOLEAN, "create burn-in snapshots for each screen" }, // performance options - { nullptr, nullptr, OPTION_HEADER, "CORE PERFORMANCE OPTIONS" }, - { OPTION_AUTOFRAMESKIP ";afs", "0", OPTION_BOOLEAN, "enable automatic frameskip adjustment to maintain emulation speed" }, - { OPTION_FRAMESKIP ";fs(0-10)", "0", OPTION_INTEGER, "set frameskip to fixed value, 0-10 (upper limit with autoframeskip)" }, - { OPTION_SECONDS_TO_RUN ";str", "0", OPTION_INTEGER, "number of emulated seconds to run before automatically exiting" }, - { OPTION_THROTTLE, "1", OPTION_BOOLEAN, "throttle emulation to keep system running in sync with real time" }, - { OPTION_SLEEP, "1", OPTION_BOOLEAN, "enable sleeping, which gives time back to other applications when idle" }, - { OPTION_SPEED "(0.01-100)", "1.0", OPTION_FLOAT, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" }, - { OPTION_REFRESHSPEED ";rs", "0", OPTION_BOOLEAN, "automatically adjust emulation speed to keep the emulated refresh rate slower than the host screen" }, - { OPTION_LOWLATENCY ";lolat", "0", OPTION_BOOLEAN, "draws new frame before throttling to reduce input latency" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE PERFORMANCE OPTIONS" }, + { OPTION_AUTOFRAMESKIP ";afs", "0", core_options::option_type::BOOLEAN, "enable automatic frameskip adjustment to maintain emulation speed" }, + { OPTION_FRAMESKIP ";fs(0-10)", "0", core_options::option_type::INTEGER, "set frameskip to fixed value, 0-10 (upper limit with autoframeskip)" }, + { OPTION_SECONDS_TO_RUN ";str", "0", core_options::option_type::INTEGER, "number of emulated seconds to run before automatically exiting" }, + { OPTION_THROTTLE, "1", core_options::option_type::BOOLEAN, "throttle emulation to keep system running in sync with real time" }, + { OPTION_SLEEP, "1", core_options::option_type::BOOLEAN, "enable sleeping, which gives time back to other applications when idle" }, + { OPTION_SPEED "(0.01-100)", "1.0", core_options::option_type::FLOAT, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" }, + { OPTION_REFRESHSPEED ";rs", "0", core_options::option_type::BOOLEAN, "automatically adjust emulation speed to keep the emulated refresh rate slower than the host screen" }, + { OPTION_LOWLATENCY ";lolat", "0", core_options::option_type::BOOLEAN, "draws new frame before throttling to reduce input latency" }, // render options - { nullptr, nullptr, OPTION_HEADER, "CORE RENDER OPTIONS" }, - { OPTION_KEEPASPECT ";ka", "1", OPTION_BOOLEAN, "maintain aspect ratio when scaling to fill output screen/window" }, - { OPTION_UNEVENSTRETCH ";ues", "1", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally or vertically" }, - { OPTION_UNEVENSTRETCHX ";uesx", "0", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally"}, - { OPTION_UNEVENSTRETCHY ";uesy", "0", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill otuput screen/window vertially"}, - { OPTION_AUTOSTRETCHXY ";asxy", "0", OPTION_BOOLEAN, "automatically apply -unevenstretchx/y based on source native orientation"}, - { OPTION_INTOVERSCAN ";ios", "0", OPTION_BOOLEAN, "allow overscan on integer scaled targets"}, - { OPTION_INTSCALEX ";sx", "0", OPTION_INTEGER, "set horizontal integer scale factor"}, - { OPTION_INTSCALEY ";sy", "0", OPTION_INTEGER, "set vertical integer scale factor"}, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE RENDER OPTIONS" }, + { OPTION_KEEPASPECT ";ka", "1", core_options::option_type::BOOLEAN, "maintain aspect ratio when scaling to fill output screen/window" }, + { OPTION_UNEVENSTRETCH ";ues", "1", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally or vertically" }, + { OPTION_UNEVENSTRETCHX ";uesx", "0", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally"}, + { OPTION_UNEVENSTRETCHY ";uesy", "0", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill otuput screen/window vertially"}, + { OPTION_AUTOSTRETCHXY ";asxy", "0", core_options::option_type::BOOLEAN, "automatically apply -unevenstretchx/y based on source native orientation"}, + { OPTION_INTOVERSCAN ";ios", "0", core_options::option_type::BOOLEAN, "allow overscan on integer scaled targets"}, + { OPTION_INTSCALEX ";sx", "0", core_options::option_type::INTEGER, "set horizontal integer scale factor"}, + { OPTION_INTSCALEY ";sy", "0", core_options::option_type::INTEGER, "set vertical integer scale factor"}, // rotation options - { nullptr, nullptr, OPTION_HEADER, "CORE ROTATION OPTIONS" }, - { OPTION_ROTATE, "1", OPTION_BOOLEAN, "rotate the game screen according to the game's orientation when needed" }, - { OPTION_ROR, "0", OPTION_BOOLEAN, "rotate screen clockwise 90 degrees" }, - { OPTION_ROL, "0", OPTION_BOOLEAN, "rotate screen counterclockwise 90 degrees" }, - { OPTION_AUTOROR, "0", OPTION_BOOLEAN, "automatically rotate screen clockwise 90 degrees if vertical" }, - { OPTION_AUTOROL, "0", OPTION_BOOLEAN, "automatically rotate screen counterclockwise 90 degrees if vertical" }, - { OPTION_FLIPX, "0", OPTION_BOOLEAN, "flip screen left-right" }, - { OPTION_FLIPY, "0", OPTION_BOOLEAN, "flip screen upside-down" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE ROTATION OPTIONS" }, + { OPTION_ROTATE, "1", core_options::option_type::BOOLEAN, "rotate the game screen according to the game's orientation when needed" }, + { OPTION_ROR, "0", core_options::option_type::BOOLEAN, "rotate screen clockwise 90 degrees" }, + { OPTION_ROL, "0", core_options::option_type::BOOLEAN, "rotate screen counterclockwise 90 degrees" }, + { OPTION_AUTOROR, "0", core_options::option_type::BOOLEAN, "automatically rotate screen clockwise 90 degrees if vertical" }, + { OPTION_AUTOROL, "0", core_options::option_type::BOOLEAN, "automatically rotate screen counterclockwise 90 degrees if vertical" }, + { OPTION_FLIPX, "0", core_options::option_type::BOOLEAN, "flip screen left-right" }, + { OPTION_FLIPY, "0", core_options::option_type::BOOLEAN, "flip screen upside-down" }, // artwork options - { nullptr, nullptr, OPTION_HEADER, "CORE ARTWORK OPTIONS" }, - { OPTION_ARTWORK_CROP ";artcrop", "0", OPTION_BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" }, - { OPTION_FALLBACK_ARTWORK, nullptr, OPTION_STRING, "fallback artwork if no external artwork or internal driver layout defined" }, - { OPTION_OVERRIDE_ARTWORK, nullptr, OPTION_STRING, "override artwork for external artwork and internal driver layout" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE ARTWORK OPTIONS" }, + { OPTION_ARTWORK_CROP ";artcrop", "0", core_options::option_type::BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" }, + { OPTION_FALLBACK_ARTWORK, nullptr, core_options::option_type::STRING, "fallback artwork if no external artwork or internal driver layout defined" }, + { OPTION_OVERRIDE_ARTWORK, nullptr, core_options::option_type::STRING, "override artwork for external artwork and internal driver layout" }, // screen options - { nullptr, nullptr, OPTION_HEADER, "CORE SCREEN OPTIONS" }, - { OPTION_BRIGHTNESS "(0.1-2.0)", "1.0", OPTION_FLOAT, "default game screen brightness correction" }, - { OPTION_CONTRAST "(0.1-2.0)", "1.0", OPTION_FLOAT, "default game screen contrast correction" }, - { OPTION_GAMMA "(0.1-3.0)", "1.0", OPTION_FLOAT, "default game screen gamma correction" }, - { OPTION_PAUSE_BRIGHTNESS "(0.0-1.0)", "0.65", OPTION_FLOAT, "amount to scale the screen brightness when paused" }, - { OPTION_EFFECT, "none", OPTION_STRING, "name of a PNG file to use for visual effects, or 'none'" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE SCREEN OPTIONS" }, + { OPTION_BRIGHTNESS "(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "default game screen brightness correction" }, + { OPTION_CONTRAST "(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "default game screen contrast correction" }, + { OPTION_GAMMA "(0.1-3.0)", "1.0", core_options::option_type::FLOAT, "default game screen gamma correction" }, + { OPTION_PAUSE_BRIGHTNESS "(0.0-1.0)", "0.65", core_options::option_type::FLOAT, "amount to scale the screen brightness when paused" }, + { OPTION_EFFECT, "none", core_options::option_type::STRING, "name of a PNG file to use for visual effects, or 'none'" }, // vector options - { nullptr, nullptr, OPTION_HEADER, "CORE VECTOR OPTIONS" }, - { OPTION_BEAM_WIDTH_MIN, "1.0", OPTION_FLOAT, "set vector beam width minimum" }, - { OPTION_BEAM_WIDTH_MAX, "1.0", OPTION_FLOAT, "set vector beam width maximum" }, - { OPTION_BEAM_DOT_SIZE, "1.0", OPTION_FLOAT, "set vector beam size for dots" }, - { OPTION_BEAM_INTENSITY_WEIGHT, "0", OPTION_FLOAT, "set vector beam intensity weight " }, - { OPTION_FLICKER, "0", OPTION_FLOAT, "set vector flicker effect" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE VECTOR OPTIONS" }, + { OPTION_BEAM_WIDTH_MIN, "1.0", core_options::option_type::FLOAT, "set vector beam width minimum" }, + { OPTION_BEAM_WIDTH_MAX, "1.0", core_options::option_type::FLOAT, "set vector beam width maximum" }, + { OPTION_BEAM_DOT_SIZE, "1.0", core_options::option_type::FLOAT, "set vector beam size for dots" }, + { OPTION_BEAM_INTENSITY_WEIGHT, "0", core_options::option_type::FLOAT, "set vector beam intensity weight " }, + { OPTION_FLICKER, "0", core_options::option_type::FLOAT, "set vector flicker effect" }, // sound options - { nullptr, nullptr, OPTION_HEADER, "CORE SOUND OPTIONS" }, - { OPTION_SAMPLERATE ";sr(1000-1000000)", "48000", OPTION_INTEGER, "set sound output sample rate" }, - { OPTION_SAMPLES, "1", OPTION_BOOLEAN, "enable the use of external samples if available" }, - { OPTION_VOLUME ";vol", "0", OPTION_INTEGER, "sound volume in decibels (-32 min, 0 max)" }, - { OPTION_COMPRESSOR, "1", OPTION_BOOLEAN, "enable compressor for sound" }, - { OPTION_SPEAKER_REPORT "(0-4)", "0", OPTION_INTEGER, "print report of speaker ouput maxima (0=none, or 1-4 for more detail)" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE SOUND OPTIONS" }, + { OPTION_SAMPLERATE ";sr(1000-1000000)", "48000", core_options::option_type::INTEGER, "set sound output sample rate" }, + { OPTION_SAMPLES, "1", core_options::option_type::BOOLEAN, "enable the use of external samples if available" }, + { OPTION_VOLUME ";vol", "0", core_options::option_type::INTEGER, "sound volume in decibels (-32 min, 0 max)" }, + { OPTION_COMPRESSOR, "1", core_options::option_type::BOOLEAN, "enable compressor for sound" }, + { OPTION_SPEAKER_REPORT "(0-4)", "0", core_options::option_type::INTEGER, "print report of speaker ouput maxima (0=none, or 1-4 for more detail)" }, // input options - { nullptr, nullptr, OPTION_HEADER, "CORE INPUT OPTIONS" }, - { OPTION_COIN_LOCKOUT ";coinlock", "1", OPTION_BOOLEAN, "ignore coin inputs if coin lockout output is active" }, - { OPTION_CTRLR, nullptr, OPTION_STRING, "preconfigure for specified controller" }, - { OPTION_MOUSE, "0", OPTION_BOOLEAN, "enable mouse input" }, - { OPTION_JOYSTICK ";joy", "1", OPTION_BOOLEAN, "enable joystick input" }, - { OPTION_LIGHTGUN ";gun", "0", OPTION_BOOLEAN, "enable lightgun input" }, - { OPTION_MULTIKEYBOARD ";multikey", "0", OPTION_BOOLEAN, "enable separate input from each keyboard device (if present)" }, - { OPTION_MULTIMOUSE, "0", OPTION_BOOLEAN, "enable separate input from each mouse device (if present)" }, - { OPTION_STEADYKEY ";steady", "0", OPTION_BOOLEAN, "enable steadykey support" }, - { OPTION_UI_ACTIVE, "0", OPTION_BOOLEAN, "enable user interface on top of emulated keyboard (if present)" }, - { OPTION_OFFSCREEN_RELOAD ";reload", "0", OPTION_BOOLEAN, "convert lightgun button 2 into offscreen reload" }, - { OPTION_JOYSTICK_MAP ";joymap", "auto", OPTION_STRING, "explicit joystick map, or auto to auto-select" }, - { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz(0.00-1)", "0.3", OPTION_FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" }, - { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat(0.00-1)", "0.85", OPTION_FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" }, - { OPTION_NATURAL_KEYBOARD ";nat", "0", OPTION_BOOLEAN, "specifies whether to use a natural keyboard or not" }, - { OPTION_JOYSTICK_CONTRADICTORY ";joy_contradictory","0", OPTION_BOOLEAN, "enable contradictory direction digital joystick input at the same time" }, - { OPTION_COIN_IMPULSE, "0", OPTION_INTEGER, "set coin impulse time (n<0 disable impulse, n==0 obey driver, 0<n set time n)" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE INPUT OPTIONS" }, + { OPTION_COIN_LOCKOUT ";coinlock", "1", core_options::option_type::BOOLEAN, "ignore coin inputs if coin lockout output is active" }, + { OPTION_CTRLR, nullptr, core_options::option_type::STRING, "preconfigure for specified controller" }, + { OPTION_MOUSE, "0", core_options::option_type::BOOLEAN, "enable mouse input" }, + { OPTION_JOYSTICK ";joy", "1", core_options::option_type::BOOLEAN, "enable joystick input" }, + { OPTION_LIGHTGUN ";gun", "0", core_options::option_type::BOOLEAN, "enable lightgun input" }, + { OPTION_MULTIKEYBOARD ";multikey", "0", core_options::option_type::BOOLEAN, "enable separate input from each keyboard device (if present)" }, + { OPTION_MULTIMOUSE, "0", core_options::option_type::BOOLEAN, "enable separate input from each mouse device (if present)" }, + { OPTION_STEADYKEY ";steady", "0", core_options::option_type::BOOLEAN, "enable steadykey support" }, + { OPTION_UI_ACTIVE, "0", core_options::option_type::BOOLEAN, "enable user interface on top of emulated keyboard (if present)" }, + { OPTION_OFFSCREEN_RELOAD ";reload", "0", core_options::option_type::BOOLEAN, "convert lightgun button 2 into offscreen reload" }, + { OPTION_JOYSTICK_MAP ";joymap", "auto", core_options::option_type::STRING, "explicit joystick map, or auto to auto-select" }, + { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz(0.00-1)", "0.15", core_options::option_type::FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" }, + { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat(0.00-1)", "0.85", core_options::option_type::FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" }, + { OPTION_JOYSTICK_THRESHOLD ";joy_threshold;jthresh(0.00-1)", "0.3", core_options::option_type::FLOAT, "threshold for joystick to be considered active as a switch (0.0 center, 1.0 end)" }, + { OPTION_NATURAL_KEYBOARD ";nat", "0", core_options::option_type::BOOLEAN, "specifies whether to use a natural keyboard or not" }, + { OPTION_JOYSTICK_CONTRADICTORY ";joy_contradictory","0", core_options::option_type::BOOLEAN, "enable contradictory direction digital joystick input at the same time" }, + { OPTION_COIN_IMPULSE, "0", core_options::option_type::INTEGER, "set coin impulse time (n<0 disable impulse, n==0 obey driver, 0<n set time n)" }, // input autoenable options - { nullptr, nullptr, OPTION_HEADER, "CORE INPUT AUTOMATIC ENABLE OPTIONS" }, - { OPTION_PADDLE_DEVICE ";paddle", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a paddle control is present" }, - { OPTION_ADSTICK_DEVICE ";adstick", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if an analog joystick control is present" }, - { OPTION_PEDAL_DEVICE ";pedal", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a pedal control is present" }, - { OPTION_DIAL_DEVICE ";dial", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a dial control is present" }, - { OPTION_TRACKBALL_DEVICE ";trackball", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a trackball control is present" }, - { OPTION_LIGHTGUN_DEVICE, "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a lightgun control is present" }, - { OPTION_POSITIONAL_DEVICE, "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a positional control is present" }, - { OPTION_MOUSE_DEVICE, "mouse", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a mouse control is present" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE INPUT AUTOMATIC ENABLE OPTIONS" }, + { OPTION_PADDLE_DEVICE ";paddle", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a paddle control is present" }, + { OPTION_ADSTICK_DEVICE ";adstick", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if an analog joystick control is present" }, + { OPTION_PEDAL_DEVICE ";pedal", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a pedal control is present" }, + { OPTION_DIAL_DEVICE ";dial", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a dial control is present" }, + { OPTION_TRACKBALL_DEVICE ";trackball", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a trackball control is present" }, + { OPTION_LIGHTGUN_DEVICE, "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a lightgun control is present" }, + { OPTION_POSITIONAL_DEVICE, "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a positional control is present" }, + { OPTION_MOUSE_DEVICE, "mouse", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a mouse control is present" }, // debugging options - { nullptr, nullptr, OPTION_HEADER, "CORE DEBUGGING OPTIONS" }, - { OPTION_VERBOSE ";v", "0", OPTION_BOOLEAN, "display additional diagnostic information" }, - { OPTION_LOG, "0", OPTION_BOOLEAN, "generate an error.log file" }, - { OPTION_OSLOG, "0", OPTION_BOOLEAN, "output error.log data to system diagnostic output (debugger or standard error)" }, - { OPTION_DEBUG ";d", "0", OPTION_BOOLEAN, "enable/disable debugger" }, - { OPTION_UPDATEINPAUSE, "0", OPTION_BOOLEAN, "keep calling video updates while in pause" }, - { OPTION_DEBUGSCRIPT, nullptr, OPTION_STRING, "script for debugger" }, - { OPTION_DEBUGLOG, "0", OPTION_BOOLEAN, "write debug console output to debug.log" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE DEBUGGING OPTIONS" }, + { OPTION_VERBOSE ";v", "0", core_options::option_type::BOOLEAN, "display additional diagnostic information" }, + { OPTION_LOG, "0", core_options::option_type::BOOLEAN, "generate an error.log file" }, + { OPTION_OSLOG, "0", core_options::option_type::BOOLEAN, "output error.log data to system diagnostic output (debugger or standard error)" }, + { OPTION_DEBUG ";d", "0", core_options::option_type::BOOLEAN, "enable/disable debugger" }, + { OPTION_UPDATEINPAUSE, "0", core_options::option_type::BOOLEAN, "keep calling video updates while in pause" }, + { OPTION_DEBUGSCRIPT, nullptr, core_options::option_type::PATH, "script for debugger" }, + { OPTION_DEBUGLOG, "0", core_options::option_type::BOOLEAN, "write debug console output to debug.log" }, // comm options - { nullptr, nullptr, OPTION_HEADER, "CORE COMM OPTIONS" }, - { OPTION_COMM_LOCAL_HOST, "0.0.0.0", OPTION_STRING, "local address to bind to" }, - { OPTION_COMM_LOCAL_PORT, "15112", OPTION_STRING, "local port to bind to" }, - { OPTION_COMM_REMOTE_HOST, "127.0.0.1", OPTION_STRING, "remote address to connect to" }, - { OPTION_COMM_REMOTE_PORT, "15112", OPTION_STRING, "remote port to connect to" }, - { OPTION_COMM_FRAME_SYNC, "0", OPTION_BOOLEAN, "sync frames" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE COMM OPTIONS" }, + { OPTION_COMM_LOCAL_HOST, "0.0.0.0", core_options::option_type::STRING, "local address to bind to" }, + { OPTION_COMM_LOCAL_PORT, "15112", core_options::option_type::STRING, "local port to bind to" }, + { OPTION_COMM_REMOTE_HOST, "127.0.0.1", core_options::option_type::STRING, "remote address to connect to" }, + { OPTION_COMM_REMOTE_PORT, "15112", core_options::option_type::STRING, "remote port to connect to" }, + { OPTION_COMM_FRAME_SYNC, "0", core_options::option_type::BOOLEAN, "sync frames" }, // misc options - { nullptr, nullptr, OPTION_HEADER, "CORE MISC OPTIONS" }, - { OPTION_DRC, "1", OPTION_BOOLEAN, "enable DRC CPU core if available" }, - { OPTION_DRC_USE_C, "0", OPTION_BOOLEAN, "force DRC to use C backend" }, - { OPTION_DRC_LOG_UML, "0", OPTION_BOOLEAN, "write DRC UML disassembly log" }, - { OPTION_DRC_LOG_NATIVE, "0", OPTION_BOOLEAN, "write DRC native disassembly log" }, - { OPTION_BIOS, nullptr, OPTION_STRING, "select the system BIOS to use" }, - { OPTION_CHEAT ";c", "0", OPTION_BOOLEAN, "enable cheat subsystem" }, - { OPTION_SKIP_GAMEINFO, "0", OPTION_BOOLEAN, "skip displaying the system information screen at startup" }, - { OPTION_UI_FONT, "default", OPTION_STRING, "specify a font to use" }, - { OPTION_UI, "cabinet", OPTION_STRING, "type of UI (simple|cabinet)" }, - { OPTION_RAMSIZE ";ram", nullptr, OPTION_STRING, "size of RAM (if supported by driver)" }, - { OPTION_CONFIRM_QUIT, "0", OPTION_BOOLEAN, "ask for confirmation before exiting" }, - { OPTION_UI_MOUSE, "1", OPTION_BOOLEAN, "display UI mouse cursor" }, - { OPTION_LANGUAGE ";lang", "", OPTION_STRING, "set UI display language" }, - { OPTION_NVRAM_SAVE ";nvwrite", "1", OPTION_BOOLEAN, "save NVRAM data on exit" }, - - { nullptr, nullptr, OPTION_HEADER, "SCRIPTING OPTIONS" }, - { OPTION_AUTOBOOT_COMMAND ";ab", nullptr, OPTION_STRING, "command to execute after machine boot" }, - { OPTION_AUTOBOOT_DELAY, "0", OPTION_INTEGER, "delay before executing autoboot command (seconds)" }, - { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, OPTION_STRING, "Lua script to execute after machine boot" }, - { OPTION_CONSOLE, "0", OPTION_BOOLEAN, "enable emulator Lua console" }, - { OPTION_PLUGINS, "1", OPTION_BOOLEAN, "enable Lua plugin support" }, - { OPTION_PLUGIN, nullptr, OPTION_STRING, "list of plugins to enable" }, - { OPTION_NO_PLUGIN, nullptr, OPTION_STRING, "list of plugins to disable" }, - - { nullptr, nullptr, OPTION_HEADER, "HTTP SERVER OPTIONS" }, - { OPTION_HTTP, "0", OPTION_BOOLEAN, "enable HTTP server" }, - { OPTION_HTTP_PORT, "8080", OPTION_INTEGER, "HTTP server port" }, - { OPTION_HTTP_ROOT, "web", OPTION_STRING, "HTTP server document root" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CORE MISC OPTIONS" }, + { OPTION_DRC, "1", core_options::option_type::BOOLEAN, "enable DRC CPU core if available" }, + { OPTION_DRC_USE_C, "0", core_options::option_type::BOOLEAN, "force DRC to use C backend" }, + { OPTION_DRC_LOG_UML, "0", core_options::option_type::BOOLEAN, "write DRC UML disassembly log" }, + { OPTION_DRC_LOG_NATIVE, "0", core_options::option_type::BOOLEAN, "write DRC native disassembly log" }, + { OPTION_BIOS, nullptr, core_options::option_type::STRING, "select the system BIOS to use" }, + { OPTION_CHEAT ";c", "0", core_options::option_type::BOOLEAN, "enable cheat subsystem" }, + { OPTION_SKIP_GAMEINFO, "0", core_options::option_type::BOOLEAN, "skip displaying the system information screen at startup" }, + { OPTION_UI_FONT, "default", core_options::option_type::STRING, "specify a font to use" }, + { OPTION_UI, "cabinet", core_options::option_type::STRING, "type of UI (simple|cabinet)" }, + { OPTION_RAMSIZE ";ram", nullptr, core_options::option_type::STRING, "size of RAM (if supported by driver)" }, + { OPTION_CONFIRM_QUIT, "0", core_options::option_type::BOOLEAN, "ask for confirmation before exiting" }, + { OPTION_UI_MOUSE, "1", core_options::option_type::BOOLEAN, "display UI mouse cursor" }, + { OPTION_LANGUAGE ";lang", "", core_options::option_type::STRING, "set UI display language" }, + { OPTION_NVRAM_SAVE ";nvwrite", "1", core_options::option_type::BOOLEAN, "save NVRAM data on exit" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "SCRIPTING OPTIONS" }, + { OPTION_AUTOBOOT_COMMAND ";ab", nullptr, core_options::option_type::STRING, "command to execute after machine boot" }, + { OPTION_AUTOBOOT_DELAY, "0", core_options::option_type::INTEGER, "delay before executing autoboot command (seconds)" }, + { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, core_options::option_type::PATH, "Lua script to execute after machine boot" }, + { OPTION_CONSOLE, "0", core_options::option_type::BOOLEAN, "enable emulator Lua console" }, + { OPTION_PLUGINS, "1", core_options::option_type::BOOLEAN, "enable Lua plugin support" }, + { OPTION_PLUGIN, nullptr, core_options::option_type::STRING, "list of plugins to enable" }, + { OPTION_NO_PLUGIN, nullptr, core_options::option_type::STRING, "list of plugins to disable" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "HTTP SERVER OPTIONS" }, + { OPTION_HTTP, "0", core_options::option_type::BOOLEAN, "enable HTTP server" }, + { OPTION_HTTP_PORT, "8080", core_options::option_type::INTEGER, "HTTP server port" }, + { OPTION_HTTP_ROOT, "web", core_options::option_type::PATH, "HTTP server document root" }, { nullptr } }; @@ -254,7 +259,7 @@ namespace } protected: - virtual void internal_set_value(std::string &&newvalue) override + virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override { m_host.set_system_name(std::move(newvalue)); } @@ -274,7 +279,7 @@ namespace } protected: - virtual void internal_set_value(std::string &&newvalue) override + virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override { m_host.set_software(std::move(newvalue)); } @@ -312,7 +317,7 @@ namespace } protected: - virtual void internal_set_value(std::string &&newvalue) override + virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override { m_host.specify(std::move(newvalue), false); } @@ -338,7 +343,7 @@ namespace } protected: - virtual void internal_set_value(std::string &&newvalue) override + virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override { m_host.specify(std::move(newvalue), false); } @@ -528,7 +533,7 @@ void emu_options::update_slot_and_image_options() if (add_and_remove_slot_options()) changed = true; - // second, we perform an analgous operation with m_image_options + // second, we perform an analogous operation with m_image_options if (add_and_remove_image_options()) changed = true; @@ -614,8 +619,8 @@ bool emu_options::add_and_remove_slot_options() //------------------------------------------------- -// add_and_remove_slot_options - add any missing -// and/or purge extraneous slot options +// add_and_remove_image_options - add any missing +// and/or purge extraneous image options //------------------------------------------------- bool emu_options::add_and_remove_image_options() @@ -718,7 +723,7 @@ bool emu_options::add_and_remove_image_options() //------------------------------------------------- // reevaluate_default_card_software - based on recent -// changes in what images are mounted, give drivers +// changes in what images are mounted, give devices // a chance to specify new default slot options //------------------------------------------------- @@ -757,6 +762,16 @@ void emu_options::reevaluate_default_card_software() std::string default_card_software = get_default_card_software(slot); if (slot_opt.default_card_software() != default_card_software) { + // HACK: prevent option values set from "XXX_default" in software list entries + // from getting cleared out, using crude heuristic to distinguish these from + // values representing cartridge types and such + if (default_card_software.empty()) + { + auto *opt = slot.option(slot_opt.default_card_software().c_str()); + if (opt && opt->selectable()) + continue; + } + slot_opt.set_default_card_software(std::move(default_card_software)); // calling set_default_card_software() can cause a cascade of slot/image @@ -845,7 +860,8 @@ void emu_options::set_software(std::string &&new_software) } // keep any deferred options for the next round - softlist_opts = std::move(deferred_opts); + softlist_opts.slot = std::move(deferred_opts.slot); + softlist_opts.image = std::move(deferred_opts.image); // do we have any pending options after failing to distribute any? size_t after_size = softlist_opts.slot.size() + softlist_opts.image.size(); @@ -853,6 +869,14 @@ void emu_options::set_software(std::string &&new_software) throw options_error_exception("Could not assign software option"); } + // distribute slot option defaults + for (auto &slot_opt : softlist_opts.slot_defaults) + { + auto iter = m_slot_options.find(slot_opt.first); + if (iter != m_slot_options.end()) + iter->second.set_default_card_software(std::move(slot_opt.second)); + } + // we've succeeded; update the set name m_software_name = std::move(new_software); } @@ -922,9 +946,12 @@ emu_options::software_options emu_options::evaluate_initial_softlist_options(con // we need to find a mountable image slot, but we need to ensure it is a slot // for which we have not already distributed a part to device_image_interface *image = software_list_device::find_mountable_image( - config, - swpart, - [&results](const device_image_interface &candidate) { return results.image.count(candidate.instance_name()) == 0; }); + config, + swpart, + [&results] (const device_image_interface &candidate) + { + return results.image.count(candidate.instance_name()) == 0; + }); // did we find a slot to put this part into? if (image != nullptr) @@ -957,7 +984,15 @@ emu_options::software_options emu_options::evaluate_initial_softlist_options(con && fi.name().compare(fi.name().size() - default_suffix.size(), default_suffix.size(), default_suffix) == 0) { std::string slot_name = fi.name().substr(0, fi.name().size() - default_suffix.size()); - results.slot[slot_name] = fi.value(); + + // only add defaults if they exist in this configuration + device_t *device = config.root_device().subdevice(slot_name.c_str()); + if (device) + { + device_slot_interface *intf; + if (device->interface(intf) && intf->option(fi.value().c_str())) + results.slot_defaults[slot_name] = fi.value(); + } } } } @@ -1050,8 +1085,9 @@ image_option &emu_options::image_option(const std::string &device_name) void emu_options::command_argument_processed() { // some command line arguments require that the system name be set, so we can get slot options - if (command_arguments().size() == 1 && !core_iswildstr(command_arguments()[0].c_str()) && - (command() == "listdevices" || (command() == "listslots") || (command() == "listmedia") || (command() == "listsoftware"))) + // FIXME: having this here is a massively leaky abstraction + if (command_arguments().size() == 1 && !core_iswildstr(command_arguments()[0]) && + (command() == "listdevices" || (command() == "listslots") || (command() == "listbios") || (command() == "listmedia") || (command() == "listsoftware"))) { set_system_name(command_arguments()[0]); } @@ -1220,8 +1256,8 @@ void slot_option::set_bios(std::string &&text) { if (!m_specified) { - m_specified = true; m_specified_value = value(); + m_specified = true; } m_specified_bios = std::move(text); } diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h index 296e2e46590..0a1b1dcf413 100644 --- a/src/emu/emuopts.h +++ b/src/emu/emuopts.h @@ -136,6 +136,7 @@ #define OPTION_JOYSTICK_MAP "joystick_map" #define OPTION_JOYSTICK_DEADZONE "joystick_deadzone" #define OPTION_JOYSTICK_SATURATION "joystick_saturation" +#define OPTION_JOYSTICK_THRESHOLD "joystick_threshold" #define OPTION_NATURAL_KEYBOARD "natural" #define OPTION_JOYSTICK_CONTRADICTORY "joystick_contradictory" #define OPTION_COIN_IMPULSE "coin_impulse" @@ -426,6 +427,7 @@ public: const char *joystick_map() const { return value(OPTION_JOYSTICK_MAP); } float joystick_deadzone() const { return float_value(OPTION_JOYSTICK_DEADZONE); } float joystick_saturation() const { return float_value(OPTION_JOYSTICK_SATURATION); } + float joystick_threshold() const { return float_value(OPTION_JOYSTICK_THRESHOLD); } bool steadykey() const { return bool_value(OPTION_STEADYKEY); } bool ui_active() const { return bool_value(OPTION_UI_ACTIVE); } bool offscreen_reload() const { return bool_value(OPTION_OFFSCREEN_RELOAD); } @@ -502,6 +504,7 @@ private: struct software_options { std::unordered_map<std::string, std::string> slot; + std::unordered_map<std::string, std::string> slot_defaults; std::unordered_map<std::string, std::string> image; }; diff --git a/src/emu/emupal.h b/src/emu/emupal.h index 73ee3809e90..cb4884a72fb 100644 --- a/src/emu/emupal.h +++ b/src/emu/emupal.h @@ -373,10 +373,10 @@ protected: virtual void device_start() override; // device_palette_interface overrides - virtual u32 palette_entries() const override { return m_entries; } - virtual u32 palette_indirect_entries() const override { return m_indirect_entries; } - virtual bool palette_shadows_enabled() const override { return m_enable_shadows; } - virtual bool palette_hilights_enabled() const override { return m_enable_hilights; } + virtual u32 palette_entries() const noexcept override { return m_entries; } + virtual u32 palette_indirect_entries() const noexcept override { return m_indirect_entries; } + virtual bool palette_shadows_enabled() const noexcept override { return m_enable_shadows; } + virtual bool palette_hilights_enabled() const noexcept override { return m_enable_hilights; } // generic palette init routines void palette_init_all_black(palette_device &palette); diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp index 6d5d6b8a806..c0341b93368 100644 --- a/src/emu/fileio.cpp +++ b/src/emu/fileio.cpp @@ -14,6 +14,8 @@ #include "util/path.h" #include "util/unzip.h" +#include <tuple> + //#define VERBOSE 1 #define LOG_OUTPUT_FUNC osd_printf_verbose #include "logmacro.h" @@ -107,7 +109,7 @@ path_iterator &path_iterator::operator=(path_iterator const &that) // multipath sequence //------------------------------------------------- -bool path_iterator::next(std::string &buffer, const char *name) +bool path_iterator::next(std::string &buffer) { // if none left, return false to indicate we are done if (!m_is_first && (m_searchpath.cend() == m_current)) @@ -120,10 +122,6 @@ bool path_iterator::next(std::string &buffer, const char *name) if (m_searchpath.cend() != m_current) ++m_current; - // append the name if we have one - if (name) - util::path_append(buffer, name); - // bump the index and return true m_is_first = false; return true; @@ -160,9 +158,13 @@ const osd::directory::entry *file_enumerator::next(const char *subdir) while (!m_curdir) { // if we fail to get anything more, we're done - if (!m_iterator.next(m_pathbuffer, subdir)) + if (!m_iterator.next(m_pathbuffer)) return nullptr; + // append the subdir if we have one + if (subdir) + util::path_append(m_pathbuffer, subdir); + // open the path m_curdir = osd::directory::open(m_pathbuffer); } @@ -259,7 +261,7 @@ util::hash_collection &emu_file::hashes(std::string_view types) // determine which hashes we need std::string needed; for (char scan : types) - if (already_have.find_first_of(scan) == -1) + if (already_have.find_first_of(scan) == std::string::npos) needed.push_back(scan); // if we need nothing, skip it @@ -279,15 +281,14 @@ util::hash_collection &emu_file::hashes(std::string_view types) return m_hashes; } - // read the data if we can - const u8 *filedata = (const u8 *)m_file->buffer(); - if (filedata == nullptr) + std::uint64_t length; + if (m_file->length(length)) return m_hashes; - // compute the hash - std::uint64_t length; - if (!m_file->length(length)) - m_hashes.compute(filedata, length, needed.c_str()); + // hash the data + std::size_t actual; + (void)m_hashes.compute(*m_file, 0U, length, actual, needed.c_str()); // FIXME: need better interface to report errors + return m_hashes; } @@ -532,9 +533,10 @@ u32 emu_file::read(void *buffer, u32 length) return 0; // read the data if we can + std::error_condition err; size_t actual = 0; if (m_file) - m_file->read(buffer, length, actual); + std::tie(err, actual) = util::read(*m_file, buffer, length); return actual; } @@ -602,9 +604,10 @@ u32 emu_file::write(const void *buffer, u32 length) { // FIXME: need better interface to report errors // write the data if we can + std::error_condition err; size_t actual = 0; if (m_file) - m_file->write(buffer, length, actual); + std::tie(err, actual) = util::write(*m_file, buffer, length); return actual; } @@ -628,7 +631,7 @@ int emu_file::puts(std::string_view s) // vfprintf - vfprintf to a text file //------------------------------------------------- -int emu_file::vprintf(util::format_argument_pack<std::ostream> const &args) +int emu_file::vprintf(util::format_argument_pack<char> const &args) { // write the data if we can return m_file ? m_file->vprintf(args) : 0; @@ -805,7 +808,7 @@ std::error_condition emu_file::load_zipped_file() m_zipdata.resize(m_ziplength); // read the data into our buffer and return - auto const ziperr = m_zipfile->decompress(&m_zipdata[0], m_zipdata.size()); + auto const ziperr = m_zipfile->decompress(m_zipdata.data(), m_zipdata.size()); if (ziperr) { m_zipdata.clear(); @@ -813,7 +816,7 @@ std::error_condition emu_file::load_zipped_file() } // convert to RAM file - std::error_condition const filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file); + std::error_condition const filerr = util::core_file::open_ram(m_zipdata.data(), m_zipdata.size(), m_openflags, m_file); if (filerr) { m_zipdata.clear(); diff --git a/src/emu/fileio.h b/src/emu/fileio.h index 91aedad173e..225cebd0a81 100644 --- a/src/emu/fileio.h +++ b/src/emu/fileio.h @@ -61,7 +61,7 @@ public: path_iterator &operator=(path_iterator const &that); // main interface - bool next(std::string &buffer, const char *name = nullptr); + bool next(std::string &buffer); void reset(); private: @@ -182,7 +182,7 @@ public: // writing u32 write(const void *buffer, u32 length); int puts(std::string_view s); - int vprintf(util::format_argument_pack<std::ostream> const &args); + int vprintf(util::format_argument_pack<char> const &args); template <typename Format, typename... Params> int printf(Format &&fmt, Params &&...args) { return vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)); diff --git a/src/emu/gamedrv.h b/src/emu/gamedrv.h index a1cb8a40155..6ab934bc53f 100644 --- a/src/emu/gamedrv.h +++ b/src/emu/gamedrv.h @@ -30,44 +30,31 @@ struct machine_flags { enum type : u32 { - MASK_ORIENTATION = 0x00000007, - MASK_TYPE = 0x00000038, + MASK_ORIENTATION = 0x0000'0007, - FLIP_X = 0x00000001, - FLIP_Y = 0x00000002, - SWAP_XY = 0x00000004, - ROT0 = 0x00000000, + FLIP_X = 0x0000'0001, + FLIP_Y = 0x0000'0002, + SWAP_XY = 0x0000'0004, + ROT0 = 0x0000'0000, ROT90 = FLIP_X | SWAP_XY, ROT180 = FLIP_X | FLIP_Y, ROT270 = FLIP_Y | SWAP_XY, - TYPE_ARCADE = 0x00000008, // coin-operated machine for public use - TYPE_CONSOLE = 0x00000010, // console system - TYPE_COMPUTER = 0x00000018, // any kind of computer including home computers, minis, calculators, ... - TYPE_OTHER = 0x00000038, // any other emulated system (e.g. clock, satellite receiver, ...) - - NOT_WORKING = 0x00000040, - SUPPORTS_SAVE = 0x00000080, // system supports save states - NO_COCKTAIL = 0x00000100, // screen flip support is missing - IS_BIOS_ROOT = 0x00000200, // this driver entry is a BIOS root - REQUIRES_ARTWORK = 0x00000400, // requires external artwork for key game elements - CLICKABLE_ARTWORK = 0x00000800, // artwork is clickable and requires mouse cursor - UNOFFICIAL = 0x00001000, // unofficial hardware modification - NO_SOUND_HW = 0x00002000, // system has no sound output - MECHANICAL = 0x00004000, // contains mechanical parts (pinball, redemption games, ...) - IS_INCOMPLETE = 0x00008000 // official system with blatantly incomplete hardware/software + NOT_WORKING = 0x0000'0040, + SUPPORTS_SAVE = 0x0000'0080, // system supports save states + NO_COCKTAIL = 0x0000'0100, // screen flip support is missing + IS_BIOS_ROOT = 0x0000'0200, // this driver entry is a BIOS root + REQUIRES_ARTWORK = 0x0000'0400, // requires external artwork for key game elements + UNOFFICIAL = 0x0000'0800, // unofficial hardware modification + NO_SOUND_HW = 0x0000'1000, // system has no sound output + MECHANICAL = 0x0000'2000, // contains mechanical parts (pinball, redemption games, ...) + IS_INCOMPLETE = 0x0000'4000 // official system with blatantly incomplete hardware/software }; }; DECLARE_ENUM_BITWISE_OPERATORS(machine_flags::type); -constexpr u64 MACHINE_TYPE_ARCADE = machine_flags::TYPE_ARCADE; -constexpr u64 MACHINE_TYPE_CONSOLE = machine_flags::TYPE_CONSOLE; -constexpr u64 MACHINE_TYPE_COMPUTER = machine_flags::TYPE_COMPUTER; -constexpr u64 MACHINE_TYPE_OTHER = machine_flags::TYPE_OTHER; - - /// \addtogroup machinedef /// \{ /// \name System emulation status constants @@ -83,7 +70,6 @@ constexpr u64 MACHINE_SUPPORTS_SAVE = machine_flags::SUPPORTS_SAVE; constexpr u64 MACHINE_NO_COCKTAIL = machine_flags::NO_COCKTAIL; ///< The system supports screen flipping for use in a cocktail cabinet, but this feature is not properly emulated constexpr u64 MACHINE_IS_BIOS_ROOT = machine_flags::IS_BIOS_ROOT; ///< The system represents an empty system board of some kind - clones are treated as separate systems rather than variants constexpr u64 MACHINE_REQUIRES_ARTWORK = machine_flags::REQUIRES_ARTWORK; ///< The system requires external artwork for key functionality -constexpr u64 MACHINE_CLICKABLE_ARTWORK = machine_flags::CLICKABLE_ARTWORK; ///< Enables pointer display for the system to facilitate using clickable artwork constexpr u64 MACHINE_UNOFFICIAL = machine_flags::UNOFFICIAL; ///< The system represents an after-market or end-user modification to a system constexpr u64 MACHINE_NO_SOUND_HW = machine_flags::NO_SOUND_HW; ///< The system has no sound output capability constexpr u64 MACHINE_MECHANICAL = machine_flags::MECHANICAL; ///< The system depends on mechanical features for key functionality @@ -204,11 +190,9 @@ driver_device_creator< \ /// \addtogroup machinedef /// \{ -/// \brief Define a "game" system +/// \brief Define a system /// -/// Use this macro to define most systems intended for public use, -/// including arcade games, gambling machines, vending machines, and -/// information kiosks. Muse be used in the global namespace. +/// Must be used in the global namespace. /// /// Creates an appropriately named and populated #game_driver structure /// describing the system. @@ -252,7 +236,7 @@ driver_device_creator< \ /// unemulated and imperfectly emulated feature flags that apply to /// all systems implemented using the class in the class itself to /// avoid repetition. -/// \sa GAMEL CONS COMP SYST +/// \sa GAMEL SYST #define GAME(YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR, COMPANY, FULLNAME, FLAGS) \ GAME_DRIVER_TRAITS(NAME, FULLNAME) \ extern game_driver const GAME_NAME(NAME) \ @@ -267,18 +251,18 @@ extern game_driver const GAME_NAME(NAME) \ ROM_NAME(NAME), \ nullptr, \ nullptr, \ - machine_flags::type(u32((MONITOR) | (FLAGS) | MACHINE_TYPE_ARCADE)),\ + machine_flags::type(u32((MONITOR) | (FLAGS))), \ #NAME \ }; -/// \brief Define a "game" system with an additional internal layout +/// \brief Define a system with an additional internal layout /// /// Equivalent to the #GAME macro, but with the additional ability to -/// supply system-specific internal artwork layout data. Views from the +/// supply a system-specific internal artwork layout. Views from the /// system-specific layout are available in addition to any views from -/// layout data specified in the machine configuration. Must be used in -/// the global namespace. +/// layouts specified in the machine configuration. Must be used in the +/// global namespace. /// /// Creates an appropriately named and populated #game_driver structure /// describing the system. @@ -324,7 +308,7 @@ extern game_driver const GAME_NAME(NAME) \ /// avoid repetition. /// \param LAYOUT An #internal_layout structure providing additional /// internal artwork for the system. -/// \sa GAME CONS COMP SYST +/// \sa GAME SYST #define GAMEL(YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR, COMPANY, FULLNAME, FLAGS, LAYOUT) \ GAME_DRIVER_TRAITS(NAME, FULLNAME) \ extern game_driver const GAME_NAME(NAME) \ @@ -339,15 +323,15 @@ extern game_driver const GAME_NAME(NAME) \ ROM_NAME(NAME), \ nullptr, \ &LAYOUT, \ - machine_flags::type(u32((MONITOR) | (FLAGS) | MACHINE_TYPE_ARCADE)),\ + machine_flags::type(u32((MONITOR) | (FLAGS))), \ #NAME \ }; -/// \brief Define a "console" system +/// \brief Define a system with software compatibility grouping /// -/// Use this macro to define appliance-like entertainment systems -/// designed for domestic use. Must be used in the global namespace. +/// Equivalent to the #GAME macro, but allows software-compatible +/// systems to be grouped. /// /// Creates an appropriately named and populated #game_driver structure /// describing the system. @@ -390,156 +374,31 @@ extern game_driver const GAME_NAME(NAME) \ /// unemulated and imperfectly emulated feature flags that apply to /// all systems implemented using the class in the class itself to /// avoid repetition. Screen orientation flags may be included here. -/// \sa GAME GAMEL COMP SYST -#define CONS(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ -GAME_DRIVER_TRAITS(NAME, FULLNAME) \ -extern game_driver const GAME_NAME(NAME) \ -{ \ - GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \ - #PARENT, \ - #YEAR, \ - COMPANY, \ - [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \ - INPUT_PORTS_NAME(INPUT), \ - [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \ - ROM_NAME(NAME), \ - #COMPAT, \ - nullptr, \ - machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_CONSOLE)), \ - #NAME \ -}; +/// \sa GAME GAMEL +#define SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ + GAME_DRIVER_TRAITS(NAME, FULLNAME) \ + extern game_driver const GAME_NAME(NAME) \ + { \ + GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \ + #PARENT, \ + #YEAR, \ + COMPANY, \ + [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \ + INPUT_PORTS_NAME(INPUT), \ + [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \ + ROM_NAME(NAME), \ + #COMPAT, \ + nullptr, \ + machine_flags::type(u32(ROT0 | (FLAGS))), \ + #NAME \ + }; -/// \brief Define a "computer" system -/// -/// Use this macro to define computer-like systems. Must be used in the -/// global namespace. -/// -/// Creates an appropriately named and populated #game_driver structure -/// describing the system. -/// \param YEAR The year that the system was first made available. Must -/// be a token containing only the digits zero to nine, question mark -/// and plus sign. -/// \param NAME The short name of the system, used for identification, -/// and in filesystem paths for assets and data. Must be a token no -/// longer than sixteen characters, containing only ASCII lowercase -/// letters, digits and underscores. Must be globally unique across -/// systems and devices. -/// \param PARENT Short name of the parent or BIOS system if applicable, -/// or a single digit zero otherwise. -/// \param COMPAT Short name of a system that this system is compatible -/// with if applicable, or a single digit zero otherwise. -/// \param MACHINE Function used to buid machine configuration for the -/// system. Must be a public member function of the system device -/// class (\p CLASS argument), returning void and taking a reference -/// to a #machine_config object as a parameter. -/// \param INPUT Input port definitions for the root device of the -/// system, usually defined using #INPUT_PORTS_START and associated -/// macros. -/// \param CLASS Class to instantiate as the root device of the system. -/// Must be an implementation of #driver_device. -/// \param INIT Initialisation function called after all child devices -/// have started, but before the driver start functions are called. -/// Often used for tasks like decrypting ROMs. Must be a public -/// member function of the system device class (\p CLASS argument), -/// returning void and accepting no parameters. The function -/// #driver_device::empty_init is supplied for systems that don't need -/// to perform additional tasks. -/// \param COMPANY Name of the developer or distributor of the system. -/// Must be a string. -/// \param FULLNAME Display name for the system. Must be a string, and -/// must be globally unique across systems and devices. -/// \param FLAGS Bitwise combination of emulation status flags for the -/// system, in addition to flags supplied by the system device class -/// (see #device_t::unemulated_features and -/// #device_t::imperfect_features). It is advisable to supply -/// unemulated and imperfectly emulated feature flags that apply to -/// all systems implemented using the class in the class itself to -/// avoid repetition. Screen orientation flags may be included here. -/// \sa GAME GAMEL CONS SYST -#define COMP(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ -GAME_DRIVER_TRAITS(NAME, FULLNAME) \ -extern game_driver const GAME_NAME(NAME) \ -{ \ - GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \ - #PARENT, \ - #YEAR, \ - COMPANY, \ - [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \ - INPUT_PORTS_NAME(INPUT), \ - [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \ - ROM_NAME(NAME), \ - #COMPAT, \ - nullptr, \ - machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_COMPUTER)), \ - #NAME \ -}; - +#define CONS(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ + SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) -/// \brief Define a generic system -/// -/// Use this macro to define miscellaneous systems that don't fall into -/// one of the other categories. Must be used in the global namespace. -/// -/// Creates an appropriately named and populated #game_driver structure -/// describing the system. -/// \param YEAR The year that the system was first made available. Must -/// be a token containing only the digits zero to nine, question mark -/// and plus sign. -/// \param NAME The short name of the system, used for identification, -/// and in filesystem paths for assets and data. Must be a token no -/// longer than sixteen characters, containing only ASCII lowercase -/// letters, digits and underscores. Must be globally unique across -/// systems and devices. -/// \param PARENT Short name of the parent or BIOS system if applicable, -/// or a single digit zero otherwise. -/// \param COMPAT Short name of a system that this system is compatible -/// with if applicable, or a single digit zero otherwise. -/// \param MACHINE Function used to buid machine configuration for the -/// system. Must be a public member function of the system device -/// class (\p CLASS argument), returning void and taking a reference -/// to a #machine_config object as a parameter. -/// \param INPUT Input port definitions for the root device of the -/// system, usually defined using #INPUT_PORTS_START and associated -/// macros. -/// \param CLASS Class to instantiate as the root device of the system. -/// Must be an implementation of #driver_device. -/// \param INIT Initialisation function called after all child devices -/// have started, but before the driver start functions are called. -/// Often used for tasks like decrypting ROMs. Must be a public -/// member function of the system device class (\p CLASS argument), -/// returning void and accepting no parameters. The function -/// #driver_device::empty_init is supplied for systems that don't need -/// to perform additional tasks. -/// \param COMPANY Name of the developer or distributor of the system. -/// Must be a string. -/// \param FULLNAME Display name for the system. Must be a string, and -/// must be globally unique across systems and devices. -/// \param FLAGS Bitwise combination of emulation status flags for the -/// system, in addition to flags supplied by the system device class -/// (see #device_t::unemulated_features and -/// #device_t::imperfect_features). It is advisable to supply -/// unemulated and imperfectly emulated feature flags that apply to -/// all systems implemented using the class in the class itself to -/// avoid repetition. Screen orientation flags may be included here. -/// \sa GAME GAMEL CONS COMP -#define SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ -GAME_DRIVER_TRAITS(NAME, FULLNAME) \ -extern game_driver const GAME_NAME(NAME) \ -{ \ - GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \ - #PARENT, \ - #YEAR, \ - COMPANY, \ - [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \ - INPUT_PORTS_NAME(INPUT), \ - [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \ - ROM_NAME(NAME), \ - #COMPAT, \ - nullptr, \ - machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_OTHER)), \ - #NAME \ -}; +#define COMP(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \ + SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) /// \} diff --git a/src/emu/hashfile.cpp b/src/emu/hashfile.cpp index a6107e5e630..8436ad339fb 100644 --- a/src/emu/hashfile.cpp +++ b/src/emu/hashfile.cpp @@ -13,6 +13,7 @@ #include "drivenum.h" #include "emuopts.h" +#include "fileio.h" #include "hash.h" diff --git a/src/emu/http.cpp b/src/emu/http.cpp index f36244e31ac..2a30a13dba3 100644 --- a/src/emu/http.cpp +++ b/src/emu/http.cpp @@ -9,6 +9,9 @@ ***************************************************************************/ #include "emu.h" +#include "http.h" +#include "server_http.hpp" +#include "server_ws.hpp" #ifdef __sun #define ASIO_DISABLE_DEV_POLL @@ -141,28 +144,28 @@ public: virtual ~http_request_impl() = default; /** Retrieves the requested resource. */ - virtual const std::string get_resource() { + virtual const std::string get_resource() override { // The entire resource: path, query and fragment. return m_request->path; } /** Returns the path part of the requested resource. */ - virtual const std::string get_path() { + virtual const std::string get_path() override { return m_request->path.substr(0, m_path_end); } /** Returns the query part of the requested resource. */ - virtual const std::string get_query() { + virtual const std::string get_query() override { return m_query == std::string::npos ? "" : m_request->path.substr(m_query, m_query_end); } /** Returns the fragment part of the requested resource. */ - virtual const std::string get_fragment() { + virtual const std::string get_fragment() override { return m_fragment == std::string::npos ? "" : m_request->path.substr(m_fragment); } /** Retrieves a header from the HTTP request. */ - virtual const std::string get_header(const std::string &header_name) { + virtual const std::string get_header(const std::string &header_name) override { auto i = m_request->header.find(header_name); if (i != m_request->header.end()) { return (*i).second; @@ -172,7 +175,7 @@ public: } /** Retrieves a header from the HTTP request. */ - virtual const std::list<std::string> get_headers(const std::string &header_name) { + virtual const std::list<std::string> get_headers(const std::string &header_name) override { std::list<std::string> result; auto range = m_request->header.equal_range(header_name); for (auto i = range.first; i != range.second; i++) { @@ -182,7 +185,7 @@ public: } /** Returns the body that was submitted with the HTTP request. */ - virtual const std::string get_body() { + virtual const std::string get_body() override { // TODO(cbrunschen): What to return here - http_server::Request has a 'content' feld that is never filled in! return ""; } @@ -201,23 +204,23 @@ struct http_response_impl : public http_manager::http_response { virtual ~http_response_impl() = default; /** Sets the HTTP status to be returned to the client. */ - virtual void set_status(int status) { + virtual void set_status(int status) override { m_status = status; } /** Sets the HTTP content type to be returned to the client. */ - virtual void set_content_type(const std::string &content_type) { + virtual void set_content_type(const std::string &content_type) override { m_content_type = content_type; } /** Sets the body to be sent to the client. */ - virtual void set_body(const std::string &body) { + virtual void set_body(const std::string &body) override { m_body.str(""); append_body(body); } /** Appends something to the body to be sent to the client. */ - virtual void append_body(const std::string &body) { + virtual void append_body(const std::string &body) override { m_body << body; } @@ -255,7 +258,7 @@ struct websocket_connection_impl : public http_manager::websocket_connection { : m_wsserver(server), m_connection(connection) { } /** Sends a message to the client that is connected on the other end of this Websocket connection. */ - virtual void send_message(const std::string &payload, int opcode) { + virtual void send_message(const std::string &payload, int opcode) override { if (auto connection = m_connection.lock()) { std::shared_ptr<webpp::ws_server::SendStream> message_stream = std::make_shared<webpp::ws_server::SendStream>(); (*message_stream) << payload; @@ -264,7 +267,7 @@ struct websocket_connection_impl : public http_manager::websocket_connection { } /** Closes this open Websocket connection. */ - virtual void close() { + virtual void close() override { if (auto connection = m_connection.lock()) { m_wsserver->send_close(connection, 1000 /* normal close */); } diff --git a/src/emu/http.h b/src/emu/http.h index b0adf1e2b3d..e7c26d7980f 100644 --- a/src/emu/http.h +++ b/src/emu/http.h @@ -10,18 +10,12 @@ #pragma once -#ifndef __EMU_H__ -#error Dont include this file directly; include emu.h instead. -#endif - #ifndef MAME_EMU_HTTP_H #define MAME_EMU_HTTP_H #include <mutex> #include <thread> #include <ctime> -#include "server_http.hpp" -#include "server_ws.hpp" //************************************************************************** // TYPE DEFINITIONS @@ -33,6 +27,13 @@ namespace asio class io_context; } +namespace webpp +{ + class http_server; + class ws_server; + struct Connection; +} + class http_manager { DISABLE_COPYING(http_manager); diff --git a/src/emu/image.cpp b/src/emu/image.cpp index 5e58758eb89..3839a57549b 100644 --- a/src/emu/image.cpp +++ b/src/emu/image.cpp @@ -14,8 +14,11 @@ #include "config.h" #include "drivenum.h" #include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "softlist.h" +// lib/util #include "corestr.h" #include "xmlfile.h" #include "zippath.h" @@ -37,6 +40,9 @@ image_manager::image_manager(running_machine &machine) // make sure that any required devices have been allocated for (device_image_interface &image : image_interface_enumerator(machine.root_device())) { + // see if region-based chds are available + image.check_preset_images(); + // ignore things not user loadable if (!image.user_loadable()) continue; @@ -48,27 +54,32 @@ image_manager::image_manager(running_machine &machine) if (!startup_image.empty()) { // we do have a startup image specified - load it - image_init_result result = image_init_result::FAIL; + std::pair<std::error_condition, std::string> result(image_error::UNSPECIFIED, std::string()); // try as a softlist if (software_name_parse(startup_image)) + { + osd_printf_verbose("%s: attempting to load software item %s\n", image.device().tag(), startup_image); result = image.load_software(startup_image); + } // failing that, try as an image - if (result != image_init_result::PASS) + if (result.first) + { + osd_printf_verbose("%s: attempting to load media image %s\n", image.device().tag(), startup_image); result = image.load(startup_image); + } // failing that, try creating it (if appropriate) - if (result != image_init_result::PASS && image.support_command_line_image_creation()) + if (result.first && image.support_command_line_image_creation()) + { + osd_printf_verbose("%s: attempting to create media image %s\n", image.device().tag(), startup_image); result = image.create(startup_image); + } // did the image load fail? - if (result != image_init_result::PASS) + if (result.first) { - // retrieve image error message - std::string image_err = std::string(image.error()); - std::string startup_image_name = startup_image; - // unload the bad image image.unload(); @@ -77,11 +88,18 @@ image_manager::image_manager(running_machine &machine) if (machine.options().write_config()) write_config(machine.options(), nullptr, &machine.system()); - throw emu_fatalerror(EMU_ERR_DEVICE, "Device %s load (-%s %s) failed: %s", + // retrieve image error message + throw emu_fatalerror(EMU_ERR_DEVICE, + !result.second.empty() + ? "Device %1$s load (-%2$s %3$s) failed: %4$s (%5$s:%6$d %7$s)" + : "Device %1$s load (-%2$s %3$s) failed: %7$s (%5$s:%6$d)", image.device().name(), image.instance_name(), - startup_image_name, - image_err); + startup_image, + result.second, + result.first.category().name(), + result.first.value(), + result.first.message()); } } } @@ -240,13 +258,14 @@ void image_manager::postdevice_init() /* make sure that any required devices have been allocated */ for (device_image_interface &image : image_interface_enumerator(machine().root_device())) { - image_init_result result = image.finish_load(); + auto [result, image_err] = image.finish_load(); /* did the image load fail? */ - if (result != image_init_result::PASS) + if (result) { /* retrieve image error message */ - std::string image_err = std::string(image.error()); + if (image_err.empty()) + image_err = result.message(); /* unload all images */ unload_all(); diff --git a/src/emu/image.h b/src/emu/image.h index daf48b1f21d..95dca8a92b9 100644 --- a/src/emu/image.h +++ b/src/emu/image.h @@ -36,7 +36,7 @@ private: void options_extract(); int write_config(emu_options &options, const char *filename, const game_driver *gamedrv); - bool try_change_working_directory(std::string &working_directory, const std::string &subdir);; + bool try_change_working_directory(std::string &working_directory, const std::string &subdir); // internal state running_machine & m_machine; // reference to our machine diff --git a/src/emu/inpttype.h b/src/emu/inpttype.h new file mode 100644 index 00000000000..fa711b7eabd --- /dev/null +++ b/src/emu/inpttype.h @@ -0,0 +1,353 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + inpttype.ipp + + Core-defined input types. + +***************************************************************************/ +#ifndef MAME_EMU_INPTTYPE_H +#define MAME_EMU_INPTTYPE_H + +#pragma once + +#include "interface/inputfwd.h" +#include "osdcomm.h" + + +enum ioport_type : osd::u32 +{ + // pseudo-port types + IPT_INVALID = 0, + IPT_UNUSED, + IPT_END, + IPT_UNKNOWN, + IPT_PORT, + IPT_DIPSWITCH, + IPT_CONFIG, + + // start buttons + IPT_START1, + IPT_START2, + IPT_START3, + IPT_START4, + IPT_START5, + IPT_START6, + IPT_START7, + IPT_START8, + IPT_START9, + IPT_START10, + + // coin slots + IPT_COIN1, + IPT_COIN2, + IPT_COIN3, + IPT_COIN4, + IPT_COIN5, + IPT_COIN6, + IPT_COIN7, + IPT_COIN8, + IPT_COIN9, + IPT_COIN10, + IPT_COIN11, + IPT_COIN12, + IPT_BILL1, + + // service coin + IPT_SERVICE1, + IPT_SERVICE2, + IPT_SERVICE3, + IPT_SERVICE4, + + // tilt inputs + IPT_TILT1, + IPT_TILT2, + IPT_TILT3, + IPT_TILT4, + + // misc other digital inputs + IPT_POWER_ON, + IPT_POWER_OFF, + IPT_SERVICE, + IPT_TILT, + IPT_INTERLOCK, + IPT_MEMORY_RESET, + IPT_VOLUME_UP, + IPT_VOLUME_DOWN, + IPT_START, // use the numbered start button(s) for coin-ops + IPT_SELECT, + IPT_KEYPAD, + IPT_KEYBOARD, + + // digital joystick inputs + IPT_DIGITAL_JOYSTICK_FIRST, + + // use IPT_JOYSTICK for panels where the player has one single joystick + IPT_JOYSTICK_UP, + IPT_JOYSTICK_DOWN, + IPT_JOYSTICK_LEFT, + IPT_JOYSTICK_RIGHT, + + // use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels + IPT_JOYSTICKRIGHT_UP, + IPT_JOYSTICKRIGHT_DOWN, + IPT_JOYSTICKRIGHT_LEFT, + IPT_JOYSTICKRIGHT_RIGHT, + IPT_JOYSTICKLEFT_UP, + IPT_JOYSTICKLEFT_DOWN, + IPT_JOYSTICKLEFT_LEFT, + IPT_JOYSTICKLEFT_RIGHT, + + IPT_DIGITAL_JOYSTICK_LAST, + + // action buttons + IPT_BUTTON1, + IPT_BUTTON2, + IPT_BUTTON3, + IPT_BUTTON4, + IPT_BUTTON5, + IPT_BUTTON6, + IPT_BUTTON7, + IPT_BUTTON8, + IPT_BUTTON9, + IPT_BUTTON10, + IPT_BUTTON11, + IPT_BUTTON12, + IPT_BUTTON13, + IPT_BUTTON14, + IPT_BUTTON15, + IPT_BUTTON16, + + // mahjong inputs + IPT_MAHJONG_FIRST, + + IPT_MAHJONG_A, + IPT_MAHJONG_B, + IPT_MAHJONG_C, + IPT_MAHJONG_D, + IPT_MAHJONG_E, + IPT_MAHJONG_F, + IPT_MAHJONG_G, + IPT_MAHJONG_H, + IPT_MAHJONG_I, + IPT_MAHJONG_J, + IPT_MAHJONG_K, + IPT_MAHJONG_L, + IPT_MAHJONG_M, + IPT_MAHJONG_N, + IPT_MAHJONG_O, + IPT_MAHJONG_P, + IPT_MAHJONG_Q, + IPT_MAHJONG_KAN, + IPT_MAHJONG_PON, + IPT_MAHJONG_CHI, + IPT_MAHJONG_REACH, + IPT_MAHJONG_RON, + IPT_MAHJONG_FLIP_FLOP, + IPT_MAHJONG_BET, + IPT_MAHJONG_SCORE, + IPT_MAHJONG_DOUBLE_UP, + IPT_MAHJONG_BIG, + IPT_MAHJONG_SMALL, + IPT_MAHJONG_LAST_CHANCE, + + IPT_MAHJONG_LAST, + + // hanafuda inputs + IPT_HANAFUDA_FIRST, + + IPT_HANAFUDA_A, + IPT_HANAFUDA_B, + IPT_HANAFUDA_C, + IPT_HANAFUDA_D, + IPT_HANAFUDA_E, + IPT_HANAFUDA_F, + IPT_HANAFUDA_G, + IPT_HANAFUDA_H, + IPT_HANAFUDA_YES, + IPT_HANAFUDA_NO, + + IPT_HANAFUDA_LAST, + + // gambling inputs + IPT_GAMBLING_FIRST, + + IPT_GAMBLE_KEYIN, // attendant + IPT_GAMBLE_KEYOUT, // attendant + IPT_GAMBLE_SERVICE, // attendant + IPT_GAMBLE_BOOK, // attendant + IPT_GAMBLE_DOOR, // attendant + // IPT_GAMBLE_DOOR2, // many gambling games have several doors. + // IPT_GAMBLE_DOOR3, + // IPT_GAMBLE_DOOR4, + // IPT_GAMBLE_DOOR5, + + IPT_GAMBLE_PAYOUT, // player + IPT_GAMBLE_BET, // player + IPT_GAMBLE_DEAL, // player + IPT_GAMBLE_STAND, // player + IPT_GAMBLE_TAKE, // player + IPT_GAMBLE_D_UP, // player + IPT_GAMBLE_HALF, // player + IPT_GAMBLE_HIGH, // player + IPT_GAMBLE_LOW, // player + + // poker-specific inputs + IPT_POKER_HOLD1, + IPT_POKER_HOLD2, + IPT_POKER_HOLD3, + IPT_POKER_HOLD4, + IPT_POKER_HOLD5, + IPT_POKER_CANCEL, + + // slot-specific inputs + IPT_SLOT_STOP1, + IPT_SLOT_STOP2, + IPT_SLOT_STOP3, + IPT_SLOT_STOP4, + IPT_SLOT_STOP_ALL, + + IPT_GAMBLING_LAST, + + // analog inputs + IPT_ANALOG_FIRST, + + IPT_ANALOG_ABSOLUTE_FIRST, + + IPT_AD_STICK_X, // absolute // autocenter + IPT_AD_STICK_Y, // absolute // autocenter + IPT_AD_STICK_Z, // absolute // autocenter + IPT_PADDLE, // absolute // autocenter + IPT_PADDLE_V, // absolute // autocenter + IPT_PEDAL, // absolute // autocenter + IPT_PEDAL2, // absolute // autocenter + IPT_PEDAL3, // absolute // autocenter + IPT_LIGHTGUN_X, // absolute + IPT_LIGHTGUN_Y, // absolute + IPT_POSITIONAL, // absolute // autocenter if not wraps + IPT_POSITIONAL_V, // absolute // autocenter if not wraps + + IPT_ANALOG_ABSOLUTE_LAST, + + IPT_DIAL, // relative + IPT_DIAL_V, // relative + IPT_TRACKBALL_X, // relative + IPT_TRACKBALL_Y, // relative + IPT_MOUSE_X, // relative + IPT_MOUSE_Y, // relative + + IPT_ANALOG_LAST, + + // analog adjuster support + IPT_ADJUSTER, + + // the following are special codes for user interface handling - not to be used by drivers! + IPT_UI_FIRST, + + IPT_UI_MENU, + IPT_UI_SELECT, + IPT_UI_BACK, + IPT_UI_CANCEL, + IPT_UI_CLEAR, + IPT_UI_HELP, + IPT_UI_UP, + IPT_UI_DOWN, + IPT_UI_LEFT, + IPT_UI_RIGHT, + IPT_UI_HOME, + IPT_UI_END, + IPT_UI_PAGE_UP, + IPT_UI_PAGE_DOWN, + IPT_UI_PREV_GROUP, + IPT_UI_NEXT_GROUP, + IPT_UI_ON_SCREEN_DISPLAY, + IPT_UI_TOGGLE_UI, + IPT_UI_DEBUG_BREAK, + IPT_UI_PAUSE, + IPT_UI_PAUSE_SINGLE, + IPT_UI_REWIND_SINGLE, + IPT_UI_SAVE_STATE, + IPT_UI_SAVE_STATE_QUICK, + IPT_UI_LOAD_STATE, + IPT_UI_LOAD_STATE_QUICK, + IPT_UI_RESET_MACHINE, + IPT_UI_SOFT_RESET, + IPT_UI_SHOW_GFX, + IPT_UI_FRAMESKIP_DEC, + IPT_UI_FRAMESKIP_INC, + IPT_UI_THROTTLE, + IPT_UI_FAST_FORWARD, + IPT_UI_SHOW_FPS, + IPT_UI_SNAPSHOT, + IPT_UI_RECORD_MNG, + IPT_UI_RECORD_AVI, + IPT_UI_TOGGLE_CHEAT, + IPT_UI_DISPLAY_COMMENT, + IPT_UI_ZOOM_IN, + IPT_UI_ZOOM_OUT, + IPT_UI_ZOOM_DEFAULT, + IPT_UI_ROTATE, + IPT_UI_SHOW_PROFILER, + IPT_UI_RELEASE_POINTER, + IPT_UI_PASTE, + IPT_UI_TAPE_START, + IPT_UI_TAPE_STOP, + IPT_UI_FOCUS_NEXT, + IPT_UI_FOCUS_PREV, + IPT_UI_DATS, + IPT_UI_FAVORITES, + IPT_UI_EXPORT, + IPT_UI_AUDIT, + + // additional OSD-specified UI port types (up to 16) + IPT_OSD_1, + IPT_OSD_2, + IPT_OSD_3, + IPT_OSD_4, + IPT_OSD_5, + IPT_OSD_6, + IPT_OSD_7, + IPT_OSD_8, + IPT_OSD_9, + IPT_OSD_10, + IPT_OSD_11, + IPT_OSD_12, + IPT_OSD_13, + IPT_OSD_14, + IPT_OSD_15, + IPT_OSD_16, + + IPT_UI_LAST, + + IPT_OTHER, // not mapped to standard defaults + + IPT_SPECIAL, // uninterpreted characters + IPT_CUSTOM, // handled by custom code + IPT_OUTPUT, + + IPT_COUNT, + + // aliases for some types + IPT_PADDLE_H = IPT_PADDLE, + IPT_PEDAL1 = IPT_PEDAL, + IPT_POSITIONAL_H = IPT_POSITIONAL, + IPT_DIAL_H = IPT_DIAL +}; + +DECLARE_ENUM_INCDEC_OPERATORS(ioport_type) + + +// sequence types for input_port_seq() call +enum input_seq_type : int +{ + SEQ_TYPE_INVALID = -1, + SEQ_TYPE_STANDARD = 0, + SEQ_TYPE_INCREMENT, + SEQ_TYPE_DECREMENT, + SEQ_TYPE_TOTAL +}; + +DECLARE_ENUM_INCDEC_OPERATORS(input_seq_type) + +#endif // MAME_EMU_INPTTYPE_H diff --git a/src/emu/inpttype.ipp b/src/emu/inpttype.ipp index aca3973673a..8c217a1d39c 100644 --- a/src/emu/inpttype.ipp +++ b/src/emu/inpttype.ipp @@ -19,83 +19,83 @@ namespace { #define CORE_INPUT_TYPES_P1 \ CORE_INPUT_TYPES_BEGIN(p1) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_UP, N_p("input-name", "P1 Up"), input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_DOWN, N_p("input-name", "P1 Down"), input_seq(KEYCODE_DOWN, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_LEFT, N_p("input-name", "P1 Left"), input_seq(KEYCODE_LEFT, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_RIGHT, N_p("input-name", "P1 Right"), input_seq(KEYCODE_RIGHT, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_UP, N_p("input-name", "P1 Right Stick/Up"), input_seq(KEYCODE_I, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_DOWN, N_p("input-name", "P1 Right Stick/Down"), input_seq(KEYCODE_K, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_LEFT, N_p("input-name", "P1 Right Stick/Left"), input_seq(KEYCODE_J, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P1 Right Stick/Right"), input_seq(KEYCODE_L, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_UP, N_p("input-name", "P1 Left Stick/Up"), input_seq(KEYCODE_E, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_DOWN, N_p("input-name", "P1 Left Stick/Down"), input_seq(KEYCODE_D, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_LEFT, N_p("input-name", "P1 Left Stick/Left"), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_RIGHT, N_p("input-name", "P1 Left Stick/Right"), input_seq(KEYCODE_F, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON1, N_p("input-name", "P1 Button 1"), input_seq(KEYCODE_LCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON2, N_p("input-name", "P1 Button 2"), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON3, N_p("input-name", "P1 Button 3"), input_seq(KEYCODE_SPACE, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON4, N_p("input-name", "P1 Button 4"), input_seq(KEYCODE_LSHIFT, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON5, N_p("input-name", "P1 Button 5"), input_seq(KEYCODE_Z, input_seq::or_code, JOYCODE_BUTTON5_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON6, N_p("input-name", "P1 Button 6"), input_seq(KEYCODE_X, input_seq::or_code, JOYCODE_BUTTON6_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON7, N_p("input-name", "P1 Button 7"), input_seq(KEYCODE_C, input_seq::or_code, JOYCODE_BUTTON7_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON8, N_p("input-name", "P1 Button 8"), input_seq(KEYCODE_V, input_seq::or_code, JOYCODE_BUTTON8_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON9, N_p("input-name", "P1 Button 9"), input_seq(KEYCODE_B, input_seq::or_code, JOYCODE_BUTTON9_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON10, N_p("input-name", "P1 Button 10"), input_seq(KEYCODE_N, input_seq::or_code, JOYCODE_BUTTON10_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON11, N_p("input-name", "P1 Button 11"), input_seq(KEYCODE_M, input_seq::or_code, JOYCODE_BUTTON11_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON12, N_p("input-name", "P1 Button 12"), input_seq(KEYCODE_COMMA, input_seq::or_code, JOYCODE_BUTTON12_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON13, N_p("input-name", "P1 Button 13"), input_seq(KEYCODE_STOP, input_seq::or_code, JOYCODE_BUTTON13_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON14, N_p("input-name", "P1 Button 14"), input_seq(KEYCODE_SLASH, input_seq::or_code, JOYCODE_BUTTON14_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON15, N_p("input-name", "P1 Button 15"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON15_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON16, N_p("input-name", "P1 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, START, N_p("input-name", "P1 Start"), input_seq(KEYCODE_1, input_seq::or_code, JOYCODE_START_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, SELECT, N_p("input-name", "P1 Select"), input_seq(KEYCODE_5, input_seq::or_code, JOYCODE_SELECT_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_UP) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_LEFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq(KEYCODE_I) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq(KEYCODE_K) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq(KEYCODE_J) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq(KEYCODE_L) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq(KEYCODE_E) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq(KEYCODE_D) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq(KEYCODE_S) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq(KEYCODE_F) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_LCONTROL, input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_LALT, input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_SPACE, input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON4, N_p("input-name", "%p Button 4"), input_seq(KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON5, N_p("input-name", "%p Button 5"), input_seq(KEYCODE_Z) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON6, N_p("input-name", "%p Button 6"), input_seq(KEYCODE_X) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON7, N_p("input-name", "%p Button 7"), input_seq(KEYCODE_C) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON8, N_p("input-name", "%p Button 8"), input_seq(KEYCODE_V) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON9, N_p("input-name", "%p Button 9"), input_seq(KEYCODE_B) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON10, N_p("input-name", "%p Button 10"), input_seq(KEYCODE_N) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON11, N_p("input-name", "%p Button 11"), input_seq(KEYCODE_M) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON12, N_p("input-name", "%p Button 12"), input_seq(KEYCODE_COMMA) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON13, N_p("input-name", "%p Button 13"), input_seq(KEYCODE_STOP) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON14, N_p("input-name", "%p Button 14"), input_seq(KEYCODE_SLASH) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON15, N_p("input-name", "%p Button 15"), input_seq(KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_1) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_5) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P1_MAHJONG \ CORE_INPUT_TYPES_BEGIN(p1_mahjong) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_A, N_p("input-name", "P1 Mahjong A"), input_seq(KEYCODE_A) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_B, N_p("input-name", "P1 Mahjong B"), input_seq(KEYCODE_B) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_C, N_p("input-name", "P1 Mahjong C"), input_seq(KEYCODE_C) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_D, N_p("input-name", "P1 Mahjong D"), input_seq(KEYCODE_D) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_E, N_p("input-name", "P1 Mahjong E"), input_seq(KEYCODE_E) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_F, N_p("input-name", "P1 Mahjong F"), input_seq(KEYCODE_F) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_G, N_p("input-name", "P1 Mahjong G"), input_seq(KEYCODE_G) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_H, N_p("input-name", "P1 Mahjong H"), input_seq(KEYCODE_H) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_I, N_p("input-name", "P1 Mahjong I"), input_seq(KEYCODE_I) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_J, N_p("input-name", "P1 Mahjong J"), input_seq(KEYCODE_J) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_K, N_p("input-name", "P1 Mahjong K"), input_seq(KEYCODE_K) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_L, N_p("input-name", "P1 Mahjong L"), input_seq(KEYCODE_L) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_M, N_p("input-name", "P1 Mahjong M"), input_seq(KEYCODE_M) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_N, N_p("input-name", "P1 Mahjong N"), input_seq(KEYCODE_N) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_O, N_p("input-name", "P1 Mahjong O"), input_seq(KEYCODE_O) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_P, N_p("input-name", "P1 Mahjong P"), input_seq(KEYCODE_COLON) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_Q, N_p("input-name", "P1 Mahjong Q"), input_seq(KEYCODE_Q) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_KAN, N_p("input-name", "P1 Mahjong Kan"), input_seq(KEYCODE_LCONTROL) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_PON, N_p("input-name", "P1 Mahjong Pon"), input_seq(KEYCODE_LALT) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_CHI, N_p("input-name", "P1 Mahjong Chi"), input_seq(KEYCODE_SPACE) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_REACH, N_p("input-name", "P1 Mahjong Reach"), input_seq(KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_RON, N_p("input-name", "P1 Mahjong Ron"), input_seq(KEYCODE_Z) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_FLIP_FLOP, N_p("input-name", "P1 Mahjong Flip Flop"), input_seq(KEYCODE_Y) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BET, N_p("input-name", "P1 Mahjong Bet"), input_seq(KEYCODE_3) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SCORE, N_p("input-name", "P1 Mahjong Take Score"), input_seq(KEYCODE_RCONTROL) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_DOUBLE_UP, N_p("input-name", "P1 Mahjong Double Up"), input_seq(KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BIG, N_p("input-name", "P1 Mahjong Big"), input_seq(KEYCODE_ENTER) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SMALL, N_p("input-name", "P1 Mahjong Small"), input_seq(KEYCODE_BACKSPACE) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_LAST_CHANCE, N_p("input-name", "P1 Mahjong Last Chance"), input_seq(KEYCODE_RALT) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(0)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P1_HANAFUDA \ CORE_INPUT_TYPES_BEGIN(p1_hanafuda) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_A, N_p("input-name", "P1 Hanafuda A/1"), input_seq(KEYCODE_A) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_B, N_p("input-name", "P1 Hanafuda B/2"), input_seq(KEYCODE_B) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_C, N_p("input-name", "P1 Hanafuda C/3"), input_seq(KEYCODE_C) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_D, N_p("input-name", "P1 Hanafuda D/4"), input_seq(KEYCODE_D) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_E, N_p("input-name", "P1 Hanafuda E/5"), input_seq(KEYCODE_E) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_F, N_p("input-name", "P1 Hanafuda F/6"), input_seq(KEYCODE_F) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_G, N_p("input-name", "P1 Hanafuda G/7"), input_seq(KEYCODE_G) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_H, N_p("input-name", "P1 Hanafuda H/8"), input_seq(KEYCODE_H) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_YES, N_p("input-name", "P1 Hanafuda Yes"), input_seq(KEYCODE_M) ) \ - INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_NO, N_p("input-name", "P1 Hanafuda No"), input_seq(KEYCODE_N) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_A, N_p("input-name", "%p Hanafuda A/1"), input_seq(KEYCODE_A_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_B, N_p("input-name", "%p Hanafuda B/2"), input_seq(KEYCODE_B_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_C, N_p("input-name", "%p Hanafuda C/3"), input_seq(KEYCODE_C_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_D, N_p("input-name", "%p Hanafuda D/4"), input_seq(KEYCODE_D_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_E, N_p("input-name", "%p Hanafuda E/5"), input_seq(KEYCODE_E_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_F, N_p("input-name", "%p Hanafuda F/6"), input_seq(KEYCODE_F_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_G, N_p("input-name", "%p Hanafuda G/7"), input_seq(KEYCODE_G_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_H, N_p("input-name", "%p Hanafuda H/8"), input_seq(KEYCODE_H_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_YES, N_p("input-name", "%p Hanafuda Yes"), input_seq(KEYCODE_M_INDEXED(0)) ) \ + INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_NO, N_p("input-name", "%p Hanafuda No"), input_seq(KEYCODE_N_INDEXED(0)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_GAMBLE \ @@ -137,355 +137,421 @@ namespace { #define CORE_INPUT_TYPES_P2 \ CORE_INPUT_TYPES_BEGIN(p2) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_UP, N_p("input-name", "P2 Up"), input_seq(KEYCODE_R, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_DOWN, N_p("input-name", "P2 Down"), input_seq(KEYCODE_F, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_LEFT, N_p("input-name", "P2 Left"), input_seq(KEYCODE_D, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_RIGHT, N_p("input-name", "P2 Right"), input_seq(KEYCODE_G, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_UP, N_p("input-name", "P2 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_DOWN, N_p("input-name", "P2 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_LEFT, N_p("input-name", "P2 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P2 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_UP, N_p("input-name", "P2 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_DOWN, N_p("input-name", "P2 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_LEFT, N_p("input-name", "P2 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_RIGHT, N_p("input-name", "P2 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON1, N_p("input-name", "P2 Button 1"), input_seq(KEYCODE_A, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON2, N_p("input-name", "P2 Button 2"), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON3, N_p("input-name", "P2 Button 3"), input_seq(KEYCODE_Q, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON4, N_p("input-name", "P2 Button 4"), input_seq(KEYCODE_W, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON5, N_p("input-name", "P2 Button 5"), input_seq(KEYCODE_E, input_seq::or_code, JOYCODE_BUTTON5_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON6, N_p("input-name", "P2 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON7, N_p("input-name", "P2 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON8, N_p("input-name", "P2 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON9, N_p("input-name", "P2 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON10, N_p("input-name", "P2 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON11, N_p("input-name", "P2 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON12, N_p("input-name", "P2 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON13, N_p("input-name", "P2 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON14, N_p("input-name", "P2 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON15, N_p("input-name", "P2 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON16, N_p("input-name", "P2 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, START, N_p("input-name", "P2 Start"), input_seq(KEYCODE_2, input_seq::or_code, JOYCODE_START_INDEXED(1)) ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, SELECT, N_p("input-name", "P2 Select"), input_seq(KEYCODE_6, input_seq::or_code, JOYCODE_SELECT_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_R) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_F) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_D) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_G) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_A, input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_S, input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_Q, input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON4, N_p("input-name", "%p Button 4"), input_seq(KEYCODE_W) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON5, N_p("input-name", "%p Button 5"), input_seq(KEYCODE_E) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_2) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_6) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P2_MAHJONG \ CORE_INPUT_TYPES_BEGIN(p2_mahjong) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_A, N_p("input-name", "P2 Mahjong A"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_B, N_p("input-name", "P2 Mahjong B"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_C, N_p("input-name", "P2 Mahjong C"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_D, N_p("input-name", "P2 Mahjong D"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_E, N_p("input-name", "P2 Mahjong E"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_F, N_p("input-name", "P2 Mahjong F"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_G, N_p("input-name", "P2 Mahjong G"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_H, N_p("input-name", "P2 Mahjong H"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_I, N_p("input-name", "P2 Mahjong I"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_J, N_p("input-name", "P2 Mahjong J"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_K, N_p("input-name", "P2 Mahjong K"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_L, N_p("input-name", "P2 Mahjong L"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_M, N_p("input-name", "P2 Mahjong M"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_N, N_p("input-name", "P2 Mahjong N"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_O, N_p("input-name", "P2 Mahjong O"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_P, N_p("input-name", "P2 Mahjong P"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_Q, N_p("input-name", "P2 Mahjong Q"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_KAN, N_p("input-name", "P2 Mahjong Kan"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_PON, N_p("input-name", "P2 Mahjong Pon"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_CHI, N_p("input-name", "P2 Mahjong Chi"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_REACH, N_p("input-name", "P2 Mahjong Reach"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_RON, N_p("input-name", "P2 Mahjong Ron"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BET, N_p("input-name", "P2 Mahjong Bet"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_LAST_CHANCE, N_p("input-name", "P2 Mahjong Last Chance"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SCORE, N_p("input-name", "P2 Mahjong Take Score"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_DOUBLE_UP, N_p("input-name", "P2 Mahjong Double Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_FLIP_FLOP, N_p("input-name", "P2 Mahjong Flip Flop"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BIG, N_p("input-name", "P2 Mahjong Big"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SMALL, N_p("input-name", "P2 Mahjong Small"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(1)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P2_HANAFUDA \ CORE_INPUT_TYPES_BEGIN(p2_hanafuda) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_A, N_p("input-name", "P2 Hanafuda A/1"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_B, N_p("input-name", "P2 Hanafuda B/2"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_C, N_p("input-name", "P2 Hanafuda C/3"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_D, N_p("input-name", "P2 Hanafuda D/4"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_E, N_p("input-name", "P2 Hanafuda E/5"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_F, N_p("input-name", "P2 Hanafuda F/6"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_G, N_p("input-name", "P2 Hanafuda G/7"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_H, N_p("input-name", "P2 Hanafuda H/8"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_YES, N_p("input-name", "P2 Hanafuda Yes"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_NO, N_p("input-name", "P2 Hanafuda No"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_A, N_p("input-name", "%p Hanafuda A/1"), input_seq(KEYCODE_A_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_B, N_p("input-name", "%p Hanafuda B/2"), input_seq(KEYCODE_B_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_C, N_p("input-name", "%p Hanafuda C/3"), input_seq(KEYCODE_C_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_D, N_p("input-name", "%p Hanafuda D/4"), input_seq(KEYCODE_D_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_E, N_p("input-name", "%p Hanafuda E/5"), input_seq(KEYCODE_E_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_F, N_p("input-name", "%p Hanafuda F/6"), input_seq(KEYCODE_F_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_G, N_p("input-name", "%p Hanafuda G/7"), input_seq(KEYCODE_G_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_H, N_p("input-name", "%p Hanafuda H/8"), input_seq(KEYCODE_H_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_YES, N_p("input-name", "%p Hanafuda Yes"), input_seq(KEYCODE_M_INDEXED(1)) ) \ + INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_NO, N_p("input-name", "%p Hanafuda No"), input_seq(KEYCODE_N_INDEXED(1)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P3 \ CORE_INPUT_TYPES_BEGIN(p3) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_UP, N_p("input-name", "P3 Up"), input_seq(KEYCODE_I, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_DOWN, N_p("input-name", "P3 Down"), input_seq(KEYCODE_K, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_LEFT, N_p("input-name", "P3 Left"), input_seq(KEYCODE_J, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_RIGHT, N_p("input-name", "P3 Right"), input_seq(KEYCODE_L, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_UP, N_p("input-name", "P3 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_DOWN, N_p("input-name", "P3 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_LEFT, N_p("input-name", "P3 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P3 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_UP, N_p("input-name", "P3 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_DOWN, N_p("input-name", "P3 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_LEFT, N_p("input-name", "P3 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_RIGHT, N_p("input-name", "P3 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON1, N_p("input-name", "P3 Button 1"), input_seq(KEYCODE_RCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(2), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON2, N_p("input-name", "P3 Button 2"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON3, N_p("input-name", "P3 Button 3"), input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON4, N_p("input-name", "P3 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON5, N_p("input-name", "P3 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON6, N_p("input-name", "P3 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON7, N_p("input-name", "P3 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON8, N_p("input-name", "P3 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON9, N_p("input-name", "P3 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON10, N_p("input-name", "P3 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON11, N_p("input-name", "P3 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON12, N_p("input-name", "P3 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON13, N_p("input-name", "P3 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON14, N_p("input-name", "P3 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON15, N_p("input-name", "P3 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON16, N_p("input-name", "P3 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, START, N_p("input-name", "P3 Start"), input_seq(KEYCODE_3, input_seq::or_code, JOYCODE_START_INDEXED(2)) ) \ - INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, SELECT, N_p("input-name", "P3 Select"), input_seq(KEYCODE_7, input_seq::or_code, JOYCODE_SELECT_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_I) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_K) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_J) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_L) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_RCONTROL, input_seq::or_code, GUNCODE_BUTTON1_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, GUNCODE_BUTTON2_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_ENTER) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_3) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_7) ) \ + CORE_INPUT_TYPES_END() + +#define CORE_INPUT_TYPES_P3_MAHJONG \ + CORE_INPUT_TYPES_BEGIN(p3_mahjong) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(2)) ) \ + INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(2)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P4 \ CORE_INPUT_TYPES_BEGIN(p4) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_UP, N_p("input-name", "P4 Up"), input_seq(KEYCODE_8_PAD, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_DOWN, N_p("input-name", "P4 Down"), input_seq(KEYCODE_2_PAD, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_LEFT, N_p("input-name", "P4 Left"), input_seq(KEYCODE_4_PAD, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_RIGHT, N_p("input-name", "P4 Right"), input_seq(KEYCODE_6_PAD, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_UP, N_p("input-name", "P4 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_DOWN, N_p("input-name", "P4 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_LEFT, N_p("input-name", "P4 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P4 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_UP, N_p("input-name", "P4 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_DOWN, N_p("input-name", "P4 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_LEFT, N_p("input-name", "P4 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_RIGHT, N_p("input-name", "P4 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON1, N_p("input-name", "P4 Button 1"), input_seq(KEYCODE_0_PAD, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON2, N_p("input-name", "P4 Button 2"), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON3, N_p("input-name", "P4 Button 3"), input_seq(KEYCODE_ENTER_PAD, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON4, N_p("input-name", "P4 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON5, N_p("input-name", "P4 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON6, N_p("input-name", "P4 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON7, N_p("input-name", "P4 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON8, N_p("input-name", "P4 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON9, N_p("input-name", "P4 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON10, N_p("input-name", "P4 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON11, N_p("input-name", "P4 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON12, N_p("input-name", "P4 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON13, N_p("input-name", "P4 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON14, N_p("input-name", "P4 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON15, N_p("input-name", "P4 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON16, N_p("input-name", "P4 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, START, N_p("input-name", "P4 Start"), input_seq(KEYCODE_4, input_seq::or_code, JOYCODE_START_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, SELECT, N_p("input-name", "P4 Select"), input_seq(KEYCODE_8, input_seq::or_code, JOYCODE_SELECT_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_8_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_2_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_4_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_6_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_0_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_DEL_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_ENTER_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_4) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_8) ) \ + CORE_INPUT_TYPES_END() + +#define CORE_INPUT_TYPES_P4_MAHJONG \ + CORE_INPUT_TYPES_BEGIN(p4_mahjong) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(3)) ) \ + INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(3)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P5 \ CORE_INPUT_TYPES_BEGIN(p5) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_UP, N_p("input-name", "P5 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_DOWN, N_p("input-name", "P5 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_LEFT, N_p("input-name", "P5 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_RIGHT, N_p("input-name", "P5 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_UP, N_p("input-name", "P5 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_DOWN, N_p("input-name", "P5 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_LEFT, N_p("input-name", "P5 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P5 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_UP, N_p("input-name", "P5 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_DOWN, N_p("input-name", "P5 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_LEFT, N_p("input-name", "P5 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_RIGHT, N_p("input-name", "P5 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON1, N_p("input-name", "P5 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON2, N_p("input-name", "P5 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON3, N_p("input-name", "P5 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON4, N_p("input-name", "P5 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON5, N_p("input-name", "P5 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON6, N_p("input-name", "P5 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON7, N_p("input-name", "P5 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON8, N_p("input-name", "P5 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON9, N_p("input-name", "P5 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON10, N_p("input-name", "P5 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON11, N_p("input-name", "P5 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON12, N_p("input-name", "P5 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON13, N_p("input-name", "P5 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON14, N_p("input-name", "P5 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON15, N_p("input-name", "P5 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON16, N_p("input-name", "P5 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(4)) ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, START, N_p("input-name", "P5 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, SELECT, N_p("input-name", "P5 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P6 \ CORE_INPUT_TYPES_BEGIN(p6) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_UP, N_p("input-name", "P6 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_DOWN, N_p("input-name", "P6 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_LEFT, N_p("input-name", "P6 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_RIGHT, N_p("input-name", "P6 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_UP, N_p("input-name", "P6 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_DOWN, N_p("input-name", "P6 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_LEFT, N_p("input-name", "P6 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P6 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_UP, N_p("input-name", "P6 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_DOWN, N_p("input-name", "P6 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_LEFT, N_p("input-name", "P6 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_RIGHT, N_p("input-name", "P6 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON1, N_p("input-name", "P6 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON2, N_p("input-name", "P6 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON3, N_p("input-name", "P6 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON4, N_p("input-name", "P6 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON5, N_p("input-name", "P6 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON6, N_p("input-name", "P6 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON7, N_p("input-name", "P6 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON8, N_p("input-name", "P6 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON9, N_p("input-name", "P6 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON10, N_p("input-name", "P6 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON11, N_p("input-name", "P6 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON12, N_p("input-name", "P6 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON13, N_p("input-name", "P6 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON14, N_p("input-name", "P6 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON15, N_p("input-name", "P6 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON16, N_p("input-name", "P6 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(5)) ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, START, N_p("input-name", "P6 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, SELECT, N_p("input-name", "P6 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P7 \ CORE_INPUT_TYPES_BEGIN(p7) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_UP, N_p("input-name", "P7 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_DOWN, N_p("input-name", "P7 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_LEFT, N_p("input-name", "P7 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_RIGHT, N_p("input-name", "P7 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_UP, N_p("input-name", "P7 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_DOWN, N_p("input-name", "P7 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_LEFT, N_p("input-name", "P7 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P7 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_UP, N_p("input-name", "P7 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_DOWN, N_p("input-name", "P7 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_LEFT, N_p("input-name", "P7 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_RIGHT, N_p("input-name", "P7 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON1, N_p("input-name", "P7 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON2, N_p("input-name", "P7 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON3, N_p("input-name", "P7 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON4, N_p("input-name", "P7 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON5, N_p("input-name", "P7 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON6, N_p("input-name", "P7 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON7, N_p("input-name", "P7 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON8, N_p("input-name", "P7 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON9, N_p("input-name", "P7 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON10, N_p("input-name", "P7 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON11, N_p("input-name", "P7 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON12, N_p("input-name", "P7 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON13, N_p("input-name", "P7 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON14, N_p("input-name", "P7 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON15, N_p("input-name", "P7 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON16, N_p("input-name", "P7 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(6)) ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, START, N_p("input-name", "P7 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, SELECT, N_p("input-name", "P7 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P8 \ CORE_INPUT_TYPES_BEGIN(p8) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_UP, N_p("input-name", "P8 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_DOWN, N_p("input-name", "P8 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_LEFT, N_p("input-name", "P8 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_RIGHT, N_p("input-name", "P8 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_UP, N_p("input-name", "P8 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_DOWN, N_p("input-name", "P8 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_LEFT, N_p("input-name", "P8 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P8 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_UP, N_p("input-name", "P8 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_DOWN, N_p("input-name", "P8 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_LEFT, N_p("input-name", "P8 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_RIGHT, N_p("input-name", "P8 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON1, N_p("input-name", "P8 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON2, N_p("input-name", "P8 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON3, N_p("input-name", "P8 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON4, N_p("input-name", "P8 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON5, N_p("input-name", "P8 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON6, N_p("input-name", "P8 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON7, N_p("input-name", "P8 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON8, N_p("input-name", "P8 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON9, N_p("input-name", "P8 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON10, N_p("input-name", "P8 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON11, N_p("input-name", "P8 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON12, N_p("input-name", "P8 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON13, N_p("input-name", "P8 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON14, N_p("input-name", "P8 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON15, N_p("input-name", "P8 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON16, N_p("input-name", "P8 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(7)) ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, START, N_p("input-name", "P8 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, SELECT, N_p("input-name", "P8 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P9 \ CORE_INPUT_TYPES_BEGIN(p9) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_UP, N_p("input-name", "P9 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_DOWN, N_p("input-name", "P9 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_LEFT, N_p("input-name", "P9 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_RIGHT, N_p("input-name", "P9 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_UP, N_p("input-name", "P9 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_DOWN, N_p("input-name", "P9 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_LEFT, N_p("input-name", "P9 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P9 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_UP, N_p("input-name", "P9 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_DOWN, N_p("input-name", "P9 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_LEFT, N_p("input-name", "P9 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_RIGHT, N_p("input-name", "P9 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON1, N_p("input-name", "P9 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON2, N_p("input-name", "P9 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON3, N_p("input-name", "P9 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON4, N_p("input-name", "P9 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON5, N_p("input-name", "P9 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON6, N_p("input-name", "P9 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON7, N_p("input-name", "P9 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON8, N_p("input-name", "P9 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON9, N_p("input-name", "P9 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON10, N_p("input-name", "P9 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON11, N_p("input-name", "P9 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON12, N_p("input-name", "P9 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON13, N_p("input-name", "P9 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON14, N_p("input-name", "P9 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON15, N_p("input-name", "P9 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON16, N_p("input-name", "P9 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(8)) ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, START, N_p("input-name", "P9 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, SELECT, N_p("input-name", "P9 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_P10 \ CORE_INPUT_TYPES_BEGIN(p10) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_UP, N_p("input-name", "P10 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_DOWN, N_p("input-name", "P10 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_LEFT, N_p("input-name", "P10 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_RIGHT, N_p("input-name", "P10 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_UP, N_p("input-name", "P10 Right Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_DOWN, N_p("input-name", "P10 Right Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_LEFT, N_p("input-name", "P10 Right Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P10 Right Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_UP, N_p("input-name", "P10 Left Stick/Up"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_DOWN, N_p("input-name", "P10 Left Stick/Down"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_LEFT, N_p("input-name", "P10 Left Stick/Left"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_RIGHT, N_p("input-name", "P10 Left Stick/Right"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON1, N_p("input-name", "P10 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON2, N_p("input-name", "P10 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON3, N_p("input-name", "P10 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON4, N_p("input-name", "P10 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON5, N_p("input-name", "P10 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON6, N_p("input-name", "P10 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON7, N_p("input-name", "P10 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON8, N_p("input-name", "P10 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON9, N_p("input-name", "P10 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON10, N_p("input-name", "P10 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON11, N_p("input-name", "P10 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON12, N_p("input-name", "P10 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON13, N_p("input-name", "P10 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON14, N_p("input-name", "P10 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON15, N_p("input-name", "P10 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON16, N_p("input-name", "P10 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(9)) ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, START, N_p("input-name", "P10 Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, SELECT, N_p("input-name", "P10 Select"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, START, N_p("input-name", "%p Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, SELECT, N_p("input-name", "%p Select"), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_START \ @@ -494,10 +560,10 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START2, N_p("input-name", "2 Players Start"), input_seq(KEYCODE_2, input_seq::or_code, JOYCODE_START_INDEXED(1)) ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START3, N_p("input-name", "3 Players Start"), input_seq(KEYCODE_3, input_seq::or_code, JOYCODE_START_INDEXED(2)) ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START4, N_p("input-name", "4 Players Start"), input_seq(KEYCODE_4, input_seq::or_code, JOYCODE_START_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START5, N_p("input-name", "5 Players Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START6, N_p("input-name", "6 Players Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START7, N_p("input-name", "7 Players Start"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START8, N_p("input-name", "8 Players Start"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START5, N_p("input-name", "5 Players Start"), input_seq(JOYCODE_START_INDEXED(4)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START6, N_p("input-name", "6 Players Start"), input_seq(JOYCODE_START_INDEXED(5)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START7, N_p("input-name", "7 Players Start"), input_seq(JOYCODE_START_INDEXED(6)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START8, N_p("input-name", "8 Players Start"), input_seq(JOYCODE_START_INDEXED(7)) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_COIN \ @@ -506,15 +572,15 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN2, N_p("input-name", "Coin 2"), input_seq(KEYCODE_6, input_seq::or_code, JOYCODE_SELECT_INDEXED(1)) ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN3, N_p("input-name", "Coin 3"), input_seq(KEYCODE_7, input_seq::or_code, JOYCODE_SELECT_INDEXED(2)) ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN4, N_p("input-name", "Coin 4"), input_seq(KEYCODE_8, input_seq::or_code, JOYCODE_SELECT_INDEXED(3)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN5, N_p("input-name", "Coin 5"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN6, N_p("input-name", "Coin 6"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN7, N_p("input-name", "Coin 7"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN8, N_p("input-name", "Coin 8"), input_seq() ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN5, N_p("input-name", "Coin 5"), input_seq(JOYCODE_SELECT_INDEXED(4)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN6, N_p("input-name", "Coin 6"), input_seq(JOYCODE_SELECT_INDEXED(5)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN7, N_p("input-name", "Coin 7"), input_seq(JOYCODE_SELECT_INDEXED(6)) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN8, N_p("input-name", "Coin 8"), input_seq(JOYCODE_SELECT_INDEXED(7)) ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN9, N_p("input-name", "Coin 9"), input_seq() ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN10, N_p("input-name", "Coin 10"), input_seq() ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN11, N_p("input-name", "Coin 11"), input_seq() ) \ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN12, N_p("input-name", "Coin 12"), input_seq() ) \ - INPUT_PORT_DIGITAL_TYPE( 0, OTHER, BILL1, N_p("input-name", "Bill 1"), input_seq(KEYCODE_BACKSPACE) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, OTHER, BILL1, N_p("input-name", "Banknote 1"), input_seq(KEYCODE_BACKSPACE) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_SERVICE \ @@ -547,226 +613,226 @@ namespace { #define CORE_INPUT_TYPES_PEDAL \ CORE_INPUT_TYPES_BEGIN(pedal) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL, N_p("input-name", "P1 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0)) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL, N_p("input-name", "P2 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_A, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(1)) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL, N_p("input-name", "P3 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(2)) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL, N_p("input-name", "P4 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_0_PAD, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(3)) ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL, N_p("input-name", "P5 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(4)) ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL, N_p("input-name", "P6 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(5)) ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL, N_p("input-name", "P7 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(6)) ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL, N_p("input-name", "P8 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(7)) ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL, N_p("input-name", "P9 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(8)) ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL, N_p("input-name", "P10 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(9)) ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_LCONTROL) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_A) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_RCONTROL) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_0_PAD) ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_PEDAL2 \ CORE_INPUT_TYPES_BEGIN(pedal2) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, N_p("input-name", "P1 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, N_p("input-name", "P2 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, N_p("input-name", "P3 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, N_p("input-name", "P4 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, N_p("input-name", "P5 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, N_p("input-name", "P6 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, N_p("input-name", "P7 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, N_p("input-name", "P8 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, N_p("input-name", "P9 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, N_p("input-name", "P10 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_LALT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_S) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_RSHIFT) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_DEL_PAD) ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_PEDAL3 \ CORE_INPUT_TYPES_BEGIN(pedal3) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL3, N_p("input-name", "P1 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_SPACE, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0)) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL3, N_p("input-name", "P2 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_Q, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(1)) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL3, N_p("input-name", "P3 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(2)) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL3, N_p("input-name", "P4 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER_PAD, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(3)) ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL3, N_p("input-name", "P5 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(4)) ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL3, N_p("input-name", "P6 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(5)) ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL3, N_p("input-name", "P7 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(6)) ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL3, N_p("input-name", "P8 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(7)) ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL3, N_p("input-name", "P9 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(8)) ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL3, N_p("input-name", "P10 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(9)) ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_SPACE) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_Q) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER_PAD) ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_PADDLE \ CORE_INPUT_TYPES_BEGIN(paddle) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE, N_p("input-name", "Paddle"), input_seq(JOYCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE, N_p("input-name", "Paddle 2"), input_seq(JOYCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE, N_p("input-name", "Paddle 3"), input_seq(JOYCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE, N_p("input-name", "Paddle 4"), input_seq(JOYCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE, N_p("input-name", "Paddle 5"), input_seq(JOYCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE, N_p("input-name", "Paddle 6"), input_seq(JOYCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE, N_p("input-name", "Paddle 7"), input_seq(JOYCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE, N_p("input-name", "Paddle 8"), input_seq(JOYCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE, N_p("input-name", "Paddle 9"), input_seq(JOYCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE, N_p("input-name", "Paddle 10"), input_seq(JOYCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE, N_p("input-name", "Paddle"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE, N_p("input-name", "Paddle 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE, N_p("input-name", "Paddle 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE, N_p("input-name", "Paddle 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE, N_p("input-name", "Paddle 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE, N_p("input-name", "Paddle 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE, N_p("input-name", "Paddle 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE, N_p("input-name", "Paddle 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE, N_p("input-name", "Paddle 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE, N_p("input-name", "Paddle 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_PADDLE_V \ CORE_INPUT_TYPES_BEGIN(paddle_v) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE_V, N_p("input-name", "Paddle V"), input_seq(JOYCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE_V, N_p("input-name", "Paddle V 2"), input_seq(JOYCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE_V, N_p("input-name", "Paddle V 3"), input_seq(JOYCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE_V, N_p("input-name", "Paddle V 4"), input_seq(JOYCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE_V, N_p("input-name", "Paddle V 5"), input_seq(JOYCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE_V, N_p("input-name", "Paddle V 6"), input_seq(JOYCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, N_p("input-name", "Paddle V 7"), input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, N_p("input-name", "Paddle V 8"), input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, N_p("input-name", "Paddle V 9"), input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, N_p("input-name", "Paddle V 10"), input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE_V, N_p("input-name", "Paddle V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE_V, N_p("input-name", "Paddle V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE_V, N_p("input-name", "Paddle V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE_V, N_p("input-name", "Paddle V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE_V, N_p("input-name", "Paddle V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE_V, N_p("input-name", "Paddle V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, N_p("input-name", "Paddle V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, N_p("input-name", "Paddle V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, N_p("input-name", "Paddle V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, N_p("input-name", "Paddle V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_POSITIONAL \ CORE_INPUT_TYPES_BEGIN(positional) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL, N_p("input-name", "Positional"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL, N_p("input-name", "Positional 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL, N_p("input-name", "Positional 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL, N_p("input-name", "Positional 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL, N_p("input-name", "Positional 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL, N_p("input-name", "Positional 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL, N_p("input-name", "Positional 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL, N_p("input-name", "Positional 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL, N_p("input-name", "Positional 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL, N_p("input-name", "Positional 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL, N_p("input-name", "Positional"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL, N_p("input-name", "Positional 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL, N_p("input-name", "Positional 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL, N_p("input-name", "Positional 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL, N_p("input-name", "Positional 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL, N_p("input-name", "Positional 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL, N_p("input-name", "Positional 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL, N_p("input-name", "Positional 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL, N_p("input-name", "Positional 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL, N_p("input-name", "Positional 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_POSITIONAL_V \ CORE_INPUT_TYPES_BEGIN(positional_v) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL_V, N_p("input-name", "Positional V"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL_V, N_p("input-name", "Positional V 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL_V, N_p("input-name", "Positional V 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL_V, N_p("input-name", "Positional V 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL_V, N_p("input-name", "Positional V 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL_V, N_p("input-name", "Positional V 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL_V, N_p("input-name", "Positional V 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL_V, N_p("input-name", "Positional V 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL_V, N_p("input-name", "Positional V 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL_V, N_p("input-name", "Positional V 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL_V, N_p("input-name", "Positional V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL_V, N_p("input-name", "Positional V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL_V, N_p("input-name", "Positional V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL_V, N_p("input-name", "Positional V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL_V, N_p("input-name", "Positional V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL_V, N_p("input-name", "Positional V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL_V, N_p("input-name", "Positional V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL_V, N_p("input-name", "Positional V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL_V, N_p("input-name", "Positional V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL_V, N_p("input-name", "Positional V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_DIAL \ CORE_INPUT_TYPES_BEGIN(dial) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL, N_p("input-name", "Dial"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL, N_p("input-name", "Dial 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL, N_p("input-name", "Dial 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL, N_p("input-name", "Dial 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL, N_p("input-name", "Dial 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL, N_p("input-name", "Dial 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL, N_p("input-name", "Dial 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL, N_p("input-name", "Dial 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL, N_p("input-name", "Dial 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL, N_p("input-name", "Dial 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL, N_p("input-name", "Dial"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL, N_p("input-name", "Dial 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL, N_p("input-name", "Dial 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL, N_p("input-name", "Dial 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL, N_p("input-name", "Dial 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL, N_p("input-name", "Dial 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL, N_p("input-name", "Dial 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL, N_p("input-name", "Dial 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL, N_p("input-name", "Dial 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL, N_p("input-name", "Dial 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_DIAL_V \ CORE_INPUT_TYPES_BEGIN(dial_v) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL_V, N_p("input-name", "Dial V"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL_V, N_p("input-name", "Dial V 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL_V, N_p("input-name", "Dial V 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL_V, N_p("input-name", "Dial V 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL_V, N_p("input-name", "Dial V 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL_V, N_p("input-name", "Dial V 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL_V, N_p("input-name", "Dial V 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL_V, N_p("input-name", "Dial V 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL_V, N_p("input-name", "Dial V 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL_V, N_p("input-name", "Dial V 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL_V, N_p("input-name", "Dial V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL_V, N_p("input-name", "Dial V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL_V, N_p("input-name", "Dial V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL_V, N_p("input-name", "Dial V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL_V, N_p("input-name", "Dial V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL_V, N_p("input-name", "Dial V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL_V, N_p("input-name", "Dial V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL_V, N_p("input-name", "Dial V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL_V, N_p("input-name", "Dial V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL_V, N_p("input-name", "Dial V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_TRACKBALL_X \ CORE_INPUT_TYPES_BEGIN(trackball_x) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_X, N_p("input-name", "Track X"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_X, N_p("input-name", "Track X 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_X, N_p("input-name", "Track X 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_X, N_p("input-name", "Track X 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_X, N_p("input-name", "Track X 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_X, N_p("input-name", "Track X 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_X, N_p("input-name", "Track X 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_X, N_p("input-name", "Track X 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_X, N_p("input-name", "Track X 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_X, N_p("input-name", "Track X 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_X, N_p("input-name", "Trackball X"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_X, N_p("input-name", "Trackball X 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_X, N_p("input-name", "Trackball X 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_X, N_p("input-name", "Trackball X 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_X, N_p("input-name", "Trackball X 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_X, N_p("input-name", "Trackball X 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_X, N_p("input-name", "Trackball X 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_X, N_p("input-name", "Trackball X 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_X, N_p("input-name", "Trackball X 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_X, N_p("input-name", "Trackball X 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_TRACKBALL_Y \ CORE_INPUT_TYPES_BEGIN(trackball_y) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_Y, N_p("input-name", "Track Y"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_Y, N_p("input-name", "Track Y 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_Y, N_p("input-name", "Track Y 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_Y, N_p("input-name", "Track Y 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_Y, N_p("input-name", "Track Y 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_Y, N_p("input-name", "Track Y 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_Y, N_p("input-name", "Track Y 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_Y, N_p("input-name", "Track Y 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_Y, N_p("input-name", "Track Y 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_Y, N_p("input-name", "Track Y 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_Y, N_p("input-name", "Trackball Y"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_Y, N_p("input-name", "Trackball Y 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_Y, N_p("input-name", "Trackball Y 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_Y, N_p("input-name", "Trackball Y 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_Y, N_p("input-name", "Trackball Y 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_Y, N_p("input-name", "Trackball Y 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_Y, N_p("input-name", "Trackball Y 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_Y, N_p("input-name", "Trackball Y 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_Y, N_p("input-name", "Trackball Y 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_Y, N_p("input-name", "Trackball Y 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_AD_STICK_X \ CORE_INPUT_TYPES_BEGIN(ad_stick_x) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_X, N_p("input-name", "AD Stick X"), input_seq(JOYCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_X, N_p("input-name", "AD Stick X 2"), input_seq(JOYCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_X, N_p("input-name", "AD Stick X 3"), input_seq(JOYCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_X, N_p("input-name", "AD Stick X 4"), input_seq(JOYCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_X, N_p("input-name", "AD Stick X 5"), input_seq(JOYCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_X, N_p("input-name", "AD Stick X 6"), input_seq(JOYCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_X, N_p("input-name", "AD Stick X 7"), input_seq(JOYCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_X, N_p("input-name", "AD Stick X 8"), input_seq(JOYCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_X, N_p("input-name", "AD Stick X 9"), input_seq(JOYCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_X, N_p("input-name", "AD Stick X 10"), input_seq(JOYCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_X, N_p("input-name", "AD Stick X"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_X, N_p("input-name", "AD Stick X 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_X, N_p("input-name", "AD Stick X 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_X, N_p("input-name", "AD Stick X 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_X, N_p("input-name", "AD Stick X 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_X, N_p("input-name", "AD Stick X 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_X, N_p("input-name", "AD Stick X 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_X, N_p("input-name", "AD Stick X 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_X, N_p("input-name", "AD Stick X 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_X, N_p("input-name", "AD Stick X 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_AD_STICK_Y \ CORE_INPUT_TYPES_BEGIN(ad_stick_y) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Y, N_p("input-name", "AD Stick Y"), input_seq(JOYCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Y, N_p("input-name", "AD Stick Y 2"), input_seq(JOYCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Y, N_p("input-name", "AD Stick Y 3"), input_seq(JOYCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Y, N_p("input-name", "AD Stick Y 4"), input_seq(JOYCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Y, N_p("input-name", "AD Stick Y 5"), input_seq(JOYCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Y, N_p("input-name", "AD Stick Y 6"), input_seq(JOYCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Y, N_p("input-name", "AD Stick Y 7"), input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Y, N_p("input-name", "AD Stick Y 8"), input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Y, N_p("input-name", "AD Stick Y 9"), input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Y, N_p("input-name", "AD Stick Y 10"), input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Y, N_p("input-name", "AD Stick Y"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Y, N_p("input-name", "AD Stick Y 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Y, N_p("input-name", "AD Stick Y 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Y, N_p("input-name", "AD Stick Y 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Y, N_p("input-name", "AD Stick Y 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Y, N_p("input-name", "AD Stick Y 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Y, N_p("input-name", "AD Stick Y 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Y, N_p("input-name", "AD Stick Y 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Y, N_p("input-name", "AD Stick Y 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Y, N_p("input-name", "AD Stick Y 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_AD_STICK_Z \ CORE_INPUT_TYPES_BEGIN(ad_stick_z) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Z, N_p("input-name", "AD Stick Z"), input_seq(JOYCODE_Z_INDEXED(0)), input_seq(KEYCODE_A), input_seq(KEYCODE_Z) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Z, N_p("input-name", "AD Stick Z 2"), input_seq(JOYCODE_Z_INDEXED(1)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Z, N_p("input-name", "AD Stick Z 3"), input_seq(JOYCODE_Z_INDEXED(2)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Z, N_p("input-name", "AD Stick Z 4"), input_seq(JOYCODE_Z_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Z, N_p("input-name", "AD Stick Z 5"), input_seq(JOYCODE_Z_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Z, N_p("input-name", "AD Stick Z 6"), input_seq(JOYCODE_Z_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Z, N_p("input-name", "AD Stick Z 7"), input_seq(JOYCODE_Z_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Z, N_p("input-name", "AD Stick Z 8"), input_seq(JOYCODE_Z_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Z, N_p("input-name", "AD Stick Z 9"), input_seq(JOYCODE_Z_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Z, N_p("input-name", "AD Stick Z 10"), input_seq(JOYCODE_Z_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Z, N_p("input-name", "AD Stick Z"), input_seq(), input_seq(KEYCODE_A), input_seq(KEYCODE_Z) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Z, N_p("input-name", "AD Stick Z 2"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Z, N_p("input-name", "AD Stick Z 3"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Z, N_p("input-name", "AD Stick Z 4"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Z, N_p("input-name", "AD Stick Z 5"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Z, N_p("input-name", "AD Stick Z 6"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Z, N_p("input-name", "AD Stick Z 7"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Z, N_p("input-name", "AD Stick Z 8"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Z, N_p("input-name", "AD Stick Z 9"), input_seq(), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Z, N_p("input-name", "AD Stick Z 10"), input_seq(), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_LIGHTGUN_X \ CORE_INPUT_TYPES_BEGIN(lightgun_x) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_X, N_p("input-name", "Lightgun X"), input_seq(GUNCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_X, N_p("input-name", "Lightgun X 2"), input_seq(GUNCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_X, N_p("input-name", "Lightgun X 3"), input_seq(GUNCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_X, N_p("input-name", "Lightgun X 4"), input_seq(GUNCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_X, N_p("input-name", "Lightgun X 5"), input_seq(GUNCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_X, N_p("input-name", "Lightgun X 6"), input_seq(GUNCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_X, N_p("input-name", "Lightgun X 7"), input_seq(GUNCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_X, N_p("input-name", "Lightgun X 8"), input_seq(GUNCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_X, N_p("input-name", "Lightgun X 9"), input_seq(GUNCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_X, N_p("input-name", "Lightgun X 10"), input_seq(GUNCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_X, N_p("input-name", "Lightgun X"), input_seq(GUNCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_X, N_p("input-name", "Lightgun X 2"), input_seq(GUNCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_X, N_p("input-name", "Lightgun X 3"), input_seq(GUNCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_X, N_p("input-name", "Lightgun X 4"), input_seq(GUNCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_X, N_p("input-name", "Lightgun X 5"), input_seq(GUNCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_X, N_p("input-name", "Lightgun X 6"), input_seq(GUNCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_X, N_p("input-name", "Lightgun X 7"), input_seq(GUNCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_X, N_p("input-name", "Lightgun X 8"), input_seq(GUNCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_X, N_p("input-name", "Lightgun X 9"), input_seq(GUNCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_X, N_p("input-name", "Lightgun X 10"), input_seq(GUNCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_LIGHTGUN_Y \ CORE_INPUT_TYPES_BEGIN(lightgun_y) \ - INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_Y, N_p("input-name", "Lightgun Y"), input_seq(GUNCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ - INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 2"), input_seq(GUNCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ - INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 3"), input_seq(GUNCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ - INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 4"), input_seq(GUNCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 5"), input_seq(GUNCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 6"), input_seq(GUNCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 7"), input_seq(GUNCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 8"), input_seq(GUNCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 9"), input_seq(GUNCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ - INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 10"), input_seq(GUNCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_Y, N_p("input-name", "Lightgun Y"), input_seq(GUNCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 2"), input_seq(GUNCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \ + INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 3"), input_seq(GUNCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \ + INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 4"), input_seq(GUNCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 5"), input_seq(GUNCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 6"), input_seq(GUNCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 7"), input_seq(GUNCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 8"), input_seq(GUNCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 9"), input_seq(GUNCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \ + INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 10"), input_seq(GUNCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_MOUSE_X \ @@ -805,16 +871,36 @@ namespace { #define CORE_INPUT_TYPES_UI \ CORE_INPUT_TYPES_BEGIN(ui) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY, N_p("input-name", "On Screen Display"), input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, N_p("input-name", "Break in Debugger"), input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CONFIGURE, N_p("input-name", "Config Menu"), input_seq(KEYCODE_TAB) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE, N_p("input-name", "Pause"), input_seq(KEYCODE_P, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, N_p("input-name", "Pause - Single Step"), input_seq(KEYCODE_P, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_P, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_REWIND_SINGLE, N_p("input-name", "Rewind - Single Step"), input_seq(KEYCODE_TILDE, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_MENU, N_p("input-name", "Show/Hide Menu"), input_seq(KEYCODE_TAB) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT, input_seq::or_code, KEYCODE_ENTER_PAD) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_BACK, N_p("input-name", "UI Back"), input_seq(KEYCODE_ESC) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, N_p("input-name", "UI Cancel"), input_seq(KEYCODE_ESC) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CLEAR, N_p("input-name", "UI Clear"), input_seq(KEYCODE_DEL) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HELP, N_p("input-name", "UI Help"), input_seq(KEYCODE_F1) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_UP, N_p("input-name", "UI Up"), input_seq(KEYCODE_UP) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DOWN, N_p("input-name", "UI Down"), input_seq(KEYCODE_DOWN) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LEFT, N_p("input-name", "UI Left"), input_seq(KEYCODE_LEFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RIGHT, N_p("input-name", "UI Right"), input_seq(KEYCODE_RIGHT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HOME, N_p("input-name", "UI Home"), input_seq(KEYCODE_HOME) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_END, N_p("input-name", "UI End"), input_seq(KEYCODE_END) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_UP, N_p("input-name", "UI Page Up"), input_seq(KEYCODE_PGUP) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, N_p("input-name", "UI Page Down"), input_seq(KEYCODE_PGDN) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PREV_GROUP, N_p("input-name", "UI Previous Group"), input_seq(KEYCODE_OPENBRACE) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_NEXT_GROUP, N_p("input-name", "UI Next Group"), input_seq(KEYCODE_CLOSEBRACE) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY, N_p("input-name", "On Screen Display"), input_seq(KEYCODE_TILDE) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "Toggle UI Controls"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, N_p("input-name", "Break in Debugger"), input_seq(KEYCODE_TILDE) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE, N_p("input-name", "Pause"), input_seq(KEYCODE_F5, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, N_p("input-name", "Pause - Single Step"), input_seq(KEYCODE_F5, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F5, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_REWIND_SINGLE, N_p("input-name", "Rewind - Single Step"), input_seq(KEYCODE_F4, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F4, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F6, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE_QUICK, N_p("input-name", "Quick Save State"), input_seq(KEYCODE_F6, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F6, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE_QUICK, N_p("input-name", "Quick Load State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RESET_MACHINE, N_p("input-name", "Reset Machine"), input_seq(KEYCODE_F3, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F3, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SOFT_RESET, N_p("input-name", "Soft Reset"), input_seq(KEYCODE_F3, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_GFX, N_p("input-name", "Show Decoded Graphics"), input_seq(KEYCODE_F4) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_DEC, N_p("input-name", "Frameskip Dec"), input_seq(KEYCODE_F8) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_GFX, N_p("input-name", "Show Decoded Graphics"), input_seq(KEYCODE_F4, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_DEC, N_p("input-name", "Frameskip Dec"), input_seq(KEYCODE_F8, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_INC, N_p("input-name", "Frameskip Inc"), input_seq(KEYCODE_F9) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_THROTTLE, N_p("input-name", "Throttle"), input_seq(KEYCODE_F10) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAST_FORWARD, N_p("input-name", "Fast Forward"), input_seq(KEYCODE_INSERT) ) \ @@ -822,37 +908,21 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SNAPSHOT, N_p("input-name", "Save Snapshot"), input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_MNG, N_p("input-name", "Record MNG"), input_seq(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LCONTROL) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_AVI, N_p("input-name", "Record AVI"), input_seq(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_CHEAT, N_p("input-name", "Toggle Cheat"), input_seq(KEYCODE_F6) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_UP, N_p("input-name", "UI Up"), input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DOWN, N_p("input-name", "UI Down"), input_seq(KEYCODE_DOWN, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LEFT, N_p("input-name", "UI Left"), input_seq(KEYCODE_LEFT, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RIGHT, N_p("input-name", "UI Right"), input_seq(KEYCODE_RIGHT, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HOME, N_p("input-name", "UI Home"), input_seq(KEYCODE_HOME) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_END, N_p("input-name", "UI End"), input_seq(KEYCODE_END) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_UP, N_p("input-name", "UI Page Up"), input_seq(KEYCODE_PGUP) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, N_p("input-name", "UI Page Down"), input_seq(KEYCODE_PGDN) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, N_p("input-name", "UI Focus Next"), input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, N_p("input-name", "UI Focus Previous"), input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, KEYCODE_ENTER_PAD) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, N_p("input-name", "UI Cancel"), input_seq(KEYCODE_ESC) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_CHEAT, N_p("input-name", "Toggle Cheat"), input_seq(KEYCODE_F8, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F8, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DISPLAY_COMMENT, N_p("input-name", "UI Display Comment"), input_seq(KEYCODE_SPACE) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CLEAR, N_p("input-name", "UI Clear"), input_seq(KEYCODE_DEL) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_IN, N_p("input-name", "UI Zoom In"), input_seq(KEYCODE_EQUALS) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_OUT, N_p("input-name", "UI Zoom Out"), input_seq(KEYCODE_MINUS) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_DEFAULT, N_p("input-name", "UI Default Zoom"), input_seq(KEYCODE_0) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PREV_GROUP, N_p("input-name", "UI Previous Group"), input_seq(KEYCODE_OPENBRACE) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_NEXT_GROUP, N_p("input-name", "UI Next Group"), input_seq(KEYCODE_CLOSEBRACE) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ROTATE, N_p("input-name", "UI Rotate"), input_seq(KEYCODE_R) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_PROFILER, N_p("input-name", "Show Profiler"), input_seq(KEYCODE_F11, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "UI Toggle"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RELEASE_POINTER, N_p("input-name", "UI Release Pointer"), input_seq(KEYCODE_RCONTROL, KEYCODE_RALT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_SCRLOCK, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_START, N_p("input-name", "UI (First) Tape Start"), input_seq(KEYCODE_F2, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_STOP, N_p("input-name", "UI (First) Tape Stop"), input_seq(KEYCODE_F2, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, N_p("input-name", "UI Focus Next"), input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, N_p("input-name", "UI Focus Previous"), input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DATS, N_p("input-name", "UI External DAT View"), input_seq(KEYCODE_LALT, KEYCODE_D) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAVORITES, N_p("input-name", "UI Add/Remove favorite"), input_seq(KEYCODE_LALT, KEYCODE_F) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAVORITES, N_p("input-name", "UI Add/Remove Favorite"), input_seq(KEYCODE_LALT, KEYCODE_F) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_EXPORT, N_p("input-name", "UI Export List"), input_seq(KEYCODE_LALT, KEYCODE_E) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_AUDIT, N_p("input-name", "UI Audit Media"), input_seq(KEYCODE_F1, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ CORE_INPUT_TYPES_END() @@ -920,7 +990,9 @@ CORE_INPUT_TYPES_P2 CORE_INPUT_TYPES_P2_MAHJONG CORE_INPUT_TYPES_P2_HANAFUDA CORE_INPUT_TYPES_P3 +CORE_INPUT_TYPES_P3_MAHJONG CORE_INPUT_TYPES_P4 +CORE_INPUT_TYPES_P4_MAHJONG CORE_INPUT_TYPES_P5 CORE_INPUT_TYPES_P6 CORE_INPUT_TYPES_P7 @@ -978,7 +1050,9 @@ constexpr size_t core_input_types_count() CORE_INPUT_TYPES_P2_MAHJONG CORE_INPUT_TYPES_P2_HANAFUDA CORE_INPUT_TYPES_P3 + CORE_INPUT_TYPES_P3_MAHJONG CORE_INPUT_TYPES_P4 + CORE_INPUT_TYPES_P4_MAHJONG CORE_INPUT_TYPES_P5 CORE_INPUT_TYPES_P6 CORE_INPUT_TYPES_P7 @@ -1034,7 +1108,9 @@ ATTR_COLD inline void emplace_core_types(std::vector<input_type_entry> &typelist emplace_core_types_p2_mahjong(typelist); emplace_core_types_p2_hanafuda(typelist); emplace_core_types_p3(typelist); + emplace_core_types_p3_mahjong(typelist); emplace_core_types_p4(typelist); + emplace_core_types_p4_mahjong(typelist); emplace_core_types_p5(typelist); emplace_core_types_p6(typelist); emplace_core_types_p7(typelist); diff --git a/src/emu/input.cpp b/src/emu/input.cpp index 5c49d1c2dab..9e82f290bf7 100644 --- a/src/emu/input.cpp +++ b/src/emu/input.cpp @@ -24,20 +24,7 @@ -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// additional expanded input codes for sequences -constexpr input_code input_seq::end_code; -constexpr input_code input_seq::default_code; -constexpr input_code input_seq::not_code; -constexpr input_code input_seq::or_code; - -// constant sequences -const input_seq input_seq::empty_seq; - - +namespace { //************************************************************************** // TYPE DEFINITIONS @@ -64,8 +51,8 @@ struct code_string_table return nullptr; } - u32 m_code; - const char * m_string; + u32 m_code; + const char * m_string; }; @@ -75,7 +62,7 @@ struct code_string_table //************************************************************************** // token strings for device classes -static const code_string_table devclass_token_table[] = +const code_string_table devclass_token_table[] = { { DEVICE_CLASS_KEYBOARD, "KEYCODE" }, { DEVICE_CLASS_MOUSE, "MOUSECODE" }, @@ -85,7 +72,7 @@ static const code_string_table devclass_token_table[] = }; // friendly strings for device classes -static const code_string_table devclass_string_table[] = +const code_string_table devclass_string_table[] = { { DEVICE_CLASS_KEYBOARD, "Kbd" }, { DEVICE_CLASS_MOUSE, "Mouse" }, @@ -95,7 +82,7 @@ static const code_string_table devclass_string_table[] = }; // token strings for item modifiers -static const code_string_table modifier_token_table[] = +const code_string_table modifier_token_table[] = { { ITEM_MODIFIER_REVERSE, "REVERSE" }, { ITEM_MODIFIER_POS, "POS" }, @@ -108,7 +95,7 @@ static const code_string_table modifier_token_table[] = }; // friendly strings for item modifiers -static const code_string_table modifier_string_table[] = +const code_string_table modifier_string_table[] = { { ITEM_MODIFIER_REVERSE, "Reverse" }, { ITEM_MODIFIER_POS, "+" }, @@ -121,7 +108,7 @@ static const code_string_table modifier_string_table[] = }; // token strings for item classes -static const code_string_table itemclass_token_table[] = +const code_string_table itemclass_token_table[] = { { ITEM_CLASS_SWITCH, "SWITCH" }, { ITEM_CLASS_ABSOLUTE, "ABSOLUTE" }, @@ -130,7 +117,7 @@ static const code_string_table itemclass_token_table[] = }; // token strings for standard item ids -static const code_string_table itemid_token_table[] = +const code_string_table itemid_token_table[] = { // standard keyboard codes { ITEM_ID_A, "A" }, @@ -370,183 +357,44 @@ static const code_string_table itemid_token_table[] = //************************************************************************** -// INPUT SEQ +// UTILITY FUNCTIONS //************************************************************************** -//------------------------------------------------- -// operator+= - append a code to the end of an -// input sequence -//------------------------------------------------- - -input_seq &input_seq::operator+=(input_code code) noexcept -{ - // if not enough room, return false - const int curlength = length(); - if (curlength < m_code.size()) - { - m_code[curlength] = code; - if ((curlength + 1) < m_code.size()) - m_code[curlength + 1] = end_code; - } - return *this; -} - - -//------------------------------------------------- -// operator|= - append a code to a sequence; if -// the sequence is non-empty, insert an OR -// before the new code -//------------------------------------------------- - -input_seq &input_seq::operator|=(input_code code) noexcept +inline void accumulate_axis_value( + s32 &result, + input_item_class &resultclass, + input_item_class &resultclasszero, + s32 value, + input_item_class valueclass, + input_item_class valueclasszero) { - // overwrite end/default with the new code - if (m_code[0] == default_code) + if (!value) { - m_code[0] = code; - m_code[1] = end_code; + // track the highest-priority zero + if ((ITEM_CLASS_ABSOLUTE == valueclasszero) || (ITEM_CLASS_INVALID == resultclasszero)) + resultclasszero = valueclasszero; } - else + else if (ITEM_CLASS_ABSOLUTE == valueclass) { - // otherwise, append an OR token and then the new code - const int curlength = length(); - if ((curlength + 1) < m_code.size()) - { - m_code[curlength] = or_code; - m_code[curlength + 1] = code; - if ((curlength + 2) < m_code.size()) - m_code[curlength + 2] = end_code; - } + // absolute values override relative values + if (ITEM_CLASS_ABSOLUTE == resultclass) + result += value; + else + result = value; + resultclass = ITEM_CLASS_ABSOLUTE; } - return *this; -} - - -//------------------------------------------------- -// length - return the length of the sequence -//------------------------------------------------- - -int input_seq::length() const noexcept -{ - // find the end token; error if none found - for (int seqnum = 0; seqnum < m_code.size(); seqnum++) - if (m_code[seqnum] == end_code) - return seqnum; - return m_code.size(); -} - - -//------------------------------------------------- -// is_valid - return true if a given sequence is -// valid -//------------------------------------------------- - -bool input_seq::is_valid() const noexcept -{ - // "default" can only be of length 1 - if (m_code[0] == default_code) - return m_code[1] == end_code; - - // scan the sequence for valid codes - input_item_class lastclass = ITEM_CLASS_INVALID; - input_code lastcode = INPUT_CODE_INVALID; - decltype(m_code) positive_codes; - decltype(m_code) negative_codes; - auto positive_codes_end = positive_codes.begin(); - auto negative_codes_end = negative_codes.begin(); - for (input_code code : m_code) + else if (ITEM_CLASS_RELATIVE == valueclass) { - // invalid codes are never permitted - if (code == INPUT_CODE_INVALID) - return false; - - // if we hit an OR or the end, validate the previous chunk - if (code == or_code || code == end_code) + // relative values accumulate + if (resultclass != ITEM_CLASS_ABSOLUTE) { - // must be at least one positive code - if (positive_codes.begin() == positive_codes_end) - return false; - - // last code must not have been an internal code - if (lastcode.internal()) - return false; - - // if this is the end, we're OK - if (code == end_code) - return true; - - // reset the state for the next chunk - positive_codes_end = positive_codes.begin(); - negative_codes_end = negative_codes.begin(); - lastclass = ITEM_CLASS_INVALID; - } - else if (code == not_code) - { - // if we hit a NOT, make sure we don't have a double - if (lastcode == not_code) - return false; - } - else - { - // track positive codes, and don't allow positive and negative for the same code - if (lastcode != not_code) - { - *positive_codes_end++ = code; - if (std::find(negative_codes.begin(), negative_codes_end, code) != negative_codes_end) - return false; - } - else - { - *negative_codes_end++ = code; - if (std::find(positive_codes.begin(), positive_codes_end, code) != positive_codes_end) - return false; - } - - // non-switch items can't have a NOT - input_item_class itemclass = code.item_class(); - if (itemclass != ITEM_CLASS_SWITCH && lastcode == not_code) - return false; - - // absolute/relative items must all be the same class - if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) || - (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE)) - return false; + result += value; + resultclass = ITEM_CLASS_RELATIVE; } - - // remember the last code - lastcode = code; } - - // if we got here, we were missing an END token; fail - return false; -} - - -//------------------------------------------------- -// backspace - "backspace" over the last entry in -// a sequence -//------------------------------------------------- - -void input_seq::backspace() noexcept -{ - // if we have at least one entry, remove it - const int curlength = length(); - if (curlength > 0) - m_code[curlength - 1] = end_code; } - -//------------------------------------------------- -// replace - replace all instances of oldcode -// with newcode in a sequence -//------------------------------------------------- - -void input_seq::replace(input_code oldcode, input_code newcode) noexcept -{ - for (input_code &elem : m_code) - if (elem == oldcode) - elem = newcode; -} +} // anonymous namespace @@ -589,48 +437,67 @@ input_manager::~input_manager() //------------------------------------------------- +// class_enabled - return whether input device +// class is enabled +//------------------------------------------------- + +bool input_manager::class_enabled(input_device_class devclass) const +{ + assert(devclass >= DEVICE_CLASS_FIRST_VALID && devclass <= DEVICE_CLASS_LAST_VALID); + return m_class[devclass]->enabled(); +} + + +//------------------------------------------------- +// add_device - add a representation of a host +// input device +//------------------------------------------------- + +osd::input_device &input_manager::add_device(input_device_class devclass, std::string_view name, std::string_view id, void *internal) +{ + return device_class(devclass).add_device(name, id, internal); +} + + +//------------------------------------------------- // code_value - return the value of a given // input code //------------------------------------------------- s32 input_manager::code_value(input_code code) { - g_profiler.start(PROFILER_INPUT); - s32 result = 0; - - // dummy loop to allow clean early exits - do + auto profile = g_profiler.start(PROFILER_INPUT); + + // return 0 for any invalid devices + input_device *const device = device_from_code(code); + if (!device) + return 0; + + // also return 0 if the device class is disabled + input_class &devclass = *m_class[code.device_class()]; + if (!devclass.enabled()) + return 0; + + // if this is not a multi device, only return data for item 0 and iterate over all + int startindex = code.device_index(); + int stopindex = startindex; + if (!devclass.multi()) { - // return 0 for any invalid devices - input_device *device = device_from_code(code); - if (device == nullptr) - break; - - // also return 0 if the device class is disabled - input_class &devclass = *m_class[code.device_class()]; - if (!devclass.enabled()) - break; - - // if this is not a multi device, only return data for item 0 and iterate over all - int startindex = code.device_index(); - int stopindex = startindex; - if (!devclass.multi()) - { - if (startindex != 0) - break; - stopindex = devclass.maxindex(); - } + if (startindex != 0) + return 0; + stopindex = devclass.maxindex(); + } - // iterate over all device indices - input_item_class targetclass = code.item_class(); - for (int curindex = startindex; curindex <= stopindex; curindex++) + // iterate over all device indices + s32 result = 0; + input_item_class targetclass = code.item_class(); + for (int curindex = startindex; curindex <= stopindex; curindex++) + { + // lookup the item for the appropriate index + code.set_device_index(curindex); + input_device_item *const item = item_from_code(code); + if (item) { - // lookup the item for the appropriate index - code.set_device_index(curindex); - input_device_item *item = item_from_code(code); - if (item == nullptr) - continue; - // process items according to their native type switch (targetclass) { @@ -651,10 +518,8 @@ s32 input_manager::code_value(input_code code) break; } } - } while (0); + } - // stop the profiler before exiting - g_profiler.stop(); return result; } @@ -779,50 +644,45 @@ input_code input_manager::code_from_itemid(input_item_id itemid) const std::string input_manager::code_name(input_code code) const { // if nothing there, return an empty string - input_device_item *item = item_from_code(code); - if (item == nullptr) + input_device_item const *const item = item_from_code(code); + if (!item) return std::string(); - // determine the devclass part - const char *devclass = (*devclass_string_table)[code.device_class()]; - - // determine the devindex part - std::string devindex = string_format("%d", code.device_index() + 1); - - // if we're unifying all devices, don't display a number - if (!m_class[code.device_class()]->multi()) - devindex.clear(); + std::string str; // keyboard 0 doesn't show a class or index if it is the only one - input_device_class device_class = item->device().devclass(); - if (device_class == DEVICE_CLASS_KEYBOARD && m_class[device_class]->maxindex() == 0) + input_device_class const device_class = item->device().devclass(); + if ((device_class != DEVICE_CLASS_KEYBOARD) || (m_class[device_class]->maxindex() > 0)) { - devclass = ""; - devindex.clear(); - } + // determine the devclass part + str = (*devclass_string_table)[code.device_class()]; - // devcode part comes from the item name - std::string_view devcode = item->name(); - - // determine the modifier part - const char *modifier = (*modifier_string_table)[code.item_modifier()]; - - // devcode is redundant with joystick switch left/right/up/down - if (device_class == DEVICE_CLASS_JOYSTICK && code.item_class() == ITEM_CLASS_SWITCH) - if (code.item_modifier() >= ITEM_MODIFIER_LEFT && code.item_modifier() <= ITEM_MODIFIER_DOWN) - devcode = std::string_view(); + // if we're unifying all devices, don't display a number + if (m_class[code.device_class()]->multi()) + str.append(util::string_format(" %d ", code.device_index() + 1)); + else + str.append(" "); + } - // concatenate the strings - std::string str(devclass); - if (!devindex.empty()) - str.append(" ").append(devindex); - if (!devcode.empty()) - str.append(" ").append(devcode); - if (modifier != nullptr) - str.append(" ").append(modifier); + // append item name - redundant with joystick switch left/right/up/down + bool const joydir = + (device_class == DEVICE_CLASS_JOYSTICK) && + (code.item_class() == ITEM_CLASS_SWITCH) && + (code.item_modifier() >= ITEM_MODIFIER_LEFT) && + (code.item_modifier() <= ITEM_MODIFIER_DOWN); + if (joydir) + { + str.append((*modifier_string_table)[code.item_modifier()]); + } + else + { + str.append(item->name()); + char const *const modifier = (*modifier_string_table)[code.item_modifier()]; + if (modifier && *modifier) + str.append(" ").append(modifier); + } - // delete any leading spaces - return std::string(strtrimspace(str)); + return str; } @@ -860,7 +720,7 @@ std::string input_manager::code_to_token(input_code code) const std::string str(devclass); if (!devindex.empty()) str.append("_").append(devindex); - if (devcode[0] != 0) + if (!devcode.empty()) str.append("_").append(devcode); if (modifier != nullptr) str.append("_").append(modifier); @@ -1046,91 +906,83 @@ bool input_manager::seq_pressed(const input_seq &seq) s32 input_manager::seq_axis_value(const input_seq &seq, input_item_class &itemclass) { - // start with no valid classes - input_item_class itemclasszero = ITEM_CLASS_INVALID; + // start with zero result and no valid classes + s32 result = 0; itemclass = ITEM_CLASS_INVALID; + input_item_class itemclasszero = ITEM_CLASS_INVALID; // iterate over all of the codes - s32 result = 0; + s32 groupval = 0; + input_item_class groupclass = ITEM_CLASS_INVALID; + input_item_class groupclasszero = ITEM_CLASS_INVALID; bool invert = false; bool enable = true; for (int codenum = 0; ; codenum++) { - input_code code = seq[codenum]; + input_code const code = seq[codenum]; if (code == input_seq::not_code) { - // handle NOT + // handle NOT - invert the next code invert = true; } else if (code == input_seq::end_code) { - // handle END + // handle END - commit group and break out of loop + accumulate_axis_value( + result, itemclass, itemclasszero, + groupval, groupclass, groupclasszero); break; } else if (code == input_seq::or_code) { - // handle OR - - // reset invert and enable for the next group + // handle OR - commit group and reset for the next group + accumulate_axis_value( + result, itemclass, itemclasszero, + groupval, groupclass, groupclasszero); + groupval = 0; + groupclasszero = ITEM_CLASS_INVALID; + groupclass = ITEM_CLASS_INVALID; invert = false; enable = true; } else if (enable) { // handle everything else only if we're still enabled + input_item_class const codeclass = code.item_class(); // switch codes serve as enables - if (code.item_class() == ITEM_CLASS_SWITCH) + if (ITEM_CLASS_SWITCH == codeclass) { // AND against previous digital codes if (enable) + { enable = code_pressed(code) ^ invert; - // FIXME: need to clear current group value if enable became false - // you can't create a sequence where this matters using the internal UI, - // but you can by editing a CFG file (or controller config file) + if (!enable) + { + // clear current group if enable became false - only way out is an OR code + groupval = 0; + groupclasszero = ITEM_CLASS_INVALID; + groupclass = ITEM_CLASS_INVALID; + } + } } else { // non-switch codes are analog values - s32 value = code_value(code); - - // if we got a 0 value, don't do anything except remember the first type - if (value == 0) - { - if (itemclasszero == ITEM_CLASS_INVALID) - itemclasszero = code.item_class(); - } - else if (code.item_class() == ITEM_CLASS_ABSOLUTE) - { - // non-zero absolute values override relative values - if (itemclass == ITEM_CLASS_ABSOLUTE) - result += value; - else - result = value; - itemclass = ITEM_CLASS_ABSOLUTE; - } - else if (code.item_class() == ITEM_CLASS_RELATIVE) - { - // non-zero relative values accumulate in the absence of absolute values - if (itemclass != ITEM_CLASS_ABSOLUTE) - { - result += value; - itemclass = ITEM_CLASS_RELATIVE; - } - } + accumulate_axis_value( + groupval, groupclass, groupclasszero, + code_value(code), codeclass, codeclass); } - // clear the invert flag + // clear the invert flag - it only applies to one item invert = false; } } - // saturate mixed absolute values - if (itemclass == ITEM_CLASS_ABSOLUTE) - result = std::clamp(result, INPUT_ABSOLUTE_MIN, INPUT_ABSOLUTE_MAX); - - // if the caller wants to know the type, provide it - if (result == 0) + // saturate mixed absolute values, report neutral type + if (ITEM_CLASS_ABSOLUTE == itemclass) + result = std::clamp(result, osd::input_device::ABSOLUTE_MIN, osd::input_device::ABSOLUTE_MAX); + else if (ITEM_CLASS_INVALID == itemclass) itemclass = itemclasszero; return result; } @@ -1150,7 +1002,7 @@ input_seq input_manager::seq_clean(const input_seq &seq) const { // if this is a code item which is not valid, don't copy it and remove any preceding ORs/NOTs input_code code = seq[codenum]; - if (!code.internal() && code_name(code).empty()) + if (!code.internal() && (((code.device_index() > 0) && !m_class[code.device_class()]->multi()) || !item_from_code(code))) { while (clean_index > 0 && clean_codes[clean_index - 1].internal()) { @@ -1379,7 +1231,7 @@ bool input_manager::map_device_to_controller(const devicemap_table &table) { // remap devindex input_devclass->remap_device_index(device->devindex(), devindex); - osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex, device->name(), device->id()); + osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex + 1, device->name(), device->id()); break; } diff --git a/src/emu/input.h b/src/emu/input.h index 7bc03c13831..7c00a590a8d 100644 --- a/src/emu/input.h +++ b/src/emu/input.h @@ -17,6 +17,10 @@ #ifndef MAME_EMU_INPUT_H #define MAME_EMU_INPUT_H +#include "interface/inputcode.h" +#include "interface/inputman.h" +#include "interface/inputseq.h" + #include <algorithm> #include <array> #include <cassert> @@ -28,467 +32,16 @@ //************************************************************************** -// CONSTANTS -//************************************************************************** - -// maximum number of axis/buttons/hats with ITEM_IDs for use by osd layer -constexpr int INPUT_MAX_AXIS = 8; -constexpr int INPUT_MAX_BUTTONS = 32; -constexpr int INPUT_MAX_HATS = 4; -constexpr int INPUT_MAX_ADD_SWITCH = 16; -constexpr int INPUT_MAX_ADD_ABSOLUTE = 16; -constexpr int INPUT_MAX_ADD_RELATIVE = 16; - - -// device classes -enum input_device_class -{ - DEVICE_CLASS_INVALID, - DEVICE_CLASS_FIRST_VALID, - DEVICE_CLASS_KEYBOARD = DEVICE_CLASS_FIRST_VALID, - DEVICE_CLASS_MOUSE, - DEVICE_CLASS_LIGHTGUN, - DEVICE_CLASS_JOYSTICK, - DEVICE_CLASS_LAST_VALID = DEVICE_CLASS_JOYSTICK, - DEVICE_CLASS_INTERNAL, - DEVICE_CLASS_MAXIMUM -}; -DECLARE_ENUM_INCDEC_OPERATORS(input_device_class) - - -// device index -constexpr int DEVICE_INDEX_MAXIMUM = 0xff; - - -// input item classes -enum input_item_class -{ - ITEM_CLASS_INVALID, - ITEM_CLASS_SWITCH, - ITEM_CLASS_ABSOLUTE, - ITEM_CLASS_RELATIVE, - ITEM_CLASS_MAXIMUM -}; - - -// input item modifiers -enum input_item_modifier -{ - ITEM_MODIFIER_NONE, - ITEM_MODIFIER_REVERSE, - ITEM_MODIFIER_POS, - ITEM_MODIFIER_NEG, - ITEM_MODIFIER_LEFT, - ITEM_MODIFIER_RIGHT, - ITEM_MODIFIER_UP, - ITEM_MODIFIER_DOWN, - ITEM_MODIFIER_MAXIMUM -}; - - -// standard item IDs -enum input_item_id -{ - ITEM_ID_INVALID, - ITEM_ID_FIRST_VALID, - - // standard keyboard IDs - ITEM_ID_A = ITEM_ID_FIRST_VALID, - ITEM_ID_B, - ITEM_ID_C, - ITEM_ID_D, - ITEM_ID_E, - ITEM_ID_F, - ITEM_ID_G, - ITEM_ID_H, - ITEM_ID_I, - ITEM_ID_J, - ITEM_ID_K, - ITEM_ID_L, - ITEM_ID_M, - ITEM_ID_N, - ITEM_ID_O, - ITEM_ID_P, - ITEM_ID_Q, - ITEM_ID_R, - ITEM_ID_S, - ITEM_ID_T, - ITEM_ID_U, - ITEM_ID_V, - ITEM_ID_W, - ITEM_ID_X, - ITEM_ID_Y, - ITEM_ID_Z, - ITEM_ID_0, - ITEM_ID_1, - ITEM_ID_2, - ITEM_ID_3, - ITEM_ID_4, - ITEM_ID_5, - ITEM_ID_6, - ITEM_ID_7, - ITEM_ID_8, - ITEM_ID_9, - ITEM_ID_F1, - ITEM_ID_F2, - ITEM_ID_F3, - ITEM_ID_F4, - ITEM_ID_F5, - ITEM_ID_F6, - ITEM_ID_F7, - ITEM_ID_F8, - ITEM_ID_F9, - ITEM_ID_F10, - ITEM_ID_F11, - ITEM_ID_F12, - ITEM_ID_F13, - ITEM_ID_F14, - ITEM_ID_F15, - ITEM_ID_F16, - ITEM_ID_F17, - ITEM_ID_F18, - ITEM_ID_F19, - ITEM_ID_F20, - ITEM_ID_ESC, - ITEM_ID_TILDE, - ITEM_ID_MINUS, - ITEM_ID_EQUALS, - ITEM_ID_BACKSPACE, - ITEM_ID_TAB, - ITEM_ID_OPENBRACE, - ITEM_ID_CLOSEBRACE, - ITEM_ID_ENTER, - ITEM_ID_COLON, - ITEM_ID_QUOTE, - ITEM_ID_BACKSLASH, - ITEM_ID_BACKSLASH2, - ITEM_ID_COMMA, - ITEM_ID_STOP, - ITEM_ID_SLASH, - ITEM_ID_SPACE, - ITEM_ID_INSERT, - ITEM_ID_DEL, - ITEM_ID_HOME, - ITEM_ID_END, - ITEM_ID_PGUP, - ITEM_ID_PGDN, - ITEM_ID_LEFT, - ITEM_ID_RIGHT, - ITEM_ID_UP, - ITEM_ID_DOWN, - ITEM_ID_0_PAD, - ITEM_ID_1_PAD, - ITEM_ID_2_PAD, - ITEM_ID_3_PAD, - ITEM_ID_4_PAD, - ITEM_ID_5_PAD, - ITEM_ID_6_PAD, - ITEM_ID_7_PAD, - ITEM_ID_8_PAD, - ITEM_ID_9_PAD, - ITEM_ID_SLASH_PAD, - ITEM_ID_ASTERISK, - ITEM_ID_MINUS_PAD, - ITEM_ID_PLUS_PAD, - ITEM_ID_DEL_PAD, - ITEM_ID_ENTER_PAD, - ITEM_ID_BS_PAD, - ITEM_ID_TAB_PAD, - ITEM_ID_00_PAD, - ITEM_ID_000_PAD, - ITEM_ID_COMMA_PAD, - ITEM_ID_EQUALS_PAD, - ITEM_ID_PRTSCR, - ITEM_ID_PAUSE, - ITEM_ID_LSHIFT, - ITEM_ID_RSHIFT, - ITEM_ID_LCONTROL, - ITEM_ID_RCONTROL, - ITEM_ID_LALT, - ITEM_ID_RALT, - ITEM_ID_SCRLOCK, - ITEM_ID_NUMLOCK, - ITEM_ID_CAPSLOCK, - ITEM_ID_LWIN, - ITEM_ID_RWIN, - ITEM_ID_MENU, - ITEM_ID_CANCEL, - - // standard mouse/joystick/gun IDs - ITEM_ID_XAXIS, - ITEM_ID_YAXIS, - ITEM_ID_ZAXIS, - ITEM_ID_RXAXIS, - ITEM_ID_RYAXIS, - ITEM_ID_RZAXIS, - ITEM_ID_SLIDER1, - ITEM_ID_SLIDER2, - ITEM_ID_BUTTON1, - ITEM_ID_BUTTON2, - ITEM_ID_BUTTON3, - ITEM_ID_BUTTON4, - ITEM_ID_BUTTON5, - ITEM_ID_BUTTON6, - ITEM_ID_BUTTON7, - ITEM_ID_BUTTON8, - ITEM_ID_BUTTON9, - ITEM_ID_BUTTON10, - ITEM_ID_BUTTON11, - ITEM_ID_BUTTON12, - ITEM_ID_BUTTON13, - ITEM_ID_BUTTON14, - ITEM_ID_BUTTON15, - ITEM_ID_BUTTON16, - ITEM_ID_BUTTON17, - ITEM_ID_BUTTON18, - ITEM_ID_BUTTON19, - ITEM_ID_BUTTON20, - ITEM_ID_BUTTON21, - ITEM_ID_BUTTON22, - ITEM_ID_BUTTON23, - ITEM_ID_BUTTON24, - ITEM_ID_BUTTON25, - ITEM_ID_BUTTON26, - ITEM_ID_BUTTON27, - ITEM_ID_BUTTON28, - ITEM_ID_BUTTON29, - ITEM_ID_BUTTON30, - ITEM_ID_BUTTON31, - ITEM_ID_BUTTON32, - ITEM_ID_START, - ITEM_ID_SELECT, - - // Hats - ITEM_ID_HAT1UP, - ITEM_ID_HAT1DOWN, - ITEM_ID_HAT1LEFT, - ITEM_ID_HAT1RIGHT, - ITEM_ID_HAT2UP, - ITEM_ID_HAT2DOWN, - ITEM_ID_HAT2LEFT, - ITEM_ID_HAT2RIGHT, - ITEM_ID_HAT3UP, - ITEM_ID_HAT3DOWN, - ITEM_ID_HAT3LEFT, - ITEM_ID_HAT3RIGHT, - ITEM_ID_HAT4UP, - ITEM_ID_HAT4DOWN, - ITEM_ID_HAT4LEFT, - ITEM_ID_HAT4RIGHT, - - // Additional IDs - ITEM_ID_ADD_SWITCH1, - ITEM_ID_ADD_SWITCH2, - ITEM_ID_ADD_SWITCH3, - ITEM_ID_ADD_SWITCH4, - ITEM_ID_ADD_SWITCH5, - ITEM_ID_ADD_SWITCH6, - ITEM_ID_ADD_SWITCH7, - ITEM_ID_ADD_SWITCH8, - ITEM_ID_ADD_SWITCH9, - ITEM_ID_ADD_SWITCH10, - ITEM_ID_ADD_SWITCH11, - ITEM_ID_ADD_SWITCH12, - ITEM_ID_ADD_SWITCH13, - ITEM_ID_ADD_SWITCH14, - ITEM_ID_ADD_SWITCH15, - ITEM_ID_ADD_SWITCH16, - - ITEM_ID_ADD_ABSOLUTE1, - ITEM_ID_ADD_ABSOLUTE2, - ITEM_ID_ADD_ABSOLUTE3, - ITEM_ID_ADD_ABSOLUTE4, - ITEM_ID_ADD_ABSOLUTE5, - ITEM_ID_ADD_ABSOLUTE6, - ITEM_ID_ADD_ABSOLUTE7, - ITEM_ID_ADD_ABSOLUTE8, - ITEM_ID_ADD_ABSOLUTE9, - ITEM_ID_ADD_ABSOLUTE10, - ITEM_ID_ADD_ABSOLUTE11, - ITEM_ID_ADD_ABSOLUTE12, - ITEM_ID_ADD_ABSOLUTE13, - ITEM_ID_ADD_ABSOLUTE14, - ITEM_ID_ADD_ABSOLUTE15, - ITEM_ID_ADD_ABSOLUTE16, - - ITEM_ID_ADD_RELATIVE1, - ITEM_ID_ADD_RELATIVE2, - ITEM_ID_ADD_RELATIVE3, - ITEM_ID_ADD_RELATIVE4, - ITEM_ID_ADD_RELATIVE5, - ITEM_ID_ADD_RELATIVE6, - ITEM_ID_ADD_RELATIVE7, - ITEM_ID_ADD_RELATIVE8, - ITEM_ID_ADD_RELATIVE9, - ITEM_ID_ADD_RELATIVE10, - ITEM_ID_ADD_RELATIVE11, - ITEM_ID_ADD_RELATIVE12, - ITEM_ID_ADD_RELATIVE13, - ITEM_ID_ADD_RELATIVE14, - ITEM_ID_ADD_RELATIVE15, - ITEM_ID_ADD_RELATIVE16, - - // generic other IDs - ITEM_ID_OTHER_SWITCH, - ITEM_ID_OTHER_AXIS_ABSOLUTE, - ITEM_ID_OTHER_AXIS_RELATIVE, - ITEM_ID_MAXIMUM, - - // internal codes for sequences - ITEM_ID_SEQ_END, - ITEM_ID_SEQ_DEFAULT, - ITEM_ID_SEQ_NOT, - ITEM_ID_SEQ_OR, - - // absolute maximum ID - ITEM_ID_ABSOLUTE_MAXIMUM = 0xfff -}; -DECLARE_ENUM_INCDEC_OPERATORS(input_item_id) - - - -//************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// ======================> input_code - -// a combined code that describes a particular input on a particular device -class input_code -{ -public: - // construction/destruction - constexpr input_code( - input_device_class devclass = DEVICE_CLASS_INVALID, - int devindex = 0, - input_item_class itemclass = ITEM_CLASS_INVALID, - input_item_modifier modifier = ITEM_MODIFIER_NONE, - input_item_id itemid = ITEM_ID_INVALID) noexcept - : m_internal(((devclass & 0xf) << 28) | ((devindex & 0xff) << 20) | ((itemclass & 0xf) << 16) | ((modifier & 0xf) << 12) | (itemid & 0xfff)) - { - assert(devclass >= 0 && devclass < DEVICE_CLASS_MAXIMUM); - assert(devindex >= 0 && devindex < DEVICE_INDEX_MAXIMUM); - assert(itemclass >= 0 && itemclass < ITEM_CLASS_MAXIMUM); - assert(modifier >= 0 && modifier < ITEM_MODIFIER_MAXIMUM); - assert(itemid >= 0 && itemid < ITEM_ID_ABSOLUTE_MAXIMUM); - } - constexpr input_code(const input_code &src) noexcept = default; - - // operators - constexpr bool operator==(const input_code &rhs) const noexcept { return m_internal == rhs.m_internal; } - constexpr bool operator!=(const input_code &rhs) const noexcept { return m_internal != rhs.m_internal; } - constexpr bool operator<(const input_code &rhs) const noexcept { return m_internal < rhs.m_internal; } - - // getters - constexpr bool internal() const noexcept { return device_class() == DEVICE_CLASS_INTERNAL; } - constexpr input_device_class device_class() const noexcept { return input_device_class((m_internal >> 28) & 0xf); } - constexpr int device_index() const noexcept { return ((m_internal >> 20) & 0xff); } - constexpr input_item_class item_class() const noexcept { return input_item_class((m_internal >> 16) & 0xf); } - constexpr input_item_modifier item_modifier() const noexcept { return input_item_modifier((m_internal >> 12) & 0xf); } - constexpr input_item_id item_id() const noexcept { return input_item_id(m_internal & 0xfff); } - - // setters - void set_device_class(input_device_class devclass) noexcept - { - assert(devclass >= 0 && devclass <= 0xf); - m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28); - } - void set_device_index(int devindex) noexcept - { - assert(devindex >= 0 && devindex <= 0xff); - m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20); - } - void set_item_class(input_item_class itemclass) noexcept - { - assert(itemclass >= 0 && itemclass <= 0xf); - m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16); - } - void set_item_modifier(input_item_modifier modifier) noexcept - { - assert(modifier >= 0 && modifier <= 0xf); - m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12); - } - void set_item_id(input_item_id itemid) noexcept - { - assert(itemid >= 0 && itemid <= 0xfff); - m_internal = (m_internal & ~0xfff) | (itemid & 0xfff); - } - -private: - u32 m_internal; -}; - - -// ======================> input_seq - -// a sequence of input_codes, supporting AND/OR and inversion -class input_seq -{ -public: - // construction/destruction - input_seq() noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value>()) { } - template <typename... T> input_seq(input_code code_0, T... code_n) noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value - sizeof...(T) - 1>(), code_0, code_n...) { } - constexpr input_seq(const input_seq &rhs) noexcept = default; - - // operators - bool operator==(const input_seq &rhs) const noexcept { return m_code == rhs.m_code; } - bool operator!=(const input_seq &rhs) const noexcept { return m_code != rhs.m_code; } - constexpr input_code operator[](int index) const noexcept { return (index >= 0 && index < m_code.size()) ? m_code[index] : end_code; } - input_seq &operator+=(input_code code) noexcept; - input_seq &operator|=(input_code code) noexcept; - - // getters - constexpr bool empty() const noexcept { return m_code[0] == end_code; } - constexpr int max_size() const noexcept { return std::tuple_size<decltype(m_code)>::value; } - int length() const noexcept; - bool is_valid() const noexcept; - constexpr bool is_default() const noexcept { return m_code[0] == default_code; } - - // setters - template <typename... T> void set(input_code code_0, T... code_n) noexcept - { - static_assert(sizeof...(T) < std::tuple_size<decltype(m_code)>::value, "too many codes for input_seq"); - set<0>(code_0, code_n...); - } - void reset() noexcept { set(end_code); } - void set_default() noexcept { set(default_code); } - void backspace() noexcept; - void replace(input_code oldcode, input_code newcode) noexcept; - - // constant codes used in sequences - static constexpr input_code end_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END }; - static constexpr input_code default_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT }; - static constexpr input_code not_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT }; - static constexpr input_code or_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR }; - - // constant sequences - static const input_seq empty_seq; - -private: - static constexpr input_code get_end_code(size_t) noexcept { return end_code; } - - template <size_t... N, typename... T> input_seq(std::integer_sequence<size_t, N...>, T... code) noexcept : m_code({ code..., get_end_code(N)... }) { } - template <size_t... N> input_seq(std::integer_sequence<size_t, N...>) noexcept : m_code({ get_end_code(N)... }) { } - - template <unsigned N> void set() noexcept - { - std::fill(std::next(m_code.begin(), N), m_code.end(), end_code); - } - template <unsigned N, typename... T> void set(input_code code_0, T... code_n) noexcept - { - m_code[N] = code_0; - set<N + 1>(code_n...); - } - - // internal state - std::array<input_code, 16> m_code; -}; +using osd::input_seq; // too much trouble to qualify this everywhere // ======================> input_manager // global machine-level information about devices -class input_manager +class input_manager : public osd::input_manager { public: // controller alias table typedef @@ -498,6 +51,10 @@ public: input_manager(running_machine &machine); ~input_manager(); + // OSD interface + virtual bool class_enabled(input_device_class devclass) const override; + virtual osd::input_device &add_device(input_device_class devclass, std::string_view name, std::string_view id, void *internal) override; + // getters running_machine &machine() const { return m_machine; } input_class &device_class(input_device_class devclass) { assert(devclass >= DEVICE_CLASS_FIRST_VALID && devclass <= DEVICE_CLASS_LAST_VALID); return *m_class[devclass]; } @@ -542,466 +99,4 @@ private: }; - -//************************************************************************** -// MACROS -//************************************************************************** - -// invalid codes -#define INPUT_CODE_INVALID input_code() - -// keyboard codes -#define KEYCODE_A_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_A) -#define KEYCODE_B_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_B) -#define KEYCODE_C_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_C) -#define KEYCODE_D_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_D) -#define KEYCODE_E_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_E) -#define KEYCODE_F_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F) -#define KEYCODE_G_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_G) -#define KEYCODE_H_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_H) -#define KEYCODE_I_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_I) -#define KEYCODE_J_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_J) -#define KEYCODE_K_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_K) -#define KEYCODE_L_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_L) -#define KEYCODE_M_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_M) -#define KEYCODE_N_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_N) -#define KEYCODE_O_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_O) -#define KEYCODE_P_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_P) -#define KEYCODE_Q_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Q) -#define KEYCODE_R_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_R) -#define KEYCODE_S_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_S) -#define KEYCODE_T_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_T) -#define KEYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_U) -#define KEYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_V) -#define KEYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_W) -#define KEYCODE_X_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_X) -#define KEYCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Y) -#define KEYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Z) -#define KEYCODE_0_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0) -#define KEYCODE_1_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1) -#define KEYCODE_2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2) -#define KEYCODE_3_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3) -#define KEYCODE_4_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4) -#define KEYCODE_5_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5) -#define KEYCODE_6_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6) -#define KEYCODE_7_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7) -#define KEYCODE_8_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8) -#define KEYCODE_9_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9) -#define KEYCODE_F1_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F1) -#define KEYCODE_F2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F2) -#define KEYCODE_F3_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F3) -#define KEYCODE_F4_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F4) -#define KEYCODE_F5_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F5) -#define KEYCODE_F6_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F6) -#define KEYCODE_F7_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F7) -#define KEYCODE_F8_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F8) -#define KEYCODE_F9_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F9) -#define KEYCODE_F10_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F10) -#define KEYCODE_F11_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F11) -#define KEYCODE_F12_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F12) -#define KEYCODE_F13_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F13) -#define KEYCODE_F14_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F14) -#define KEYCODE_F15_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F15) -#define KEYCODE_F16_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F16) -#define KEYCODE_F17_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F17) -#define KEYCODE_F18_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F18) -#define KEYCODE_F19_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F19) -#define KEYCODE_F20_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F20) -#define KEYCODE_ESC_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ESC) -#define KEYCODE_TILDE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TILDE) -#define KEYCODE_MINUS_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS) -#define KEYCODE_EQUALS_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS) -#define KEYCODE_BACKSPACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSPACE) -#define KEYCODE_TAB_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB) -#define KEYCODE_OPENBRACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_OPENBRACE) -#define KEYCODE_CLOSEBRACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CLOSEBRACE) -#define KEYCODE_ENTER_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER) -#define KEYCODE_COLON_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COLON) -#define KEYCODE_QUOTE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_QUOTE) -#define KEYCODE_BACKSLASH_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH) -#define KEYCODE_BACKSLASH2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH2) -#define KEYCODE_COMMA_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA) -#define KEYCODE_STOP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_STOP) -#define KEYCODE_SLASH_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH) -#define KEYCODE_SPACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SPACE) -#define KEYCODE_INSERT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_INSERT) -#define KEYCODE_DEL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL) -#define KEYCODE_HOME_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HOME) -#define KEYCODE_END_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_END) -#define KEYCODE_PGUP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGUP) -#define KEYCODE_PGDN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGDN) -#define KEYCODE_LEFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LEFT) -#define KEYCODE_RIGHT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RIGHT) -#define KEYCODE_UP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_UP) -#define KEYCODE_DOWN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DOWN) -#define KEYCODE_0_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0_PAD) -#define KEYCODE_1_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1_PAD) -#define KEYCODE_2_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2_PAD) -#define KEYCODE_3_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3_PAD) -#define KEYCODE_4_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4_PAD) -#define KEYCODE_5_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5_PAD) -#define KEYCODE_6_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6_PAD) -#define KEYCODE_7_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7_PAD) -#define KEYCODE_8_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8_PAD) -#define KEYCODE_9_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9_PAD) -#define KEYCODE_SLASH_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH_PAD) -#define KEYCODE_ASTERISK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ASTERISK) -#define KEYCODE_MINUS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS_PAD) -#define KEYCODE_PLUS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PLUS_PAD) -#define KEYCODE_DEL_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL_PAD) -#define KEYCODE_ENTER_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER_PAD) -#define KEYCODE_BS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BS_PAD) -#define KEYCODE_TAB_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB_PAD) -#define KEYCODE_00_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_00_PAD) -#define KEYCODE_000_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_000_PAD) -#define KEYCODE_COMMA_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA_PAD) -#define KEYCODE_EQUALS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS_PAD) -#define KEYCODE_PRTSCR_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PRTSCR) -#define KEYCODE_PAUSE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PAUSE) -#define KEYCODE_LSHIFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LSHIFT) -#define KEYCODE_RSHIFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RSHIFT) -#define KEYCODE_LCONTROL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LCONTROL) -#define KEYCODE_RCONTROL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RCONTROL) -#define KEYCODE_LALT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LALT) -#define KEYCODE_RALT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RALT) -#define KEYCODE_SCRLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SCRLOCK) -#define KEYCODE_NUMLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_NUMLOCK) -#define KEYCODE_CAPSLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CAPSLOCK) -#define KEYCODE_LWIN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LWIN) -#define KEYCODE_RWIN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RWIN) -#define KEYCODE_MENU_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MENU) -#define KEYCODE_CANCEL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CANCEL) - -#define KEYCODE_A KEYCODE_A_INDEXED(0) -#define KEYCODE_B KEYCODE_B_INDEXED(0) -#define KEYCODE_C KEYCODE_C_INDEXED(0) -#define KEYCODE_D KEYCODE_D_INDEXED(0) -#define KEYCODE_E KEYCODE_E_INDEXED(0) -#define KEYCODE_F KEYCODE_F_INDEXED(0) -#define KEYCODE_G KEYCODE_G_INDEXED(0) -#define KEYCODE_H KEYCODE_H_INDEXED(0) -#define KEYCODE_I KEYCODE_I_INDEXED(0) -#define KEYCODE_J KEYCODE_J_INDEXED(0) -#define KEYCODE_K KEYCODE_K_INDEXED(0) -#define KEYCODE_L KEYCODE_L_INDEXED(0) -#define KEYCODE_M KEYCODE_M_INDEXED(0) -#define KEYCODE_N KEYCODE_N_INDEXED(0) -#define KEYCODE_O KEYCODE_O_INDEXED(0) -#define KEYCODE_P KEYCODE_P_INDEXED(0) -#define KEYCODE_Q KEYCODE_Q_INDEXED(0) -#define KEYCODE_R KEYCODE_R_INDEXED(0) -#define KEYCODE_S KEYCODE_S_INDEXED(0) -#define KEYCODE_T KEYCODE_T_INDEXED(0) -#define KEYCODE_U KEYCODE_U_INDEXED(0) -#define KEYCODE_V KEYCODE_V_INDEXED(0) -#define KEYCODE_W KEYCODE_W_INDEXED(0) -#define KEYCODE_X KEYCODE_X_INDEXED(0) -#define KEYCODE_Y KEYCODE_Y_INDEXED(0) -#define KEYCODE_Z KEYCODE_Z_INDEXED(0) -#define KEYCODE_0 KEYCODE_0_INDEXED(0) -#define KEYCODE_1 KEYCODE_1_INDEXED(0) -#define KEYCODE_2 KEYCODE_2_INDEXED(0) -#define KEYCODE_3 KEYCODE_3_INDEXED(0) -#define KEYCODE_4 KEYCODE_4_INDEXED(0) -#define KEYCODE_5 KEYCODE_5_INDEXED(0) -#define KEYCODE_6 KEYCODE_6_INDEXED(0) -#define KEYCODE_7 KEYCODE_7_INDEXED(0) -#define KEYCODE_8 KEYCODE_8_INDEXED(0) -#define KEYCODE_9 KEYCODE_9_INDEXED(0) -#define KEYCODE_F1 KEYCODE_F1_INDEXED(0) -#define KEYCODE_F2 KEYCODE_F2_INDEXED(0) -#define KEYCODE_F3 KEYCODE_F3_INDEXED(0) -#define KEYCODE_F4 KEYCODE_F4_INDEXED(0) -#define KEYCODE_F5 KEYCODE_F5_INDEXED(0) -#define KEYCODE_F6 KEYCODE_F6_INDEXED(0) -#define KEYCODE_F7 KEYCODE_F7_INDEXED(0) -#define KEYCODE_F8 KEYCODE_F8_INDEXED(0) -#define KEYCODE_F9 KEYCODE_F9_INDEXED(0) -#define KEYCODE_F10 KEYCODE_F10_INDEXED(0) -#define KEYCODE_F11 KEYCODE_F11_INDEXED(0) -#define KEYCODE_F12 KEYCODE_F12_INDEXED(0) -#define KEYCODE_F13 KEYCODE_F13_INDEXED(0) -#define KEYCODE_F14 KEYCODE_F14_INDEXED(0) -#define KEYCODE_F15 KEYCODE_F15_INDEXED(0) -#define KEYCODE_F16 KEYCODE_F16_INDEXED(0) -#define KEYCODE_F17 KEYCODE_F17_INDEXED(0) -#define KEYCODE_F18 KEYCODE_F18_INDEXED(0) -#define KEYCODE_F19 KEYCODE_F19_INDEXED(0) -#define KEYCODE_F20 KEYCODE_F20_INDEXED(0) -#define KEYCODE_ESC KEYCODE_ESC_INDEXED(0) -#define KEYCODE_TILDE KEYCODE_TILDE_INDEXED(0) -#define KEYCODE_MINUS KEYCODE_MINUS_INDEXED(0) -#define KEYCODE_EQUALS KEYCODE_EQUALS_INDEXED(0) -#define KEYCODE_BACKSPACE KEYCODE_BACKSPACE_INDEXED(0) -#define KEYCODE_TAB KEYCODE_TAB_INDEXED(0) -#define KEYCODE_OPENBRACE KEYCODE_OPENBRACE_INDEXED(0) -#define KEYCODE_CLOSEBRACE KEYCODE_CLOSEBRACE_INDEXED(0) -#define KEYCODE_ENTER KEYCODE_ENTER_INDEXED(0) -#define KEYCODE_COLON KEYCODE_COLON_INDEXED(0) -#define KEYCODE_QUOTE KEYCODE_QUOTE_INDEXED(0) -#define KEYCODE_BACKSLASH KEYCODE_BACKSLASH_INDEXED(0) -#define KEYCODE_BACKSLASH2 KEYCODE_BACKSLASH2_INDEXED(0) -#define KEYCODE_COMMA KEYCODE_COMMA_INDEXED(0) -#define KEYCODE_STOP KEYCODE_STOP_INDEXED(0) -#define KEYCODE_SLASH KEYCODE_SLASH_INDEXED(0) -#define KEYCODE_SPACE KEYCODE_SPACE_INDEXED(0) -#define KEYCODE_INSERT KEYCODE_INSERT_INDEXED(0) -#define KEYCODE_DEL KEYCODE_DEL_INDEXED(0) -#define KEYCODE_HOME KEYCODE_HOME_INDEXED(0) -#define KEYCODE_END KEYCODE_END_INDEXED(0) -#define KEYCODE_PGUP KEYCODE_PGUP_INDEXED(0) -#define KEYCODE_PGDN KEYCODE_PGDN_INDEXED(0) -#define KEYCODE_LEFT KEYCODE_LEFT_INDEXED(0) -#define KEYCODE_RIGHT KEYCODE_RIGHT_INDEXED(0) -#define KEYCODE_UP KEYCODE_UP_INDEXED(0) -#define KEYCODE_DOWN KEYCODE_DOWN_INDEXED(0) -#define KEYCODE_0_PAD KEYCODE_0_PAD_INDEXED(0) -#define KEYCODE_1_PAD KEYCODE_1_PAD_INDEXED(0) -#define KEYCODE_2_PAD KEYCODE_2_PAD_INDEXED(0) -#define KEYCODE_3_PAD KEYCODE_3_PAD_INDEXED(0) -#define KEYCODE_4_PAD KEYCODE_4_PAD_INDEXED(0) -#define KEYCODE_5_PAD KEYCODE_5_PAD_INDEXED(0) -#define KEYCODE_6_PAD KEYCODE_6_PAD_INDEXED(0) -#define KEYCODE_7_PAD KEYCODE_7_PAD_INDEXED(0) -#define KEYCODE_8_PAD KEYCODE_8_PAD_INDEXED(0) -#define KEYCODE_9_PAD KEYCODE_9_PAD_INDEXED(0) -#define KEYCODE_SLASH_PAD KEYCODE_SLASH_PAD_INDEXED(0) -#define KEYCODE_ASTERISK KEYCODE_ASTERISK_INDEXED(0) -#define KEYCODE_MINUS_PAD KEYCODE_MINUS_PAD_INDEXED(0) -#define KEYCODE_PLUS_PAD KEYCODE_PLUS_PAD_INDEXED(0) -#define KEYCODE_DEL_PAD KEYCODE_DEL_PAD_INDEXED(0) -#define KEYCODE_ENTER_PAD KEYCODE_ENTER_PAD_INDEXED(0) -#define KEYCODE_BS_PAD KEYCODE_BS_PAD_INDEXED(0) -#define KEYCODE_TAB_PAD KEYCODE_TAB_PAD_INDEXED(0) -#define KEYCODE_00_PAD KEYCODE_00_PAD_INDEXED(0) -#define KEYCODE_000_PAD KEYCODE_000_PAD_INDEXED(0) -#define KEYCODE_COMMA_PAD KEYCODE_COMMA_PAD_INDEXED(0) -#define KEYCODE_EQUALS_PAD KEYCODE_EQUALS_PAD_INDEXED(0) -#define KEYCODE_PRTSCR KEYCODE_PRTSCR_INDEXED(0) -#define KEYCODE_PAUSE KEYCODE_PAUSE_INDEXED(0) -#define KEYCODE_LSHIFT KEYCODE_LSHIFT_INDEXED(0) -#define KEYCODE_RSHIFT KEYCODE_RSHIFT_INDEXED(0) -#define KEYCODE_LCONTROL KEYCODE_LCONTROL_INDEXED(0) -#define KEYCODE_RCONTROL KEYCODE_RCONTROL_INDEXED(0) -#define KEYCODE_LALT KEYCODE_LALT_INDEXED(0) -#define KEYCODE_RALT KEYCODE_RALT_INDEXED(0) -#define KEYCODE_SCRLOCK KEYCODE_SCRLOCK_INDEXED(0) -#define KEYCODE_NUMLOCK KEYCODE_NUMLOCK_INDEXED(0) -#define KEYCODE_CAPSLOCK KEYCODE_CAPSLOCK_INDEXED(0) -#define KEYCODE_LWIN KEYCODE_LWIN_INDEXED(0) -#define KEYCODE_RWIN KEYCODE_RWIN_INDEXED(0) -#define KEYCODE_MENU KEYCODE_MENU_INDEXED(0) -#define KEYCODE_CANCEL KEYCODE_CANCEL_INDEXED(0) - -// mouse axes as relative devices -#define MOUSECODE_X_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS) -#define MOUSECODE_Y_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS) -#define MOUSECODE_Z_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS) - -#define MOUSECODE_X MOUSECODE_X_INDEXED(0) -#define MOUSECODE_Y MOUSECODE_Y_INDEXED(0) -#define MOUSECODE_Z MOUSECODE_Z_INDEXED(0) - -// mouse axes as switches in +/- direction -#define MOUSECODE_X_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_XAXIS) -#define MOUSECODE_X_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS) -#define MOUSECODE_Y_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_YAXIS) -#define MOUSECODE_Y_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS) -#define MOUSECODE_Z_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS) -#define MOUSECODE_Z_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS) - -#define MOUSECODE_X_POS_SWITCH MOUSECODE_X_POS_SWITCH_INDEXED(0) -#define MOUSECODE_X_NEG_SWITCH MOUSECODE_X_NEG_SWITCH_INDEXED(0) -#define MOUSECODE_Y_POS_SWITCH MOUSECODE_Y_POS_SWITCH_INDEXED(0) -#define MOUSECODE_Y_NEG_SWITCH MOUSECODE_Y_NEG_SWITCH_INDEXED(0) -#define MOUSECODE_Z_POS_SWITCH MOUSECODE_Z_POS_SWITCH_INDEXED(0) -#define MOUSECODE_Z_NEG_SWITCH MOUSECODE_Z_NEG_SWITCH_INDEXED(0) - -// mouse buttons -#define MOUSECODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1) -#define MOUSECODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2) -#define MOUSECODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3) -#define MOUSECODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4) -#define MOUSECODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5) -#define MOUSECODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6) -#define MOUSECODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7) -#define MOUSECODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8) - -#define MOUSECODE_BUTTON1 MOUSECODE_BUTTON1_INDEXED(0) -#define MOUSECODE_BUTTON2 MOUSECODE_BUTTON2_INDEXED(0) -#define MOUSECODE_BUTTON3 MOUSECODE_BUTTON3_INDEXED(0) -#define MOUSECODE_BUTTON4 MOUSECODE_BUTTON4_INDEXED(0) -#define MOUSECODE_BUTTON5 MOUSECODE_BUTTON5_INDEXED(0) -#define MOUSECODE_BUTTON6 MOUSECODE_BUTTON6_INDEXED(0) -#define MOUSECODE_BUTTON7 MOUSECODE_BUTTON7_INDEXED(0) -#define MOUSECODE_BUTTON8 MOUSECODE_BUTTON8_INDEXED(0) - -// gun axes as absolute devices -#define GUNCODE_X_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS) -#define GUNCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS) - -#define GUNCODE_X GUNCODE_X_INDEXED(0) -#define GUNCODE_Y GUNCODE_Y_INDEXED(0) - -// gun buttons -#define GUNCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1) -#define GUNCODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2) -#define GUNCODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3) -#define GUNCODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4) -#define GUNCODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5) -#define GUNCODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6) -#define GUNCODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7) -#define GUNCODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8) - -#define GUNCODE_BUTTON1 GUNCODE_BUTTON1_INDEXED(0) -#define GUNCODE_BUTTON2 GUNCODE_BUTTON2_INDEXED(0) -#define GUNCODE_BUTTON3 GUNCODE_BUTTON3_INDEXED(0) -#define GUNCODE_BUTTON4 GUNCODE_BUTTON4_INDEXED(0) -#define GUNCODE_BUTTON5 GUNCODE_BUTTON5_INDEXED(0) -#define GUNCODE_BUTTON6 GUNCODE_BUTTON6_INDEXED(0) -#define GUNCODE_BUTTON7 GUNCODE_BUTTON7_INDEXED(0) -#define GUNCODE_BUTTON8 GUNCODE_BUTTON8_INDEXED(0) - -// joystick axes as absolute devices -#define JOYCODE_X_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS) -#define JOYCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS) -#define JOYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS) -#define JOYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS) -#define JOYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS) -#define JOYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS) - -#define JOYCODE_X JOYCODE_X_INDEXED(0) -#define JOYCODE_Y JOYCODE_Y_INDEXED(0) -#define JOYCODE_Z JOYCODE_Z_INDEXED(0) -#define JOYCODE_U JOYCODE_U_INDEXED(0) -#define JOYCODE_V JOYCODE_V_INDEXED(0) -#define JOYCODE_W JOYCODE_W_INDEXED(0) - -// joystick axes as absolute half-axes -#define JOYCODE_X_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS) -#define JOYCODE_X_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS) -#define JOYCODE_Y_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_YAXIS) -#define JOYCODE_Y_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS) -#define JOYCODE_Z_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS) -#define JOYCODE_Z_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS) -#define JOYCODE_U_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS) -#define JOYCODE_U_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS) -#define JOYCODE_V_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS) -#define JOYCODE_V_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS) -#define JOYCODE_W_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS) -#define JOYCODE_W_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS) - -#define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0) -#define JOYCODE_Y_POS_ABSOLUTE JOYCODE_Y_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_Y_NEG_ABSOLUTE JOYCODE_Y_NEG_ABSOLUTE_INDEXED(0) -#define JOYCODE_Z_POS_ABSOLUTE JOYCODE_Z_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_Z_NEG_ABSOLUTE JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0) -#define JOYCODE_U_POS_ABSOLUTE JOYCODE_U_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0) -#define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0) -#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0) -#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0) - -// joystick axes as switches; X/Y are specially handled for left/right/up/down mapping -#define JOYCODE_X_LEFT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS) -#define JOYCODE_X_RIGHT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, ITEM_ID_XAXIS) -#define JOYCODE_Y_UP_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, ITEM_ID_YAXIS) -#define JOYCODE_Y_DOWN_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, ITEM_ID_YAXIS) -#define JOYCODE_Z_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS) -#define JOYCODE_Z_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS) -#define JOYCODE_U_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS) -#define JOYCODE_U_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS) -#define JOYCODE_V_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS) -#define JOYCODE_V_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS) -#define JOYCODE_W_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS) -#define JOYCODE_W_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS) - -#define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0) -#define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0) -#define JOYCODE_Y_UP_SWITCH JOYCODE_Y_UP_SWITCH_INDEXED(0) -#define JOYCODE_Y_DOWN_SWITCH JOYCODE_Y_DOWN_SWITCH_INDEXED(0) -#define JOYCODE_Z_POS_SWITCH JOYCODE_Z_POS_SWITCH_INDEXED(0) -#define JOYCODE_Z_NEG_SWITCH JOYCODE_Z_NEG_SWITCH_INDEXED(0) -#define JOYCODE_U_POS_SWITCH JOYCODE_U_POS_SWITCH_INDEXED(0) -#define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0) -#define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0) -#define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0) -#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0) -#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0) - -// joystick buttons -#define JOYCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1) -#define JOYCODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2) -#define JOYCODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3) -#define JOYCODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4) -#define JOYCODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5) -#define JOYCODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6) -#define JOYCODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7) -#define JOYCODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8) -#define JOYCODE_BUTTON9_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON9) -#define JOYCODE_BUTTON10_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON10) -#define JOYCODE_BUTTON11_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON11) -#define JOYCODE_BUTTON12_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON12) -#define JOYCODE_BUTTON13_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON13) -#define JOYCODE_BUTTON14_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON14) -#define JOYCODE_BUTTON15_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON15) -#define JOYCODE_BUTTON16_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON16) -#define JOYCODE_BUTTON17_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON17) -#define JOYCODE_BUTTON18_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON18) -#define JOYCODE_BUTTON19_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON19) -#define JOYCODE_BUTTON20_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON20) -#define JOYCODE_BUTTON21_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON21) -#define JOYCODE_BUTTON22_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON22) -#define JOYCODE_BUTTON23_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON23) -#define JOYCODE_BUTTON24_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON24) -#define JOYCODE_BUTTON25_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON25) -#define JOYCODE_BUTTON26_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON26) -#define JOYCODE_BUTTON27_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON27) -#define JOYCODE_BUTTON28_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON28) -#define JOYCODE_BUTTON29_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON29) -#define JOYCODE_BUTTON30_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON30) -#define JOYCODE_BUTTON31_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON31) -#define JOYCODE_BUTTON32_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON32) -#define JOYCODE_START_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_START) -#define JOYCODE_SELECT_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SELECT) - -#define JOYCODE_BUTTON1 JOYCODE_BUTTON1_INDEXED(0) -#define JOYCODE_BUTTON2 JOYCODE_BUTTON2_INDEXED(0) -#define JOYCODE_BUTTON3 JOYCODE_BUTTON3_INDEXED(0) -#define JOYCODE_BUTTON4 JOYCODE_BUTTON4_INDEXED(0) -#define JOYCODE_BUTTON5 JOYCODE_BUTTON5_INDEXED(0) -#define JOYCODE_BUTTON6 JOYCODE_BUTTON6_INDEXED(0) -#define JOYCODE_BUTTON7 JOYCODE_BUTTON7_INDEXED(0) -#define JOYCODE_BUTTON8 JOYCODE_BUTTON8_INDEXED(0) -#define JOYCODE_BUTTON9 JOYCODE_BUTTON9_INDEXED(0) -#define JOYCODE_BUTTON10 JOYCODE_BUTTON10_INDEXED(0) -#define JOYCODE_BUTTON11 JOYCODE_BUTTON11_INDEXED(0) -#define JOYCODE_BUTTON12 JOYCODE_BUTTON12_INDEXED(0) -#define JOYCODE_BUTTON13 JOYCODE_BUTTON13_INDEXED(0) -#define JOYCODE_BUTTON14 JOYCODE_BUTTON14_INDEXED(0) -#define JOYCODE_BUTTON15 JOYCODE_BUTTON15_INDEXED(0) -#define JOYCODE_BUTTON16 JOYCODE_BUTTON16_INDEXED(0) -#define JOYCODE_BUTTON17 JOYCODE_BUTTON17_INDEXED(0) -#define JOYCODE_BUTTON18 JOYCODE_BUTTON18_INDEXED(0) -#define JOYCODE_BUTTON19 JOYCODE_BUTTON19_INDEXED(0) -#define JOYCODE_BUTTON20 JOYCODE_BUTTON20_INDEXED(0) -#define JOYCODE_BUTTON21 JOYCODE_BUTTON21_INDEXED(0) -#define JOYCODE_BUTTON22 JOYCODE_BUTTON22_INDEXED(0) -#define JOYCODE_BUTTON23 JOYCODE_BUTTON23_INDEXED(0) -#define JOYCODE_BUTTON24 JOYCODE_BUTTON24_INDEXED(0) -#define JOYCODE_BUTTON25 JOYCODE_BUTTON25_INDEXED(0) -#define JOYCODE_BUTTON26 JOYCODE_BUTTON26_INDEXED(0) -#define JOYCODE_BUTTON27 JOYCODE_BUTTON27_INDEXED(0) -#define JOYCODE_BUTTON28 JOYCODE_BUTTON28_INDEXED(0) -#define JOYCODE_BUTTON29 JOYCODE_BUTTON29_INDEXED(0) -#define JOYCODE_BUTTON30 JOYCODE_BUTTON30_INDEXED(0) -#define JOYCODE_BUTTON31 JOYCODE_BUTTON31_INDEXED(0) -#define JOYCODE_BUTTON32 JOYCODE_BUTTON32_INDEXED(0) -#define JOYCODE_START JOYCODE_START_INDEXED(0) -#define JOYCODE_SELECT JOYCODE_SELECT_INDEXED(0) - - - #endif // MAME_EMU_INPUT_H diff --git a/src/emu/inputdev.cpp b/src/emu/inputdev.cpp index 436f83cf0df..a9caaf7788d 100644 --- a/src/emu/inputdev.cpp +++ b/src/emu/inputdev.cpp @@ -28,7 +28,13 @@ class input_device_switch_item : public input_device_item { public: // construction/destruction - input_device_switch_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate); + input_device_switch_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate); // readers virtual s32 read_as_switch(input_item_modifier modifier) override; @@ -54,7 +60,13 @@ class input_device_relative_item : public input_device_item { public: // construction/destruction - input_device_relative_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate); + input_device_relative_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate); // readers virtual s32 read_as_switch(input_item_modifier modifier) override; @@ -71,7 +83,13 @@ class input_device_absolute_item : public input_device_item { public: // construction/destruction - input_device_absolute_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate); + input_device_absolute_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate); // readers virtual s32 read_as_switch(input_item_modifier modifier) override; @@ -233,8 +251,8 @@ std::string joystick_map::to_string() const u8 joystick_map::update(s32 xaxisval, s32 yaxisval) { // now map the X and Y axes to a 9x9 grid using the raw values - xaxisval = ((xaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1); - yaxisval = ((yaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1); + xaxisval = ((xaxisval - osd::input_device::ABSOLUTE_MIN) * 9) / (osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN + 1); + yaxisval = ((yaxisval - osd::input_device::ABSOLUTE_MIN) * 9) / (osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN + 1); u8 mapval = m_map[yaxisval][xaxisval]; // handle stickiness @@ -258,14 +276,15 @@ u8 joystick_map::update(s32 xaxisval, s32 yaxisval) //------------------------------------------------- input_device::input_device(input_manager &manager, std::string_view name, std::string_view id, void *internal) - : m_manager(manager), - m_name(name), - m_id(id), - m_devindex(-1), - m_maxitem(input_item_id(0)), - m_internal(internal), - m_steadykey_enabled(manager.machine().options().steadykey()), - m_lightgun_reload_button(manager.machine().options().offscreen_reload()) + : m_manager(manager) + , m_name(name) + , m_id(id) + , m_devindex(-1) + , m_maxitem(input_item_id(0)) + , m_internal(internal) + , m_threshold(std::max<s32>(s32(manager.machine().options().joystick_threshold() * osd::input_device::ABSOLUTE_MAX), 1)) + , m_steadykey_enabled(manager.machine().options().steadykey()) + , m_lightgun_reload_button(manager.machine().options().offscreen_reload()) { } @@ -283,7 +302,12 @@ input_device::~input_device() // add_item - add a new item to an input device //------------------------------------------------- -input_item_id input_device::add_item(std::string_view name, input_item_id itemid, item_get_state_func getstate, void *internal) +input_item_id input_device::add_item( + std::string_view name, + std::string_view tokenhint, + input_item_id itemid, + item_get_state_func getstate, + void *internal) { if (machine().phase() != machine_phase::INIT) throw emu_fatalerror("Can only call input_device::add_item at init time!"); @@ -305,15 +329,15 @@ input_item_id input_device::add_item(std::string_view name, input_item_id itemid switch (m_manager.device_class(devclass()).standard_item_class(originalid)) { case ITEM_CLASS_SWITCH: - m_item[itemid] = std::make_unique<input_device_switch_item>(*this, name, internal, itemid, getstate); + m_item[itemid] = std::make_unique<input_device_switch_item>(*this, name, tokenhint, internal, itemid, getstate); break; case ITEM_CLASS_RELATIVE: - m_item[itemid] = std::make_unique<input_device_relative_item>(*this, name, internal, itemid, getstate); + m_item[itemid] = std::make_unique<input_device_relative_item>(*this, name, tokenhint, internal, itemid, getstate); break; case ITEM_CLASS_ABSOLUTE: - m_item[itemid] = std::make_unique<input_device_absolute_item>(*this, name, internal, itemid, getstate); + m_item[itemid] = std::make_unique<input_device_absolute_item>(*this, name, tokenhint, internal, itemid, getstate); break; default: @@ -328,6 +352,17 @@ input_item_id input_device::add_item(std::string_view name, input_item_id itemid //------------------------------------------------- +// set_default_assignments - set additional input +// assignments suitable for device +//------------------------------------------------- + +void input_device::set_default_assignments(assignment_vector &&assignments) +{ + m_default_assignments = std::move(assignments); +} + + +//------------------------------------------------- // match_device_id - match device id via // substring search //------------------------------------------------- @@ -411,9 +446,10 @@ input_device_lightgun::input_device_lightgun(input_manager &manager, std::string //------------------------------------------------- input_device_joystick::input_device_joystick(input_manager &manager, std::string_view _name, std::string_view _id, void *_internal) - : input_device(manager, _name, _id, _internal), - m_joystick_deadzone(s32(manager.machine().options().joystick_deadzone() * INPUT_ABSOLUTE_MAX)), - m_joystick_saturation(s32(manager.machine().options().joystick_saturation() * INPUT_ABSOLUTE_MAX)) + : input_device(manager, _name, _id, _internal) + , m_deadzone(s32(manager.machine().options().joystick_deadzone() * osd::input_device::ABSOLUTE_MAX)) + , m_saturation(s32(manager.machine().options().joystick_saturation() * osd::input_device::ABSOLUTE_MAX)) + , m_range(m_saturation - m_deadzone) { // get the default joystick map const char *mapstring = machine().options().joystick_map(); @@ -440,24 +476,16 @@ input_device_joystick::input_device_joystick(input_manager &manager, std::string s32 input_device_joystick::adjust_absolute_value(s32 result) const { // properties are symmetric - bool negative = false; - if (result < 0) - { - negative = true; + bool const negative = result < 0; + if (negative) result = -result; - } - // if in the deadzone, return 0 - if (result < m_joystick_deadzone) + if (result < m_deadzone) // if in the deadzone, return 0 result = 0; - - // if saturated, return the max - else if (result > m_joystick_saturation) - result = INPUT_ABSOLUTE_MAX; - - // otherwise, scale - else - result = s64(result - m_joystick_deadzone) * s64(INPUT_ABSOLUTE_MAX) / s64(m_joystick_saturation - m_joystick_deadzone); + else if (result >= m_saturation) // if saturated, return the max + result = osd::input_device::ABSOLUTE_MAX; + else // otherwise, scale + result = s64(result - m_deadzone) * s64(osd::input_device::ABSOLUTE_MAX) / m_range; // re-apply sign and return return negative ? -result : result; @@ -519,9 +547,9 @@ input_device &input_class::add_device(std::unique_ptr<input_device> &&new_device m_maxindex = std::max(m_maxindex, devindex); if (new_device->id()[0] == 0) - osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex, new_device->name()); + osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex + 1, new_device->name()); else - osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex, new_device->name(), new_device->id()); + osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex + 1, new_device->name(), new_device->id()); m_device[devindex] = std::move(new_device); return *m_device[devindex]; @@ -538,17 +566,21 @@ input_device &input_class::add_device(std::unique_ptr<input_device> &&new_device input_item_class input_class::standard_item_class(input_item_id itemid) const { - // most everything standard is a switch, apart from the axes if (itemid == ITEM_ID_OTHER_SWITCH || itemid < ITEM_ID_XAXIS || (itemid > ITEM_ID_SLIDER2 && itemid < ITEM_ID_ADD_ABSOLUTE1)) + { + // most everything standard is a switch, apart from the axes return ITEM_CLASS_SWITCH; - - // standard mouse axes are relative + } else if (m_devclass == DEVICE_CLASS_MOUSE || itemid == ITEM_ID_OTHER_AXIS_RELATIVE || (itemid >= ITEM_ID_ADD_RELATIVE1 && itemid <= ITEM_ID_ADD_RELATIVE16)) + { + // standard mouse axes are relative return ITEM_CLASS_RELATIVE; - - // all other standard axes are absolute + } else + { + // all other standard axes are absolute return ITEM_CLASS_ABSOLUTE; + } } @@ -667,25 +699,37 @@ bool input_class_joystick::set_global_joystick_map(const char *mapstring) // input_device_item - constructor //------------------------------------------------- -input_device_item::input_device_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate, input_item_class itemclass) - : m_device(device), - m_name(name), - m_internal(internal), - m_itemid(itemid), - m_itemclass(itemclass), - m_getstate(getstate), - m_current(0) +input_device_item::input_device_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate, + input_item_class itemclass) + : m_device(device) + , m_name(name) + , m_internal(internal) + , m_itemid(itemid) + , m_itemclass(itemclass) + , m_getstate(getstate) + , m_current(0) { const char *standard_token = manager().standard_token(itemid); if (standard_token) { - // use a standard token name for know item IDs - m_token.assign(standard_token); + // use a standard token name for known item IDs + m_token = standard_token; + } + else if (!tokenhint.empty()) + { + // fall back to token hint if supplied + m_token = tokenhint; } else { // otherwise, create a tokenized name - m_token.assign(strmakeupper(name)); + m_token = strmakeupper(name); strdelchr(m_token, ' '); strdelchr(m_token, '_'); } @@ -708,8 +752,8 @@ input_device_item::~input_device_item() bool input_device_item::check_axis(input_item_modifier modifier, s32 memory) { - // use INVALID_AXIS_VALUE as a short-circuit - return (memory != INVALID_AXIS_VALUE) && item_check_axis(modifier, memory); + // use osd::INVALID_AXIS_VALUE as a short-circuit + return (memory != osd::input_device::INVALID_AXIS_VALUE) && item_check_axis(modifier, memory); } @@ -721,10 +765,16 @@ bool input_device_item::check_axis(input_item_modifier modifier, s32 memory) // input_device_switch_item - constructor //------------------------------------------------- -input_device_switch_item::input_device_switch_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate) - : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_SWITCH), - m_steadykey(0), - m_oldkey(0) +input_device_switch_item::input_device_switch_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate) + : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_SWITCH) + , m_steadykey(0) + , m_oldkey(0) { } @@ -826,8 +876,14 @@ bool input_device_switch_item::steadykey_changed() // input_device_relative_item - constructor //------------------------------------------------- -input_device_relative_item::input_device_relative_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate) - : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_RELATIVE) +input_device_relative_item::input_device_relative_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate) + : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_RELATIVE) { } @@ -894,7 +950,7 @@ bool input_device_relative_item::item_check_axis(input_item_modifier modifier, s const s32 curval = read_as_relative(modifier); // for relative axes, look for ~20 pixels movement - return std::abs(curval - memory) > (20 * INPUT_RELATIVE_PER_PIXEL); + return std::abs(curval - memory) > (20 * osd::input_device::RELATIVE_PER_PIXEL); } @@ -907,8 +963,14 @@ bool input_device_relative_item::item_check_axis(input_item_modifier modifier, s // input_device_absolute_item - constructor //------------------------------------------------- -input_device_absolute_item::input_device_absolute_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate) - : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_ABSOLUTE) +input_device_absolute_item::input_device_absolute_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate) + : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_ABSOLUTE) { } @@ -921,8 +983,7 @@ input_device_absolute_item::input_device_absolute_item(input_device &device, std s32 input_device_absolute_item::read_as_switch(input_item_modifier modifier) { // start with the current value - s32 result = m_device.adjust_absolute(update_value()); - assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX); + s32 const result = update_value(); // left/right/up/down: if this is a joystick, fetch the paired X/Y axis values and convert if (m_device.devclass() == DEVICE_CLASS_JOYSTICK && modifier >= ITEM_MODIFIER_LEFT && modifier <= ITEM_MODIFIER_DOWN) @@ -940,18 +1001,24 @@ s32 input_device_absolute_item::read_as_switch(input_item_modifier modifier) // now map the X and Y axes to a 9x9 grid using the raw values joystick_map &joymap = downcast<input_device_joystick &>(m_device).joymap(); - return (joymap.update(xaxis_item->current(), yaxis_item->current()) >> (modifier - ITEM_MODIFIER_LEFT)) & 1; + return BIT(joymap.update(xaxis_item->current(), yaxis_item->current()), modifier - ITEM_MODIFIER_LEFT); } } - // positive/negative: true if past the deadzone in either direction - if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN) - return (result > 0); - else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP) - return (result < 0); - - // all other cases just return 0 - return 0; + // positive/negative: true if past the threshold in either direction, otherwise zero + switch (modifier) + { + case ITEM_MODIFIER_POS: + case ITEM_MODIFIER_RIGHT: + case ITEM_MODIFIER_DOWN: + return result >= m_device.threshold(); + case ITEM_MODIFIER_NEG: + case ITEM_MODIFIER_LEFT: + case ITEM_MODIFIER_UP: + return -result >= m_device.threshold(); + default: + return 0; + } } @@ -977,7 +1044,7 @@ s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier) { // start with the current value s32 result = m_device.adjust_absolute(update_value()); - assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX); + assert(result >= osd::input_device::ABSOLUTE_MIN && result <= osd::input_device::ABSOLUTE_MAX); // if we're doing a lightgun reload hack, override the value if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN && m_device.lightgun_reload_button()) @@ -985,16 +1052,16 @@ s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier) // if it is pressed, return (min,max) input_device_item *button2_item = m_device.item(ITEM_ID_BUTTON2); if (button2_item != nullptr && button2_item->update_value()) - result = (m_itemid == ITEM_ID_XAXIS) ? INPUT_ABSOLUTE_MIN : INPUT_ABSOLUTE_MAX; + result = (m_itemid == ITEM_ID_XAXIS) ? osd::input_device::ABSOLUTE_MIN : osd::input_device::ABSOLUTE_MAX; } // positive/negative: scale to full axis if (modifier == ITEM_MODIFIER_REVERSE) result = -result; else if (modifier == ITEM_MODIFIER_POS) - result = std::max(result, 0) * 2 + INPUT_ABSOLUTE_MIN; + result = std::max(result, 0) * 2 + osd::input_device::ABSOLUTE_MIN; else if (modifier == ITEM_MODIFIER_NEG) - result = std::max(-result, 0) * 2 + INPUT_ABSOLUTE_MIN; + result = std::max(-result, 0) * 2 + osd::input_device::ABSOLUTE_MIN; return result; } @@ -1010,9 +1077,9 @@ bool input_device_absolute_item::item_check_axis(input_item_modifier modifier, s // so the selection will not be affected by a gun going out of range const s32 curval = read_as_absolute(modifier); if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN && - (curval == INPUT_ABSOLUTE_MAX || curval == INPUT_ABSOLUTE_MIN)) + (curval == osd::input_device::ABSOLUTE_MAX || curval == osd::input_device::ABSOLUTE_MIN)) return false; // for absolute axes, look for 25% of maximum - return std::abs(curval - memory) > ((INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN) / 4); + return std::abs(curval - memory) > ((osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN) / 4); } diff --git a/src/emu/inputdev.h b/src/emu/inputdev.h index 1b6dabc9bab..8e914094610 100644 --- a/src/emu/inputdev.h +++ b/src/emu/inputdev.h @@ -13,29 +13,13 @@ #pragma once - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// relative devices return ~512 units per onscreen pixel -constexpr s32 INPUT_RELATIVE_PER_PIXEL = 512; - -// absolute devices return values between -65536 and +65536 -constexpr s32 INPUT_ABSOLUTE_MIN = -65536; -constexpr s32 INPUT_ABSOLUTE_MAX = 65536; - -// invalid memory value for axis polling -constexpr s32 INVALID_AXIS_VALUE = 0x7fffffff; +#include "interface/inputdev.h" //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// callback for getting the value of an item on a device -typedef s32 (*item_get_state_func)(void *device_internal, void *item_internal); - // ======================> joystick_map // a 9x9 joystick map @@ -88,6 +72,8 @@ private: class input_device_item { public: + using item_get_state_func = osd::input_device::item_get_state_func; + virtual ~input_device_item(); // getters @@ -114,7 +100,14 @@ public: protected: // construction/destruction - input_device_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate, input_item_class itemclass); + input_device_item( + input_device &device, + std::string_view name, + std::string_view tokenhint, + void *internal, + input_item_id itemid, + item_get_state_func getstate, + input_item_class itemclass); // internal state input_device & m_device; // reference to our owning device @@ -133,7 +126,7 @@ protected: // ======================> input_device // a logical device of a given class that can provide input -class input_device +class input_device : public osd::input_device { friend class input_class; @@ -150,16 +143,24 @@ public: const std::string &id() const { return m_id; } int devindex() const { return m_devindex; } input_device_item *item(input_item_id index) const { return m_item[index].get(); } + const assignment_vector &default_assignments() const { return m_default_assignments; } input_item_id maxitem() const { return m_maxitem; } void *internal() const { return m_internal; } + s32 threshold() const { return m_threshold; } bool steadykey_enabled() const { return m_steadykey_enabled; } bool lightgun_reload_button() const { return m_lightgun_reload_button; } // setters void set_devindex(int devindex) { m_devindex = devindex; } - // item management - input_item_id add_item(std::string_view name, input_item_id itemid, item_get_state_func getstate, void *internal = nullptr); + // interface for host input device + virtual input_item_id add_item( + std::string_view name, + std::string_view tokenhint, + input_item_id itemid, + item_get_state_func getstate, + void *internal) override; + virtual void set_default_assignments(assignment_vector &&assignments) override; // helpers s32 adjust_absolute(s32 value) const { return adjust_absolute_value(value); } @@ -177,11 +178,13 @@ private: std::string m_id; // id of device int m_devindex; // device index of this device std::unique_ptr<input_device_item> m_item[ITEM_ID_ABSOLUTE_MAXIMUM+1]; // array of pointers to items + assignment_vector m_default_assignments; // additional assignments input_item_id m_maxitem; // maximum item index - void * m_internal; // internal callback pointer + void *const m_internal; // internal callback pointer - bool m_steadykey_enabled; // steadykey enabled for keyboards - bool m_lightgun_reload_button; // lightgun reload hack + s32 const m_threshold; // threshold for treating absolute axis as active + bool const m_steadykey_enabled; // steadykey enabled for keyboards + bool const m_lightgun_reload_button; // lightgun reload hack }; @@ -252,9 +255,10 @@ protected: private: // joystick information - joystick_map m_joymap; // joystick map for this device - s32 m_joystick_deadzone; // deadzone for joystick - s32 m_joystick_saturation; // saturation position for joystick + joystick_map m_joymap; // joystick map for this device + s32 const m_deadzone; // deadzone for joystick + s32 const m_saturation; // saturation position for joystick + s64 const m_range; // difference between saturation and deadzone }; diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 0ea7974caf5..aed29b6324f 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -6,105 +6,30 @@ Input/output port handling. -**************************************************************************** - - Theory of operation - - ------------ - OSD controls - ------------ - - There are three types of controls that the OSD can provide as potential - input devices: digital controls, absolute analog controls, and relative - analog controls. - - Digital controls have only two states: on or off. They are generally - mapped to buttons and digital joystick directions (like a gamepad or a - joystick hat). The OSD layer must return either 0 (off) or 1 (on) for - these types of controls. - - Absolute analog controls are analog in the sense that they return a - range of values depending on how much a given control is moved, but they - are physically bounded. This means that there is a minimum and maximum - limit to how far the control can be moved. They are generally mapped to - analog joystick axes, lightguns, most PC steering wheels, and pedals. - The OSD layer must determine the minimum and maximum range of each - analog device and scale that to a value between -65536 and +65536 - representing the position of the control. -65536 generally refers to - the topmost or leftmost position, while +65536 refers to the bottommost - or rightmost position. Note that pedals are a special case here, the - OSD layer needs to return half axis as full -65536 to + 65536 range. - - Relative analog controls are analog as well, but are not physically - bounded. They can be moved continually in one direction without limit. - They are generally mapped to trackballs and mice. Because they are - unbounded, the OSD layer can only return delta values since the last - read. Because of this, it is difficult to scale appropriately. For - MAME's purposes, when mapping a mouse devices to a relative analog - control, one pixel of movement should correspond to 512 units. Other - analog control types should be scaled to return values of a similar - magnitude. Like absolute analog controls, negative values refer to - upward or leftward movement, while positive values refer to downward - or rightward movement. - - ------------- - Game controls - ------------- - - Similarly, the types of controls used by arcade games fall into the same - three categories: digital, absolute analog, and relative analog. The - tricky part is how to map any arbitrary type of OSD control to an - arbitrary type of game control. - - Digital controls: used for game buttons and standard 4/8-way joysticks, - as well as many other types of game controls. Mapping an OSD digital - control to a game's OSD control is trivial. For OSD analog controls, - the MAME core does not directly support mapping any OSD analog devices - to digital controls. However, the OSD layer is free to enumerate digital - equivalents for analog devices. For example, each analog axis in the - Windows OSD code enumerates to two digital controls, one for the - negative direction (up/left) and one for the position direction - (down/right). When these "digital" inputs are queried, the OSD layer - checks the axis position against the center, adding in a dead zone, - and returns 0 or 1 to indicate its position. - - Absolute analog controls: used for analog joysticks, lightguns, pedals, - and wheel controls. Mapping an OSD absolute analog control to this type - is easy. OSD relative analog controls can be mapped here as well by - accumulating the deltas and bounding the results. OSD digital controls - are mapped to these types of controls in pairs, one for a decrement and - one for an increment, but apart from that, operate the same as the OSD - relative analog controls by accumulating deltas and applying bounds. - The speed of the digital delta is user-configurable per analog input. - In addition, most absolute analog control types have an autocentering - feature that is activated when using the digital increment/decrement - sequences, which returns the control back to the center at a user- - controllable speed if no digital sequences are pressed. - - Relative analog controls: used for trackballs and dial controls. Again, - mapping an OSD relative analog control to this type is straightforward. - OSD absolute analog controls can't map directly to these, but if the OSD - layer provides a digital equivalent for each direction, it can be done. - OSD digital controls map just like they do for absolute analog controls, - except that the accumulated deltas are not bounded, but rather wrap. - ***************************************************************************/ #include "emu.h" -#include "emuopts.h" + #include "config.h" -#include "xmlfile.h" -#include "profiler.h" -#include "ui/uimain.h" +#include "emuopts.h" +#include "fileio.h" #include "inputdev.h" +#include "main.h" #include "natkeyboard.h" +#include "profiler.h" + +#include "ui/uimain.h" #include "util/corestr.h" #include "util/ioprocsfilter.h" +#include "util/language.h" +#include "util/multibyte.h" #include "util/unicode.h" +#include "util/xmlfile.h" #include "osdepend.h" +#include <algorithm> #include <cctype> #include <ctime> @@ -161,6 +86,22 @@ inline s32 apply_scale(s32 value, s64 scale) return (s64(value) * scale) / (1 << 24); } +//------------------------------------------------- +// compute_shift -- get shift required to right- +// align an I/O port field value +//------------------------------------------------- + +inline u8 compute_shift(ioport_value mask) +{ + u8 result = 0U; + while (mask && !BIT(mask, 0)) + { + mask >>= 1; + ++result; + } + return result; +} + //************************************************************************** @@ -307,6 +248,133 @@ inline bool input_seq_good(running_machine &machine, input_seq const &seq) return input_seq::end_code != machine.input().seq_clean(seq)[0]; } + +std::string substitute_player(std::string_view name, u8 player) +{ + using util::lang_translate; + + std::string result; + while (!name.empty()) + { + auto const found = name.find('%'); + if ((std::string_view::npos == found) || (name.length() == found + 1)) + { + result.append(name); + break; + } + switch (name[found + 1]) + { + case '%': + result.append(name.substr(0, found + 1)); + break; + case 'p': + result.append(name.substr(0, found)); + result.append(util::string_format(_("input-name", "P%1$u"), player + 1)); + break; + default: + result.append(name.substr(0, found + 2)); + } + name.remove_prefix(found + 2); + } + return result; +} + + + +// ======================> inp_header + +// header at the front of INP files +class inp_header +{ +public: + // parameters + static constexpr unsigned MAJVERSION = 3; + static constexpr unsigned MINVERSION = 0; + + bool read(emu_file &f) + { + return f.read(m_data, sizeof(m_data)) == sizeof(m_data); + } + bool write(emu_file &f) const + { + return f.write(m_data, sizeof(m_data)) == sizeof(m_data); + } + + bool check_magic() const + { + return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC); + } + u64 get_basetime() const + { + return get_u64le(m_data + OFFS_BASETIME); + } + unsigned get_majversion() const + { + return m_data[OFFS_MAJVERSION]; + } + unsigned get_minversion() const + { + return m_data[OFFS_MINVERSION]; + } + std::string get_sysname() const + { + return get_string<OFFS_SYSNAME, OFFS_APPDESC>(); + } + std::string get_appdesc() const + { + return get_string<OFFS_APPDESC, OFFS_END>(); + } + + void set_magic() + { + std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC); + } + void set_basetime(u64 time) + { + put_u64le(m_data + OFFS_BASETIME, time); + } + void set_version() + { + m_data[OFFS_MAJVERSION] = MAJVERSION; + m_data[OFFS_MINVERSION] = MINVERSION; + } + void set_sysname(std::string const &name) + { + set_string<OFFS_SYSNAME, OFFS_APPDESC>(name); + } + void set_appdesc(std::string const &desc) + { + set_string<OFFS_APPDESC, OFFS_END>(desc); + } + +private: + template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str) + { + std::size_t const used = (std::min<std::size_t>)(str.size() + 1, END - BEGIN); + std::memcpy(m_data + BEGIN, str.c_str(), used); + if ((END - BEGIN) > used) + std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used); + } + template <std::size_t BEGIN, std::size_t END> std::string get_string() const + { + char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN); + return std::string(begin, std::find(begin, reinterpret_cast<char const *>(m_data + END), '\0')); + } + + static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes + static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer) + static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer) + static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer) + // 0x02 bytes reserved + static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII) + static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII) + static constexpr std::size_t OFFS_END = 0x40; + + static u8 const MAGIC[OFFS_BASETIME - OFFS_MAGIC]; + + u8 m_data[OFFS_END]; +}; + } // anonymous namespace @@ -391,6 +459,24 @@ input_type_entry::input_type_entry(ioport_type type, ioport_group group, int pla //------------------------------------------------- +// name - gets the display name for the input +// type +//------------------------------------------------- + +std::string input_type_entry::name() const +{ + using util::lang_translate; + + if (!m_name) + return std::string(); + else if ((group() < IPG_PLAYER1) || (group() > IPG_PLAYER10)) + return _("input-name", m_name); + else + return substitute_player(_("input-name", m_name), player()); +} + + +//------------------------------------------------- // replace_code - replace all instances of // oldcodewith newcode in all sequences //------------------------------------------------- @@ -662,6 +748,20 @@ ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value def } } + +//------------------------------------------------- +// ~ioport_field - destructor +//------------------------------------------------- + +ioport_field::~ioport_field() +{ +} + + +//------------------------------------------------- +// set_value - programmatically set field value +//------------------------------------------------- + void ioport_field::set_value(ioport_value value) { if (is_analog()) @@ -672,11 +772,15 @@ void ioport_field::set_value(ioport_value value) //------------------------------------------------- -// ~ioport_field - destructor +// clear_value - clear programmatic override //------------------------------------------------- -ioport_field::~ioport_field() +void ioport_field::clear_value() { + if (is_analog()) + live().analog->clear_value(); + else + m_digital_value = false; } @@ -685,16 +789,25 @@ ioport_field::~ioport_field() // field (this must never return nullptr) //------------------------------------------------- -const char *ioport_field::name() const +std::string ioport_field::name() const { - // if we have a non-default name, use that - if (m_live != nullptr && !m_live->name.empty()) - return m_live->name.c_str(); - if (m_name != nullptr) + using util::lang_translate; + + // if we have an overridden name, use that + if (m_live && !m_live->name.empty()) + return m_live->name; + + // if no specific name, use the generic name for the type + if (!m_name) + return manager().type_name(m_type, m_player); + + // return name for non-controller fields as-is + ioport_group const group = manager().type_group(m_type, m_player); + if ((group < IPG_PLAYER1) || (group > IPG_PLAYER10)) return m_name; - // otherwise, return the name associated with the type - return manager().type_name(m_type, m_player); + // substitute the player number in if necessary + return substitute_player(m_name, m_player); } @@ -750,8 +863,8 @@ void ioport_field::set_defseq(input_seq_type seqtype, const input_seq &newseq) ioport_type_class ioport_field::type_class() const noexcept { // inputs associated with specific players - ioport_group group = manager().type_group(m_type, m_player); - if (group >= IPG_PLAYER1 && group <= IPG_PLAYER10) + ioport_group const group = manager().type_group(m_type, m_player); + if ((group >= IPG_PLAYER1) && (group <= IPG_PLAYER10)) return INPUT_CLASS_CONTROLLER; // keys (names derived from character codes) @@ -759,7 +872,7 @@ ioport_type_class ioport_field::type_class() const noexcept return INPUT_CLASS_KEYBOARD; // configuration settings (specific names required) - if (m_type == IPT_CONFIG) + if (m_type == IPT_CONFIG || m_type == IPT_ADJUSTER) return INPUT_CLASS_CONFIG; // DIP switches (specific names required) @@ -1373,12 +1486,16 @@ ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog) name.append(string_format("%-*s ", std::max(SPACE_COUNT - 1, 0), field.key_name(which))); } - // trim extra spaces - name = strtrimspace(name); - // special case if (name.empty()) name.assign("Unnamed Key"); + else + { + // trim extra spaces + auto pos = name.find_last_not_of(' '); + assert(pos < name.size()); + name.erase(pos + 1); + } } } @@ -1553,14 +1670,14 @@ void ioport_port::insert_field(ioport_field &newfield, ioport_value &disallowedb for (ioport_field *field = m_fieldlist.first(); field != nullptr; field = nextfield) { nextfield = field->next(); - if ((field->mask() & newfield.mask()) != 0 && + if ((field->mask() & newfield.mask()) && (newfield.condition().none() || field->condition().none() || field->condition() == newfield.condition())) { // reduce the mask of the field we found field->reduce_mask(newfield.mask()); // if the new entry fully overrides the previous one, we nuke - if (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS || field->mask() == 0) + if (!field->mask() || (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS && (field->type() != IPT_UNUSED) && (field->type() != IPT_UNKNOWN))) m_fieldlist.remove(*field); } } @@ -1657,11 +1774,10 @@ ioport_manager::ioport_manager(running_machine &machine) , m_safe_to_read(false) , m_last_frame_time(attotime::zero) , m_last_delta_nsec(0) - , m_record_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS) - , m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ) , m_playback_accumulated_speed(0) , m_playback_accumulated_frames(0) , m_deselected_card_config() + , m_applied_device_defaults(false) { for (auto &entries : m_type_to_entry) std::fill(std::begin(entries), std::end(entries), nullptr); @@ -1702,12 +1818,14 @@ time_t ioport_manager::initialize() if (&port.second->device() == &device) { for (ioport_field &field : port.second->fields()) + { if (field.type_class() == INPUT_CLASS_CONTROLLER) { if (players < field.player() + 1) players = field.player() + 1; field.set_player(field.player() + player_offset); } + } } } player_offset += players; @@ -1718,14 +1836,14 @@ time_t ioport_manager::initialize() port.second->init_live_state(); // handle autoselection of devices - init_autoselect_devices(IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z, OPTION_ADSTICK_DEVICE, "analog joystick"); - init_autoselect_devices(IPT_PADDLE, IPT_PADDLE_V, 0, OPTION_PADDLE_DEVICE, "paddle"); - init_autoselect_devices(IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3, OPTION_PEDAL_DEVICE, "pedal"); - init_autoselect_devices(IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y, 0, OPTION_LIGHTGUN_DEVICE, "lightgun"); - init_autoselect_devices(IPT_POSITIONAL, IPT_POSITIONAL_V, 0, OPTION_POSITIONAL_DEVICE, "positional"); - init_autoselect_devices(IPT_DIAL, IPT_DIAL_V, 0, OPTION_DIAL_DEVICE, "dial"); - init_autoselect_devices(IPT_TRACKBALL_X, IPT_TRACKBALL_Y, 0, OPTION_TRACKBALL_DEVICE, "trackball"); - init_autoselect_devices(IPT_MOUSE_X, IPT_MOUSE_Y, 0, OPTION_MOUSE_DEVICE, "mouse"); + init_autoselect_devices({ IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z }, OPTION_ADSTICK_DEVICE, "analog joystick"); + init_autoselect_devices({ IPT_PADDLE, IPT_PADDLE_V }, OPTION_PADDLE_DEVICE, "paddle"); + init_autoselect_devices({ IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3 }, OPTION_PEDAL_DEVICE, "pedal"); + init_autoselect_devices({ IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y }, OPTION_LIGHTGUN_DEVICE, "lightgun"); + init_autoselect_devices({ IPT_POSITIONAL, IPT_POSITIONAL_V }, OPTION_POSITIONAL_DEVICE, "positional"); + init_autoselect_devices({ IPT_DIAL, IPT_DIAL_V }, OPTION_DIAL_DEVICE, "dial"); + init_autoselect_devices({ IPT_TRACKBALL_X, IPT_TRACKBALL_Y }, OPTION_TRACKBALL_DEVICE, "trackball"); + init_autoselect_devices({ IPT_MOUSE_X, IPT_MOUSE_Y }, OPTION_MOUSE_DEVICE, "mouse"); // look for 4-way diagonal joysticks and change the default map if we find any const char *joystick_map_default = machine().options().joystick_map(); @@ -1783,39 +1901,71 @@ void ioport_manager::init_port_types() // in and the corresponding option //------------------------------------------------- -void ioport_manager::init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame) +void ioport_manager::init_autoselect_devices(std::initializer_list<ioport_type> types, std::string_view option, std::string_view ananame) { + static std::pair<char const *, char const *> const CLASS_OPTIONS[] = { + { "mouse", OPTION_MOUSE }, + { "joystick", OPTION_JOYSTICK }, + { "lightgun", OPTION_LIGHTGUN } }; + // if nothing specified, ignore the option - const char *stemp = machine().options().value(option); - if (stemp[0] == 0 || strcmp(stemp, "none") == 0) + auto const autooption = machine().options().get_entry(option); + char const *const autoclass = autooption->value(); + if (!autoclass || !*autoclass || !std::strcmp(autoclass, "none")) return; - // extract valid strings + // if the device class is enabled anyway or disabled at a higher priority level, do nothing + auto const classname = std::find_if( + std::begin(CLASS_OPTIONS), + std::end(CLASS_OPTIONS), + [&autoclass] (auto const &x) { return !std::strcmp(autoclass, x.first); }); + if (std::end(CLASS_OPTIONS) != classname) + { + if (machine().options().bool_value(classname->second)) + return; + + auto const classoption = machine().options().get_entry(classname->second); + if (classoption->priority() > autooption->priority()) + { + osd_printf_verbose("Input: Won't autoenable %s in presence of a %s as it's disabled at a higher priority\n", autoclass, ananame); + return; + } + } + + // find matching device class input_class *autoenable_class = nullptr; for (input_device_class devclass = DEVICE_CLASS_FIRST_VALID; devclass <= DEVICE_CLASS_LAST_VALID; ++devclass) - if (strcmp(stemp, machine().input().device_class(devclass).name()) == 0) + { + if (!std::strcmp(autoclass, machine().input().device_class(devclass).name())) { autoenable_class = &machine().input().device_class(devclass); break; } - if (autoenable_class == nullptr) + } + if (!autoenable_class) { - osd_printf_error("Invalid %s value %s; reverting to keyboard\n", option, stemp); + osd_printf_error("Invalid %s value %s; reverting to keyboard\n", option, autoclass); autoenable_class = &machine().input().device_class(DEVICE_CLASS_KEYBOARD); } - // only scan the list if we haven't already enabled this class of control - if (!autoenable_class->enabled()) - for (auto &port : m_portlist) - for (ioport_field const &field : port.second->fields()) + // nothing to do if the class is already enabled + if (autoenable_class->enabled()) + return; - // if this port type is in use, apply the autoselect criteria - if ((type1 != 0 && field.type() == type1) || (type2 != 0 && field.type() == type2) || (type3 != 0 && field.type() == type3)) - { - osd_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autoenable_class->name(), ananame); - autoenable_class->enable(); - break; - } + // scan the port list + for (auto &port : m_portlist) + { + for (ioport_field const &field : port.second->fields()) + { + // if this port type is in use, apply the autoselect criteria + if (std::find(std::begin(types), std::end(types), field.type()) != std::end(types)) + { + osd_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autoenable_class->name(), ananame); + autoenable_class->enable(); + return; + } + } + } } @@ -1846,15 +1996,21 @@ ioport_manager::~ioport_manager() // type/player //------------------------------------------------- -const char *ioport_manager::type_name(ioport_type type, u8 player) const noexcept +std::string ioport_manager::type_name(ioport_type type, u8 player) const { + using util::lang_translate; + // if we have a machine, use the live state and quick lookup - input_type_entry *entry = m_type_to_entry[type][player]; - if (entry != nullptr && entry->name() != nullptr) - return entry->name(); + input_type_entry const *const entry = m_type_to_entry[type][player]; + if (entry) + { + std::string name = entry->name(); + if (!name.empty()) + return name; + } // if we find nothing, return a default string (not a null pointer) - return "???"; + return _("input-name", "???"); } @@ -2000,7 +2156,7 @@ void ioport_manager::frame_update_callback() void ioport_manager::frame_update() { - g_profiler.start(PROFILER_INPUT); + auto profile = g_profiler.start(PROFILER_INPUT); // record/playback information about the current frame attotime curtime = machine().time(); @@ -2037,8 +2193,6 @@ void ioport_manager::frame_update() if (dynfield.field().type() != IPT_OUTPUT) dynfield.write(newvalue); } - - g_profiler.stop(); } @@ -2066,6 +2220,17 @@ s32 ioport_manager::frame_interpolate(s32 oldval, s32 newval) void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode) { + // make sure device defaults get applied at some point + if ((cfg_type > config_type::CONTROLLER) && !m_applied_device_defaults) + { + apply_device_defaults(); + + // after applying controller config, push that to the backup, as it's what we'll diff against + for (input_type_entry &entry : m_typelist) + for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) + entry.defseq(seqtype) = entry.seq(seqtype); + } + // in the completion phase, we finish the initialization with the final ports if (cfg_type == config_type::FINAL) { @@ -2080,9 +2245,7 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u // load device map table for controller configs only if (cfg_type == config_type::CONTROLLER) { - // iterate over all the remap nodes - load_remap_table(*parentnode); - + // iterate over device remapping entries input_manager::devicemap_table devicemap; for (util::xml::data_node const *mapdevice_node = parentnode->get_child("mapdevice"); mapdevice_node != nullptr; mapdevice_node = mapdevice_node->get_next_sibling("mapdevice")) { @@ -2092,9 +2255,23 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u devicemap.emplace(devicename, controllername); } - // map device to controller if we have a device map - if (!devicemap.empty()) - machine().input().map_device_to_controller(devicemap); + // we can't rearrange controllers after applying device-supplied defaults + if (!m_applied_device_defaults) + { + // map device to controller if we have a device map + if (!devicemap.empty()) + machine().input().map_device_to_controller(devicemap); + + // add extra default assignments for input devices + apply_device_defaults(); + } + else if (!devicemap.empty()) + { + osd_printf_warning("Controller configuration: Only <mapdevice> elements from the first applicable <system> element are applied\n"); + } + + // iterate over any input code remapping nodes + load_remap_table(*parentnode); } // iterate over all the port nodes @@ -2137,16 +2314,16 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u load_default_config(type, player, newseq); } - // after applying the controller config, push that back into the backup, since that is - // what we will diff against if (cfg_type == config_type::CONTROLLER) + { + // after applying the controller config, push that back into the backup, since that is what we will diff against for (input_type_entry &entry : m_typelist) for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) entry.defseq(seqtype) = entry.seq(seqtype); - - // load keyboard enable/disable state - if (cfg_type == config_type::SYSTEM) + } + else if (cfg_type == config_type::SYSTEM) { + // load keyboard enable/disable state std::vector<bool> kbd_enable_set; bool keyboard_enabled = false, missing_enabled = false; natural_keyboard &natkbd = machine().natkeyboard(); @@ -2303,6 +2480,7 @@ bool ioport_manager::load_controller_config( // find the matching field ioport_value const defvalue = portnode.get_attribute_int("defvalue", 0); + bool matched = false; for (ioport_field &field : port->second->fields()) { // find the matching mask and default value @@ -2313,7 +2491,10 @@ bool ioport_manager::load_controller_config( for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) { if (input_seq_good(machine(), newseq[seqtype].first)) + { + field.live().seq[seqtype] = newseq[seqtype].first; field.set_defseq(seqtype, newseq[seqtype].first); + } } // fetch configurable attributes @@ -2361,13 +2542,16 @@ bool ioport_manager::load_controller_config( #endif } - // successfully applied - return true; + // only break out of the loop for unconditional inputs + if (field.condition().condition() == ioport_condition::ALWAYS) + return true; + else + matched = true; } } - // no matching field - return false; + // return whether any field matched + return matched; } @@ -2438,7 +2622,10 @@ void ioport_manager::load_system_config( else if (revstring && !strcmp(revstring, "no")) field.live().analog->m_reverse = false; } - break; + + // only break out of the loop for unconditional inputs + if (field.condition().condition() == ioport_condition::ALWAYS) + break; } } } @@ -2475,6 +2662,82 @@ void ioport_manager::load_system_config( } +//------------------------------------------------- +// apply_device_defaults - add default assignments +// supplied by input devices +//------------------------------------------------- + +void ioport_manager::apply_device_defaults() +{ + // make sure this only happens once + assert(!m_applied_device_defaults); + m_applied_device_defaults = true; + + // TODO: come up with a way to deal with non-multi device classes here? + for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) + { + input_class &devclass = machine().input().device_class(classno); + for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) + { + // make sure device exists + input_device const *const device = devclass.device(devnum); + if (!device) + continue; + + // iterate over default assignments + for (auto [porttype, seqtype, seq] : device->default_assignments()) + { + assert(!seq.empty()); + assert(seq.is_valid()); + assert(!seq.is_default()); + + // only apply UI assignments for first device in a class + if ((IPT_UI_FIRST < porttype) && (IPT_UI_LAST > porttype) && (device->devindex() != 0)) + continue; + + // limit to maximum player count + if (device->devindex() >= MAX_PLAYERS) + continue; + + // find a matching port in the list + auto const found = std::find_if( + m_typelist.begin(), + m_typelist.end(), + [type = porttype, device] (input_type_entry const &entry) + { + return (entry.type() == type) && (entry.player() == device->devindex()); + }); + if (m_typelist.end() == found) + continue; + + // start with the current setting + input_seq remapped(found->seq(seqtype)); + if (!remapped.empty()) + remapped += input_seq::or_code; + + // append adjusting the device index + for (int i = 0, len = seq.length(); i < len; ++i) + { + input_code code = seq[i]; + if (!code.internal()) + { + assert(code.device_class() == classno); + assert(code.device_index() == 0); + assert(code.item_id() >= ITEM_ID_FIRST_VALID); + assert(code.item_id() <= ITEM_ID_ABSOLUTE_MAXIMUM); + code.set_device_index(device->devindex()); + } + remapped += code; + } + + // apply to the entry + found->set_seq(seqtype, remapped); + } + } + } +} + + //************************************************************************** // SETTINGS SAVE @@ -2586,7 +2849,7 @@ void ioport_manager::save_game_inputs(util::xml::data_node &parentnode) // iterate over ports for (auto &port : m_portlist) for (ioport_field const &field : port.second->fields()) - if (save_this_input_field_type(field.type())) + if (save_this_input_field_type(field.type()) && field.enabled()) { // determine if we changed bool changed = false; @@ -2683,9 +2946,13 @@ Type ioport_manager::playback_read(Type &result) return result = Type(0); // read the value; if we fail, end playback - size_t read; - m_playback_stream->read(&result, sizeof(result), read); - if (sizeof(result) != read) + auto const [err, actual] = read(*m_playback_stream, &result, sizeof(result)); + if (err) + { + playback_end("Read error"); + return result = Type(0); + } + else if (sizeof(result) != actual) { playback_end("End of file"); return result = Type(0); @@ -2723,7 +2990,8 @@ time_t ioport_manager::playback_init() return 0; // open the playback file - std::error_condition const filerr = m_playback_file.open(filename); + m_playback_file = std::make_unique<emu_file>(machine().options().input_directory(), OPEN_FLAG_READ); + std::error_condition const filerr = m_playback_file->open(filename); // return an explicit error if file isn't found in given path if (filerr == std::errc::no_such_file_or_directory) @@ -2735,7 +3003,7 @@ time_t ioport_manager::playback_init() // read the header and verify that it is a modern version; if not, print an error inp_header header; - if (!header.read(m_playback_file)) + if (!header.read(*m_playback_file)) fatalerror("Input file is corrupt or invalid (missing header)\n"); if (!header.check_magic()) fatalerror("Input file invalid or in an older, unsupported format\n"); @@ -2755,7 +3023,7 @@ time_t ioport_manager::playback_init() osd_printf_info("Input file is for machine '%s', not for current machine '%s'\n", sysname, machine().system().name); // enable compression - m_playback_stream = util::zlib_read(m_playback_file, 16386); + m_playback_stream = util::zlib_read(*m_playback_file, 16386); return basetime; } @@ -2771,7 +3039,7 @@ void ioport_manager::playback_end(const char *message) { // close the file m_playback_stream.reset(); - m_playback_file.close(); + m_playback_file.reset(); // pop a message if (message != nullptr) @@ -2868,9 +3136,8 @@ void ioport_manager::record_write(Type value) value = little_endianize_int16(value); // write the value; if we fail, end recording - size_t written; - if (m_record_stream->write(&value, sizeof(value), written) || (sizeof(value) != written)) - record_end("Out of space"); + if (write(*m_record_stream, &value, sizeof(value)).first) + record_end("Write error"); } template<> @@ -2893,7 +3160,8 @@ void ioport_manager::record_init() return; // open the record file - std::error_condition const filerr = m_record_file.open(filename); + m_record_file = std::make_unique<emu_file>(machine().options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + std::error_condition const filerr = m_record_file->open(filename); if (filerr) throw emu_fatalerror("ioport_manager::record_init: Failed to open file for recording (%s:%d %s)", filerr.category().name(), filerr.value(), filerr.message()); @@ -2910,10 +3178,10 @@ void ioport_manager::record_init() header.set_appdesc(util::string_format("%s %s", emulator_info::get_appname(), emulator_info::get_build_version())); // write it - header.write(m_record_file); + header.write(*m_record_file); // enable compression - m_record_stream = util::zlib_write(m_record_file, 6, 16384); + m_record_stream = util::zlib_write(*m_record_file, 6, 16384); } @@ -2928,7 +3196,7 @@ void ioport_manager::record_end(const char *message) { // close the file m_record_stream.reset(); // TODO: check for errors flushing the last compressed block before doing this - m_record_file.close(); + m_record_file.reset(); // pop a message if (message != nullptr) @@ -3145,7 +3413,7 @@ ioport_configurer& ioport_configurer::setting_alloc(ioport_value value, const ch { // make sure we have a field if (!m_curfield) - throw emu_fatalerror("alloc_setting called with no active field (value=%X name=%s)\n", value, name); + throw emu_fatalerror("setting_alloc called with no active field (value=%X name=%s)\n", value, name); // append a new setting m_cursetting = &m_curfield->m_settinglist.emplace_back(*m_curfield, value & m_curfield->mask(), string_from_token(name)); @@ -3198,9 +3466,9 @@ ioport_configurer& ioport_configurer::onoff_alloc(const char *name, ioport_value //------------------------------------------------- dynamic_field::dynamic_field(ioport_field &field) - : m_field(field), - m_shift(0), - m_oldval(field.defvalue()) + : m_field(field) + , m_shift(0) + , m_oldval(field.defvalue()) { // fill in the data for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1) @@ -3255,45 +3523,36 @@ void dynamic_field::write(ioport_value newval) //------------------------------------------------- analog_field::analog_field(ioport_field &field) - : m_field(field), - m_shift(0), - m_adjdefvalue(field.defvalue() & field.mask()), - m_adjmin(field.minval() & field.mask()), - m_adjmax(field.maxval() & field.mask()), - m_sensitivity(field.sensitivity()), - m_reverse(field.analog_reverse()), - m_delta(field.delta()), - m_centerdelta(field.centerdelta()), - m_accum(0), - m_previous(0), - m_previousanalog(0), - m_prog_analog_value(0), - m_minimum(INPUT_ABSOLUTE_MIN), - m_maximum(INPUT_ABSOLUTE_MAX), - m_center(0), - m_reverse_val(0), - m_scalepos(0), - m_scaleneg(0), - m_keyscalepos(0), - m_keyscaleneg(0), - m_positionalscale(0), - m_absolute(false), - m_wraps(false), - m_autocenter(false), - m_single_scale(false), - m_interpolate(false), - m_lastdigital(false), - m_was_written(false) -{ - // compute the shift amount and number of bits - for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1) - m_shift++; - - // initialize core data - m_adjdefvalue >>= m_shift; - m_adjmin >>= m_shift; - m_adjmax >>= m_shift; - + : m_field(field) + , m_shift(compute_shift(field.mask())) + , m_adjdefvalue((field.defvalue() & field.mask()) >> m_shift) + , m_adjmin((field.minval() & field.mask()) >> m_shift) + , m_adjmax((field.maxval() & field.mask()) >> m_shift) + , m_adjoverride((field.defvalue() & field.mask()) >> m_shift) + , m_sensitivity(field.sensitivity()) + , m_reverse(field.analog_reverse()) + , m_delta(field.delta()) + , m_centerdelta(field.centerdelta()) + , m_accum(0) + , m_previous(0) + , m_previousanalog(0) + , m_minimum(osd::input_device::ABSOLUTE_MIN) + , m_maximum(osd::input_device::ABSOLUTE_MAX) + , m_center(0) + , m_reverse_val(0) + , m_scalepos(0) + , m_scaleneg(0) + , m_keyscalepos(0) + , m_keyscaleneg(0) + , m_positionalscale(0) + , m_absolute(false) + , m_wraps(false) + , m_autocenter(false) + , m_single_scale(false) + , m_interpolate(false) + , m_lastdigital(false) + , m_use_adjoverride(false) +{ // set basic parameters based on the configured type switch (field.type()) { @@ -3312,7 +3571,7 @@ analog_field::analog_field(ioport_field &field) case IPT_PEDAL: case IPT_PEDAL2: case IPT_PEDAL3: - m_center = INPUT_ABSOLUTE_MIN; + m_center = osd::input_device::ABSOLUTE_MIN; m_accum = apply_inverse_sensitivity(m_center); m_absolute = true; m_autocenter = true; @@ -3331,7 +3590,7 @@ analog_field::analog_field(ioport_field &field) // set each position to be 512 units case IPT_POSITIONAL: case IPT_POSITIONAL_V: - m_positionalscale = compute_scale(field.maxval(), INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN); + m_positionalscale = compute_scale(field.maxval(), osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN); m_adjmin = 0; m_adjmax = field.maxval() - 1; m_wraps = field.analog_wraps(); @@ -3357,21 +3616,23 @@ analog_field::analog_field(ioport_field &field) fatalerror("Unknown analog port type -- don't know if it is absolute or not\n"); } - // further processing for absolute controls if (m_absolute) { + // further processing for absolute controls + // if the default value is pegged at the min or max, use a single scale value for the whole axis m_single_scale = (m_adjdefvalue == m_adjmin) || (m_adjdefvalue == m_adjmax); // if not "single scale", compute separate scales for each side of the default if (!m_single_scale) { - // unsigned - m_scalepos = compute_scale(m_adjmax - m_adjdefvalue, INPUT_ABSOLUTE_MAX - 0); - m_scaleneg = compute_scale(m_adjdefvalue - m_adjmin, 0 - INPUT_ABSOLUTE_MIN); - - if (m_adjmin > m_adjmax) - m_scaleneg = -m_scaleneg; + // unsigned, potentially passing through zero + m_scalepos = compute_scale( + (m_adjmax - m_adjdefvalue) & (field.mask() >> m_shift), + osd::input_device::ABSOLUTE_MAX); + m_scaleneg = compute_scale( + (m_adjdefvalue - m_adjmin) & (field.mask() >> m_shift), + -osd::input_device::ABSOLUTE_MIN); // reverse point is at center m_reverse_val = 0; @@ -3379,7 +3640,7 @@ analog_field::analog_field(ioport_field &field) else { // single axis that increases from default - m_scalepos = compute_scale(m_adjmax - m_adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN); + m_scalepos = compute_scale(m_adjmax - m_adjmin, osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN); // make the scaling the same for easier coding when we need to scale m_scaleneg = m_scalepos; @@ -3388,11 +3649,11 @@ analog_field::analog_field(ioport_field &field) m_reverse_val = m_maximum; } } - - // relative and positional controls all map directly with a 512x scale factor else { - // The relative code is set up to allow specifing PORT_MINMAX and default values. + // relative and positional controls all map directly with a 512x scale factor + + // The relative code is set up to allow specifying PORT_MINMAX and default values. // The validity checks are purposely set up to not allow you to use anything other // a default of 0 and PORT_MINMAX(0,mask). This is in case the need arises to use // this feature in the future. Keeping the code in does not hurt anything. @@ -3403,15 +3664,17 @@ analog_field::analog_field(ioport_field &field) if (m_wraps) m_adjmax++; - m_minimum = (m_adjmin - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL; - m_maximum = (m_adjmax - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL; + m_minimum = (m_adjmin - m_adjdefvalue) * osd::input_device::RELATIVE_PER_PIXEL; + m_maximum = (m_adjmax - m_adjdefvalue) * osd::input_device::RELATIVE_PER_PIXEL; // make the scaling the same for easier coding when we need to scale - m_scaleneg = m_scalepos = compute_scale(1, INPUT_RELATIVE_PER_PIXEL); + m_scaleneg = m_scalepos = compute_scale(1, osd::input_device::RELATIVE_PER_PIXEL); if (m_field.analog_reset()) + { // delta values reverse from center m_reverse_val = 0; + } else { // positional controls reverse from their max range @@ -3420,11 +3683,11 @@ analog_field::analog_field(ioport_field &field) // relative controls reverse from 1 past their max range if (m_wraps) { - // FIXME: positional needs -1, using INPUT_RELATIVE_PER_PIXEL skips a position (and reads outside the table array) - if(field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V) - m_reverse_val --; + // FIXME: positional needs -1, using osd::input_device::RELATIVE_PER_PIXEL skips a position (and reads outside the table array) + if (field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V) + m_reverse_val--; else - m_reverse_val -= INPUT_RELATIVE_PER_PIXEL; + m_reverse_val -= osd::input_device::RELATIVE_PER_PIXEL; } } } @@ -3497,7 +3760,7 @@ s32 analog_field::apply_settings(s32 value) const else if (m_single_scale) // it's a pedal or the default value is equal to min/max // so we need to adjust the center to the minimum - value -= INPUT_ABSOLUTE_MIN; + value -= osd::input_device::ABSOLUTE_MIN; // map differently for positive and negative values if (value >= 0) @@ -3523,16 +3786,28 @@ s32 analog_field::apply_settings(s32 value) const //------------------------------------------------- -// set_value - take a new value to be used -// at next frame update +// set_value - override the value that will be +// read from the field //------------------------------------------------- void analog_field::set_value(s32 value) { - m_was_written = true; - m_prog_analog_value = value; + m_use_adjoverride = true; + m_adjoverride = std::clamp(value, m_adjmin, m_adjmax); +} + + +//------------------------------------------------- +// clear_value - clear programmatic override +//------------------------------------------------- + +void analog_field::clear_value() +{ + m_use_adjoverride = false; + m_adjoverride = m_adjdefvalue; } + //------------------------------------------------- // frame_update - update the internals of a // single analog field periodically @@ -3551,13 +3826,6 @@ void analog_field::frame_update(running_machine &machine) input_item_class itemclass; s32 rawvalue = machine.input().seq_axis_value(m_field.seq(SEQ_TYPE_STANDARD), itemclass); - // use programmatically set value if available - if (m_was_written) - { - m_was_written = false; - rawvalue = m_prog_analog_value; - } - // if we got an absolute input, it overrides everything else if (itemclass == ITEM_CLASS_ABSOLUTE) { @@ -3597,7 +3865,7 @@ void analog_field::frame_update(running_machine &machine) // if port is positional, we will take the full analog control and divide it // into positions, that way as the control is moved full scale, // it moves through all the positions - rawvalue = apply_scale(rawvalue - INPUT_ABSOLUTE_MIN, m_positionalscale) * INPUT_RELATIVE_PER_PIXEL + m_minimum; + rawvalue = apply_scale(rawvalue - osd::input_device::ABSOLUTE_MIN, m_positionalscale) * osd::input_device::RELATIVE_PER_PIXEL + m_minimum; // clamp the high value so it does not roll over rawvalue = std::min(rawvalue, m_maximum); @@ -3703,6 +3971,13 @@ void analog_field::read(ioport_value &result) if (!m_field.enabled()) return; + // if set programmatically, only use the override value + if (m_use_adjoverride) + { + result = m_adjoverride; + return; + } + // start with the raw value s32 value = m_accum; diff --git a/src/emu/ioport.h b/src/emu/ioport.h index c767d44c250..bbff70db21d 100644 --- a/src/emu/ioport.h +++ b/src/emu/ioport.h @@ -17,12 +17,15 @@ #ifndef MAME_EMU_IOPORT_H #define MAME_EMU_IOPORT_H +#include "inpttype.h" + #include "ioprocs.h" #include <array> #include <cstdint> #include <cstring> #include <ctime> +#include <initializer_list> #include <list> #include <memory> #include <vector> @@ -32,9 +35,6 @@ // CONSTANTS //************************************************************************** -// input ports support up to 32 bits each -typedef u32 ioport_value; - // active high/low values for input ports constexpr ioport_value IP_ACTIVE_HIGH = 0x00000000; constexpr ioport_value IP_ACTIVE_LOW = 0xffffffff; @@ -51,18 +51,6 @@ constexpr char32_t UCHAR_SHIFT_END = UCHAR_SHIFT_2; constexpr char32_t UCHAR_MAMEKEY_BEGIN = UCHAR_PRIVATE + 2; -// sequence types for input_port_seq() call -enum input_seq_type -{ - SEQ_TYPE_INVALID = -1, - SEQ_TYPE_STANDARD = 0, - SEQ_TYPE_INCREMENT, - SEQ_TYPE_DECREMENT, - SEQ_TYPE_TOTAL -}; -DECLARE_ENUM_INCDEC_OPERATORS(input_seq_type) - - // crosshair types enum crosshair_axis_t { @@ -92,323 +80,6 @@ enum ioport_group }; -// various input port types -enum ioport_type -{ - // pseudo-port types - IPT_INVALID = 0, - IPT_UNUSED, - IPT_END, - IPT_UNKNOWN, - IPT_PORT, - IPT_DIPSWITCH, - IPT_CONFIG, - - // start buttons - IPT_START1, - IPT_START2, - IPT_START3, - IPT_START4, - IPT_START5, - IPT_START6, - IPT_START7, - IPT_START8, - IPT_START9, - IPT_START10, - - // coin slots - IPT_COIN1, - IPT_COIN2, - IPT_COIN3, - IPT_COIN4, - IPT_COIN5, - IPT_COIN6, - IPT_COIN7, - IPT_COIN8, - IPT_COIN9, - IPT_COIN10, - IPT_COIN11, - IPT_COIN12, - IPT_BILL1, - - // service coin - IPT_SERVICE1, - IPT_SERVICE2, - IPT_SERVICE3, - IPT_SERVICE4, - - // tilt inputs - IPT_TILT1, - IPT_TILT2, - IPT_TILT3, - IPT_TILT4, - - // misc other digital inputs - IPT_POWER_ON, - IPT_POWER_OFF, - IPT_SERVICE, - IPT_TILT, - IPT_INTERLOCK, - IPT_MEMORY_RESET, - IPT_VOLUME_UP, - IPT_VOLUME_DOWN, - IPT_START, // use the numbered start button(s) for coin-ops - IPT_SELECT, - IPT_KEYPAD, - IPT_KEYBOARD, - - // digital joystick inputs - IPT_DIGITAL_JOYSTICK_FIRST, - - // use IPT_JOYSTICK for panels where the player has one single joystick - IPT_JOYSTICK_UP, - IPT_JOYSTICK_DOWN, - IPT_JOYSTICK_LEFT, - IPT_JOYSTICK_RIGHT, - - // use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels - IPT_JOYSTICKRIGHT_UP, - IPT_JOYSTICKRIGHT_DOWN, - IPT_JOYSTICKRIGHT_LEFT, - IPT_JOYSTICKRIGHT_RIGHT, - IPT_JOYSTICKLEFT_UP, - IPT_JOYSTICKLEFT_DOWN, - IPT_JOYSTICKLEFT_LEFT, - IPT_JOYSTICKLEFT_RIGHT, - - IPT_DIGITAL_JOYSTICK_LAST, - - // action buttons - IPT_BUTTON1, - IPT_BUTTON2, - IPT_BUTTON3, - IPT_BUTTON4, - IPT_BUTTON5, - IPT_BUTTON6, - IPT_BUTTON7, - IPT_BUTTON8, - IPT_BUTTON9, - IPT_BUTTON10, - IPT_BUTTON11, - IPT_BUTTON12, - IPT_BUTTON13, - IPT_BUTTON14, - IPT_BUTTON15, - IPT_BUTTON16, - - // mahjong inputs - IPT_MAHJONG_FIRST, - - IPT_MAHJONG_A, - IPT_MAHJONG_B, - IPT_MAHJONG_C, - IPT_MAHJONG_D, - IPT_MAHJONG_E, - IPT_MAHJONG_F, - IPT_MAHJONG_G, - IPT_MAHJONG_H, - IPT_MAHJONG_I, - IPT_MAHJONG_J, - IPT_MAHJONG_K, - IPT_MAHJONG_L, - IPT_MAHJONG_M, - IPT_MAHJONG_N, - IPT_MAHJONG_O, - IPT_MAHJONG_P, - IPT_MAHJONG_Q, - IPT_MAHJONG_KAN, - IPT_MAHJONG_PON, - IPT_MAHJONG_CHI, - IPT_MAHJONG_REACH, - IPT_MAHJONG_RON, - IPT_MAHJONG_FLIP_FLOP, - IPT_MAHJONG_BET, - IPT_MAHJONG_SCORE, - IPT_MAHJONG_DOUBLE_UP, - IPT_MAHJONG_BIG, - IPT_MAHJONG_SMALL, - IPT_MAHJONG_LAST_CHANCE, - - IPT_MAHJONG_LAST, - - // hanafuda inputs - IPT_HANAFUDA_FIRST, - - IPT_HANAFUDA_A, - IPT_HANAFUDA_B, - IPT_HANAFUDA_C, - IPT_HANAFUDA_D, - IPT_HANAFUDA_E, - IPT_HANAFUDA_F, - IPT_HANAFUDA_G, - IPT_HANAFUDA_H, - IPT_HANAFUDA_YES, - IPT_HANAFUDA_NO, - - IPT_HANAFUDA_LAST, - - // gambling inputs - IPT_GAMBLING_FIRST, - - IPT_GAMBLE_KEYIN, // attendant - IPT_GAMBLE_KEYOUT, // attendant - IPT_GAMBLE_SERVICE, // attendant - IPT_GAMBLE_BOOK, // attendant - IPT_GAMBLE_DOOR, // attendant - // IPT_GAMBLE_DOOR2, // many gambling games have several doors. - // IPT_GAMBLE_DOOR3, - // IPT_GAMBLE_DOOR4, - // IPT_GAMBLE_DOOR5, - - IPT_GAMBLE_PAYOUT, // player - IPT_GAMBLE_BET, // player - IPT_GAMBLE_DEAL, // player - IPT_GAMBLE_STAND, // player - IPT_GAMBLE_TAKE, // player - IPT_GAMBLE_D_UP, // player - IPT_GAMBLE_HALF, // player - IPT_GAMBLE_HIGH, // player - IPT_GAMBLE_LOW, // player - - // poker-specific inputs - IPT_POKER_HOLD1, - IPT_POKER_HOLD2, - IPT_POKER_HOLD3, - IPT_POKER_HOLD4, - IPT_POKER_HOLD5, - IPT_POKER_CANCEL, - - // slot-specific inputs - IPT_SLOT_STOP1, - IPT_SLOT_STOP2, - IPT_SLOT_STOP3, - IPT_SLOT_STOP4, - IPT_SLOT_STOP_ALL, - - IPT_GAMBLING_LAST, - - // analog inputs - IPT_ANALOG_FIRST, - - IPT_ANALOG_ABSOLUTE_FIRST, - - IPT_AD_STICK_X, // absolute // autocenter - IPT_AD_STICK_Y, // absolute // autocenter - IPT_AD_STICK_Z, // absolute // autocenter - IPT_PADDLE, // absolute // autocenter - IPT_PADDLE_V, // absolute // autocenter - IPT_PEDAL, // absolute // autocenter - IPT_PEDAL2, // absolute // autocenter - IPT_PEDAL3, // absolute // autocenter - IPT_LIGHTGUN_X, // absolute - IPT_LIGHTGUN_Y, // absolute - IPT_POSITIONAL, // absolute // autocenter if not wraps - IPT_POSITIONAL_V, // absolute // autocenter if not wraps - - IPT_ANALOG_ABSOLUTE_LAST, - - IPT_DIAL, // relative - IPT_DIAL_V, // relative - IPT_TRACKBALL_X, // relative - IPT_TRACKBALL_Y, // relative - IPT_MOUSE_X, // relative - IPT_MOUSE_Y, // relative - - IPT_ANALOG_LAST, - - // analog adjuster support - IPT_ADJUSTER, - - // the following are special codes for user interface handling - not to be used by drivers! - IPT_UI_FIRST, - - IPT_UI_CONFIGURE, - IPT_UI_ON_SCREEN_DISPLAY, - IPT_UI_DEBUG_BREAK, - IPT_UI_PAUSE, - IPT_UI_PAUSE_SINGLE, - IPT_UI_REWIND_SINGLE, - IPT_UI_RESET_MACHINE, - IPT_UI_SOFT_RESET, - IPT_UI_SHOW_GFX, - IPT_UI_FRAMESKIP_DEC, - IPT_UI_FRAMESKIP_INC, - IPT_UI_THROTTLE, - IPT_UI_FAST_FORWARD, - IPT_UI_SHOW_FPS, - IPT_UI_SNAPSHOT, - IPT_UI_RECORD_MNG, - IPT_UI_RECORD_AVI, - IPT_UI_TOGGLE_CHEAT, - IPT_UI_UP, - IPT_UI_DOWN, - IPT_UI_LEFT, - IPT_UI_RIGHT, - IPT_UI_HOME, - IPT_UI_END, - IPT_UI_PAGE_UP, - IPT_UI_PAGE_DOWN, - IPT_UI_FOCUS_NEXT, - IPT_UI_FOCUS_PREV, - IPT_UI_SELECT, - IPT_UI_CANCEL, - IPT_UI_DISPLAY_COMMENT, - IPT_UI_CLEAR, - IPT_UI_ZOOM_IN, - IPT_UI_ZOOM_OUT, - IPT_UI_ZOOM_DEFAULT, - IPT_UI_PREV_GROUP, - IPT_UI_NEXT_GROUP, - IPT_UI_ROTATE, - IPT_UI_SHOW_PROFILER, - IPT_UI_TOGGLE_UI, - IPT_UI_RELEASE_POINTER, - IPT_UI_PASTE, - IPT_UI_SAVE_STATE, - IPT_UI_LOAD_STATE, - IPT_UI_TAPE_START, - IPT_UI_TAPE_STOP, - IPT_UI_DATS, - IPT_UI_FAVORITES, - IPT_UI_EXPORT, - IPT_UI_AUDIT, - - // additional OSD-specified UI port types (up to 16) - IPT_OSD_1, - IPT_OSD_2, - IPT_OSD_3, - IPT_OSD_4, - IPT_OSD_5, - IPT_OSD_6, - IPT_OSD_7, - IPT_OSD_8, - IPT_OSD_9, - IPT_OSD_10, - IPT_OSD_11, - IPT_OSD_12, - IPT_OSD_13, - IPT_OSD_14, - IPT_OSD_15, - IPT_OSD_16, - - IPT_UI_LAST, - - IPT_OTHER, // not mapped to standard defaults - - IPT_SPECIAL, // uninterpreted characters - IPT_CUSTOM, // handled by custom code - IPT_OUTPUT, - - IPT_COUNT -}; -DECLARE_ENUM_INCDEC_OPERATORS(ioport_type) -// aliases for some types -#define IPT_PADDLE_H IPT_PADDLE -#define IPT_PEDAL1 IPT_PEDAL -#define IPT_POSITIONAL_H IPT_POSITIONAL -#define IPT_DIAL_H IPT_DIAL - - // input type classes enum ioport_type_class { @@ -662,116 +333,6 @@ typedef device_delegate<void (ioport_field &, u32, ioport_value, ioport_value)> typedef device_delegate<float (float)> ioport_field_crossmap_delegate; -// ======================> inp_header - -// header at the front of INP files -class inp_header -{ -public: - // parameters - static constexpr unsigned MAJVERSION = 3; - static constexpr unsigned MINVERSION = 0; - - bool read(emu_file &f) - { - return f.read(m_data, sizeof(m_data)) == sizeof(m_data); - } - bool write(emu_file &f) const - { - return f.write(m_data, sizeof(m_data)) == sizeof(m_data); - } - - bool check_magic() const - { - return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC); - } - u64 get_basetime() const - { - return - (u64(m_data[OFFS_BASETIME + 0]) << (0 * 8)) | - (u64(m_data[OFFS_BASETIME + 1]) << (1 * 8)) | - (u64(m_data[OFFS_BASETIME + 2]) << (2 * 8)) | - (u64(m_data[OFFS_BASETIME + 3]) << (3 * 8)) | - (u64(m_data[OFFS_BASETIME + 4]) << (4 * 8)) | - (u64(m_data[OFFS_BASETIME + 5]) << (5 * 8)) | - (u64(m_data[OFFS_BASETIME + 6]) << (6 * 8)) | - (u64(m_data[OFFS_BASETIME + 7]) << (7 * 8)); - } - unsigned get_majversion() const - { - return m_data[OFFS_MAJVERSION]; - } - unsigned get_minversion() const - { - return m_data[OFFS_MINVERSION]; - } - std::string get_sysname() const - { - return get_string<OFFS_SYSNAME, OFFS_APPDESC>(); - } - std::string get_appdesc() const - { - return get_string<OFFS_APPDESC, OFFS_END>(); - } - - void set_magic() - { - std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC); - } - void set_basetime(u64 time) - { - m_data[OFFS_BASETIME + 0] = u8((time >> (0 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 1] = u8((time >> (1 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 2] = u8((time >> (2 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 3] = u8((time >> (3 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 4] = u8((time >> (4 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 5] = u8((time >> (5 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 6] = u8((time >> (6 * 8)) & 0x00ff); - m_data[OFFS_BASETIME + 7] = u8((time >> (7 * 8)) & 0x00ff); - } - void set_version() - { - m_data[OFFS_MAJVERSION] = MAJVERSION; - m_data[OFFS_MINVERSION] = MINVERSION; - } - void set_sysname(std::string const &name) - { - set_string<OFFS_SYSNAME, OFFS_APPDESC>(name); - } - void set_appdesc(std::string const &desc) - { - set_string<OFFS_APPDESC, OFFS_END>(desc); - } - -private: - template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str) - { - std::size_t const used = (std::min<std::size_t>)(str.size() + 1, END - BEGIN); - std::memcpy(m_data + BEGIN, str.c_str(), used); - if ((END - BEGIN) > used) - std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used); - } - template <std::size_t BEGIN, std::size_t END> std::string get_string() const - { - char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN); - return std::string(begin, std::find(begin, reinterpret_cast<char const *>(m_data + END), '\0')); - } - - static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes - static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer) - static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer) - static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer) - // 0x02 bytes reserved - static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII) - static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII) - static constexpr std::size_t OFFS_END = 0x40; - - static u8 const MAGIC[OFFS_BASETIME - OFFS_MAGIC]; - - u8 m_data[OFFS_END]; -}; - - // ======================> input_device_default // device defined default input settings @@ -798,7 +359,7 @@ public: ioport_group group() const noexcept { return m_group; } u8 player() const noexcept { return m_player; } const char *token() const noexcept { return m_token; } - const char *name() const noexcept { return m_name; } + std::string name() const; input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) noexcept { return m_defseq[seqtype]; } const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_defseq[seqtype]; } const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_seq[seqtype]; } @@ -1026,6 +587,7 @@ public: u8 player() const { return m_player; } bool digital_value() const { return m_digital_value; } void set_value(ioport_value value); + void clear_value(); bool optional() const { return ((m_flags & FIELD_FLAG_OPTIONAL) != 0); } bool cocktail() const { return ((m_flags & FIELD_FLAG_COCKTAIL) != 0); } @@ -1037,7 +599,7 @@ public: bool analog_invert() const { return ((m_flags & ANALOG_FLAG_INVERT) != 0); } u8 impulse() const noexcept { return m_impulse; } - const char *name() const; + std::string name() const; const char *specific_name() const noexcept { return m_name; } const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept; const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept; @@ -1262,8 +824,9 @@ public: float crosshair_read(); void frame_update(running_machine &machine); - // setters + // programmatic override (for script bindings) void set_value(s32 value); + void clear_value(); private: // helpers @@ -1276,10 +839,11 @@ private: ioport_field & m_field; // pointer to the input field referenced // adjusted values (right-justified and tweaked) - u8 m_shift; // shift to align final value in the port - s32 m_adjdefvalue; // adjusted default value from the config + u8 const m_shift; // shift to align final value in the port + s32 const m_adjdefvalue; // adjusted default value from the config s32 m_adjmin; // adjusted minimum value from the config s32 m_adjmax; // adjusted maximum value from the config + s32 m_adjoverride; // programmatically set adjusted value // live values of configurable parameters s32 m_sensitivity; // current live sensitivity (100=normal) @@ -1291,7 +855,6 @@ private: s32 m_accum; // accumulated value (including relative adjustments) s32 m_previous; // previous adjusted value s32 m_previousanalog; // previous analog value - s32 m_prog_analog_value; // programmatically set analog value // parameters for modifying live values s32 m_minimum; // minimum adjusted value @@ -1313,7 +876,7 @@ private: bool m_single_scale; // scale joystick differently if default is between min/max bool m_interpolate; // should we do linear interpolation for mid-frame reads? bool m_lastdigital; // was the last modification caused by a digital form? - bool m_was_written; // was the last modification caused programmatically? + bool m_use_adjoverride; // override what will be read from the field }; @@ -1382,7 +945,7 @@ public: // type helpers const std::vector<input_type_entry> &types() const noexcept { return m_typelist; } bool type_pressed(ioport_type type, int player = 0); - const char *type_name(ioport_type type, u8 player) const noexcept; + std::string type_name(ioport_type type, u8 player) const; ioport_group type_group(ioport_type type, int player) const noexcept; const input_seq &type_seq(ioport_type type, int player = 0, input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept; void set_type_seq(ioport_type type, int player, input_seq_type seqtype, const input_seq &newseq) noexcept; @@ -1399,7 +962,7 @@ public: private: // internal helpers void init_port_types(); - void init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame); + void init_autoselect_devices(std::initializer_list<ioport_type> types, std::string_view option, std::string_view ananame); void frame_update_callback(); void frame_update(); @@ -1414,6 +977,7 @@ private: bool load_default_config(int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]); bool load_controller_config(util::xml::data_node const &portnode, int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]); void load_system_config(util::xml::data_node const &portnode, int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]); + void apply_device_defaults(); void save_config(config_type cfg_type, util::xml::data_node *parentnode); bool save_this_input_field_type(ioport_type type); @@ -1449,8 +1013,8 @@ private: attoseconds_t m_last_delta_nsec; // nanoseconds that passed since the previous callback // playback/record information - emu_file m_record_file; // recording file (closed if not recording) - emu_file m_playback_file; // playback file (closed if not recording) + std::unique_ptr<emu_file> m_record_file; // recording file (nullptr if not recording) + std::unique_ptr<emu_file> m_playback_file; // playback file (nullptr if not recording) util::write_stream::ptr m_record_stream; // recording stream (nullptr if not recording) util::read_stream::ptr m_playback_stream; // playback stream (nullptr if not recording) u64 m_playback_accumulated_speed; // accumulated speed during playback @@ -1458,6 +1022,7 @@ private: // storage for inactive configuration std::unique_ptr<util::xml::file> m_deselected_card_config; + bool m_applied_device_defaults; }; @@ -1658,10 +1223,10 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s configurer.field_set_crosshair(CROSSHAIR_AXIS_##axis, altaxis, scale, offset); #define PORT_CROSSHAIR_MAPPER(_callback) \ - configurer.field_set_crossmapper(ioport_field_crossmap_delegate(_callback, #_callback, DEVICE_SELF, (device_t *)nullptr)); + configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, DEVICE_SELF, _callback, #_callback)); #define PORT_CROSSHAIR_MAPPER_MEMBER(_device, _class, _member) \ - configurer.field_set_crossmapper(ioport_field_crossmap_delegate(&_class::_member, #_class "::" #_member, _device, (_class *)nullptr)); + configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, _device, &_class::_member, #_class "::" #_member)); // how many optical counts for 1 full turn of the control #define PORT_FULL_TURN_COUNT(_count) \ diff --git a/src/emu/layout/dualhovu.lay b/src/emu/layout/dualhovu.lay index e4fdb3bf943..0cd46b2d5c7 100644 --- a/src/emu/layout/dualhovu.lay +++ b/src/emu/layout/dualhovu.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <view name="Dual Over-Under"> diff --git a/src/emu/layout/dualhsxs.lay b/src/emu/layout/dualhsxs.lay index 18a9eaf908a..f032d0fd48d 100644 --- a/src/emu/layout/dualhsxs.lay +++ b/src/emu/layout/dualhsxs.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <view name="Dual Side-by-Side"> diff --git a/src/emu/layout/dualhuov.lay b/src/emu/layout/dualhuov.lay index b03d7a93258..8a94ca43dc7 100644 --- a/src/emu/layout/dualhuov.lay +++ b/src/emu/layout/dualhuov.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <view name="Dual Under-Over"> diff --git a/src/emu/layout/ex800.lay b/src/emu/layout/ex800.lay index 013ea3c4e4c..208fa7bc890 100644 --- a/src/emu/layout/ex800.lay +++ b/src/emu/layout/ex800.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 copyright-holders:Dirk Best --> <mamelayout version="2"> diff --git a/src/emu/layout/exorterm155.lay b/src/emu/layout/exorterm155.lay index 9da2b5ed7ef..28bb61c0d68 100644 --- a/src/emu/layout/exorterm155.lay +++ b/src/emu/layout/exorterm155.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 LEDs for the Motorola EXORterm 155 --> diff --git a/src/emu/layout/generic.h b/src/emu/layout/generic.h index 502e38e0765..4249c3ef68b 100644 --- a/src/emu/layout/generic.h +++ b/src/emu/layout/generic.h @@ -21,6 +21,9 @@ // no screens layouts extern const internal_layout layout_noscreens; // for screenless systems +// single screen layouts +extern const internal_layout layout_monitors; // common monitor aspect ratios + // dual screen layouts extern const internal_layout layout_dualhsxs; // dual 4:3 screens side-by-side extern const internal_layout layout_dualhovu; // dual 4:3 screens above and below diff --git a/src/emu/layout/hp9122c.lay b/src/emu/layout/hp9122c.lay index 46c197908fc..418d8964fbf 100644 --- a/src/emu/layout/hp9122c.lay +++ b/src/emu/layout/hp9122c.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 copyright-holders:Sven Schnelle Hewlett-Packard HP 9122C floppy drive Layout --> diff --git a/src/emu/layout/ie15.lay b/src/emu/layout/ie15.lay index 255e2022ef8..287fcbdf77a 100644 --- a/src/emu/layout/ie15.lay +++ b/src/emu/layout/ie15.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> diff --git a/src/emu/layout/lx800.lay b/src/emu/layout/lx800.lay index 90a7dbbc742..20303e50eab 100644 --- a/src/emu/layout/lx800.lay +++ b/src/emu/layout/lx800.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 copyright-holders:Dirk Best --> <mamelayout version="2"> diff --git a/src/emu/layout/monitors.lay b/src/emu/layout/monitors.lay new file mode 100644 index 00000000000..b7a4f82f75a --- /dev/null +++ b/src/emu/layout/monitors.lay @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<!-- +license:CC0-1.0 +--> +<mamelayout version="2"> + <view name="4:3 Standard"> + <screen tag="screen"> + <bounds left="0" top="0" right="4" bottom="3" /> + </screen> + </view> + <view name="3:4 Portrait"> + <screen tag="screen"> + <bounds left="0" top="0" right="3" bottom="4" /> + </screen> + </view> + <view name="5:4 Two-Page"> + <screen tag="screen"> + <bounds left="0" top="0" right="5" bottom="4" /> + </screen> + </view> + <view name="16:9 Widescreen"> + <screen tag="screen"> + <bounds left="0" top="0" right="16" bottom="9" /> + </screen> + </view> + <view name="21:9 UltraWide"> + <screen tag="screen"> + <bounds left="0" top="0" right="21" bottom="9" /> + </screen> + </view> + <view name="32:9 Super UltraWide"> + <screen tag="screen"> + <bounds left="0" top="0" right="32" bottom="9" /> + </screen> + </view> + <view name="1:1 Air Traffic Control"> + <screen tag="screen"> + <bounds left="0" top="0" right="32" bottom="9" /> + </screen> + </view> +</mamelayout> diff --git a/src/emu/layout/nes_rob.lay b/src/emu/layout/nes_rob.lay new file mode 100644 index 00000000000..c5b10747151 --- /dev/null +++ b/src/emu/layout/nes_rob.lay @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<!-- +license:CC0-1.0 +authors:hap +--> +<mamelayout version="2"> + +<!-- define elements --> + + <element name="text_m1"><text align="1" string="motor 1:"><color red="0.8" green="0.8" blue="0.8" /></text></element> + <element name="text_m2"><text align="1" string="motor 2:"><color red="0.8" green="0.8" blue="0.8" /></text></element> + <element name="text_m3"><text align="1" string="motor 3:"><color red="0.8" green="0.8" blue="0.8" /></text></element> + + <element name="mstatus0"> + <text state="1" align="1" string="DOWN"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="DOWN"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + <element name="mstatus1"> + <text state="1" align="1" string="UP"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="UP"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + <element name="mstatus2"> + <text state="1" align="1" string="CLOSE"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="CLOSE"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + <element name="mstatus3"> + <text state="1" align="1" string="OPEN"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="OPEN"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + <element name="mstatus4"> + <text state="1" align="1" string="RIGHT"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="RIGHT"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + <element name="mstatus5"> + <text state="1" align="1" string="LEFT"><color red="1.0" green="1.0" blue="0.2" /></text> + <text state="0" align="1" string="LEFT"><color red="0.2" green="0.2" blue="0.2" /></text> + </element> + + <element name="led" defstate="0"> + <disk state="1"><color red="1.0" green="0.1" blue="0.15" /></disk> + <disk state="0"><color red="0.15" green="0.015" blue="0.017" /></disk> + </element> + + +<!-- build screen --> + + <view name="Internal Layout"> + <bounds left="4.5" right="17" top="7" bottom="14.25" /> + + <element ref="text_m1"><bounds x="5.5" y="10" width="5" height="1" /></element> + <element ref="text_m2"><bounds x="5.5" y="11.25" width="5" height="1" /></element> + <element ref="text_m3"><bounds x="5.5" y="12.5" width="5" height="1" /></element> + + <element name="rob_motor.1" ref="mstatus1"><bounds x="10" y="10" width="5" height="1" /></element> + <element name="rob_motor.0" ref="mstatus0"><bounds x="13.5" y="10" width="5" height="1" /></element> + <element name="rob_motor.5" ref="mstatus5"><bounds x="10" y="11.25" width="5" height="1" /></element> + <element name="rob_motor.4" ref="mstatus4"><bounds x="13.5" y="11.25" width="5" height="1" /></element> + <element name="rob_motor.2" ref="mstatus2"><bounds x="10" y="12.5" width="5" height="1" /></element> + <element name="rob_motor.3" ref="mstatus3"><bounds x="13.5" y="12.5" width="5" height="1" /></element> + + <element name="rob_led" ref="led"><bounds x="10" y="8" width="1" height="1" /></element> + + </view> +</mamelayout> diff --git a/src/emu/layout/noscreens.lay b/src/emu/layout/noscreens.lay index 39913376cbb..e74d12e31a5 100644 --- a/src/emu/layout/noscreens.lay +++ b/src/emu/layout/noscreens.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <element name="warning"> @@ -9,9 +9,9 @@ license:CC0 </text> </element> <view name="No screens attached"> - <bounds left="0" top="0" right="280" bottom="150" /> + <bounds left="0" top="0" right="400" bottom="300" /> <element name="warning_txt" ref="warning"> - <bounds left="50" right="230" top="50" bottom="65" /> + <bounds xc="200" yc="150" width="400" height="25" /> </element> </view> </mamelayout> diff --git a/src/emu/layout/quadhsxs.lay b/src/emu/layout/quadhsxs.lay index 1da154bb024..d8f776cb238 100644 --- a/src/emu/layout/quadhsxs.lay +++ b/src/emu/layout/quadhsxs.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <view name="Quad Side-by-Side"> diff --git a/src/emu/layout/qx10ascii.lay b/src/emu/layout/qx10ascii.lay new file mode 100644 index 00000000000..c00c7c88876 --- /dev/null +++ b/src/emu/layout/qx10ascii.lay @@ -0,0 +1,98 @@ +<?xml version="1.0"?> +<!-- +license:CC0-1.0 +--> +<mamelayout version="2"> + <element name="led" defstate="1"> + <disk state="0"> + <color red="0.75" green="0.0" blue="0.0" /> + </disk> + <disk state="1"> + <color red="0.20" green="0.0" blue="0.0" /> + </disk> + </element> + + <element name="capslock"> + <text string="CAPS"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="insert"> + <text string="INS"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf1"> + <text string="SF1"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf2"> + <text string="SF2"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf3"> + <text string="SF3"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf4"> + <text string="SF4"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + + <view name="Default Layout"> + <screen index="0"> + <bounds x="0" y="30" width="640" height="480" /> + </screen> + + <element name="led0" ref="led"> + <bounds x="33" y="17" width="10" height="10" /> + </element> + + <element name="led2" ref="led"> + <bounds x="53" y="17" width="10" height="10" /> + </element> + + <element name="led7" ref="led"> + <bounds x="83" y="17" width="10" height="10" /> + </element> + + <element name="led6" ref="led"> + <bounds x="103" y="17" width="10" height="10" /> + </element> + + <element name="led5" ref="led"> + <bounds x="123" y="17" width="10" height="10" /> + </element> + <element name="led4" ref="led"> + <bounds x="143" y="17" width="10" height="10" /> + </element> + + <element name="label1" ref="capslock"> + <bounds x="31" y="0" width="15" height="15" /> + </element> + + <element name="label2" ref="insert"> + <bounds x="51" y="0" width="15" height="15" /> + </element> + + <element name="label3" ref="sf1"> + <bounds x="81" y="0" width="15" height="15" /> + </element> + + <element name="label4" ref="sf2"> + <bounds x="101" y="0" width="15" height="15" /> + </element> + + <element name="label5" ref="sf3"> + <bounds x="121" y="0" width="15" height="15" /> + </element> + + <element name="label6" ref="sf4"> + <bounds x="141" y="0" width="15" height="15" /> + </element> + </view> +</mamelayout> diff --git a/src/emu/layout/qx10hasci.lay b/src/emu/layout/qx10hasci.lay new file mode 100644 index 00000000000..f0dadc6a0fa --- /dev/null +++ b/src/emu/layout/qx10hasci.lay @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<!-- +license:CC0-1.0 +--> +<mamelayout version="2"> + <element name="led" defstate="1"> + <disk state="0"> + <color red="0.75" green="0.0" blue="0.0" /> + </disk> + <disk state="1"> + <color red="0.20" green="0.0" blue="0.0" /> + </disk> + </element> + + <element name="capslock"> + <text string="CAPS"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="insert"> + <text string="INS"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf1"> + <text string="CALC"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf2"> + <text string="SCHED"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + <element name="sf3"> + <text string="DRAW"> + <color red="1.0" green="1.0" blue="1.0" /> + </text> + </element> + + <view name="Default Layout"> + <screen index="0"> + <bounds x="0" y="30" width="640" height="480" /> + </screen> + + <element name="led3" ref="led"> + <bounds x="33" y="17" width="10" height="10" /> + </element> + + <element name="led2" ref="led"> + <bounds x="53" y="17" width="10" height="10" /> + </element> + + <element name="led7" ref="led"> + <bounds x="83" y="17" width="10" height="10" /> + </element> + + <element name="led6" ref="led"> + <bounds x="103" y="17" width="10" height="10" /> + </element> + + <element name="led5" ref="led"> + <bounds x="123" y="17" width="10" height="10" /> + </element> + + <element name="label1" ref="capslock"> + <bounds x="31" y="0" width="15" height="15" /> + </element> + + <element name="label2" ref="insert"> + <bounds x="51" y="0" width="15" height="15" /> + </element> + + <element name="label3" ref="sf1"> + <bounds x="81" y="0" width="15" height="15" /> + </element> + + <element name="label4" ref="sf2"> + <bounds x="101" y="0" width="15" height="15" /> + </element> + + <element name="label5" ref="sf3"> + <bounds x="121" y="0" width="15" height="15" /> + </element> + </view> +</mamelayout> diff --git a/src/emu/layout/smartboard.lay b/src/emu/layout/smartboard.lay index 885f914ec67..1b028bc23fe 100644 --- a/src/emu/layout/smartboard.lay +++ b/src/emu/layout/smartboard.lay @@ -1,6 +1,7 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 +authors:Sandro Ronco, hap --> <mamelayout version="2"> @@ -12,7 +13,7 @@ license:CC0 <disk><color red="0.1" green="0.05" blue="0.07" /></disk> </element> <element name="ledr" defstate="0"> - <disk state="1"> <color red="1" green="0" blue="0" /> </disk> + <disk state="1"><color red="1" green="0" blue="0" /></disk> </element> <element name="piece" defstate="0"> @@ -84,22 +85,22 @@ license:CC0 <image file="chess/bp.svg" state="64"><color alpha="0.5" /></image> </element> - <element name="text_1"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="1"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_2"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="2"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_3"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="3"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_4"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="4"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_5"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="5"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_6"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="6"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_7"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="7"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_8"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="8"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_a"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="A"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_b"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="B"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_c"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="C"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_d"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="D"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_e"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="E"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_f"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="F"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_g"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="G"> <color red="1" green="1" blue="1" /></text> </element> - <element name="text_h"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="H"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_1"> <text string="1"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_2"> <text string="2"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_3"> <text string="3"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_4"> <text string="4"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_5"> <text string="5"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_6"> <text string="6"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_7"> <text string="7"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_8"> <text string="8"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_a"> <text string="A"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_b"> <text string="B"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_c"> <text string="C"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_d"> <text string="D"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_e"> <text string="E"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_f"> <text string="F"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_g"> <text string="G"> <color red="1" green="1" blue="1" /></text> </element> + <element name="text_h"> <text string="H"> <color red="1" green="1" blue="1" /></text> </element> <!-- sb board --> @@ -317,43 +318,23 @@ license:CC0 <element name="text_uit1"><text string="S.BOARD"><color red="0.81" green="0.8" blue="0.79" /></text></element> <element name="text_uit2"><text string="INTERFACE"><color red="0.81" green="0.8" blue="0.79" /></text></element> <element name="text_uib1"><text string="BOARD:"><color red="0.81" green="0.8" blue="0.79" /></text></element> - <element name="text_uib2"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string="RESET"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> - <element name="text_uib3"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string="CLEAR"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> + <element name="text_uib2"><text string="RESET"><color red="0.01" green="0.01" blue="0.01" /></text></element> + <element name="text_uib3"><text string="CLEAR"><color red="0.01" green="0.01" blue="0.01" /></text></element> <element name="text_uis1"><text string="SPAWN:"><color red="0.81" green="0.8" blue="0.79" /></text></element> <element name="text_uih1"><text string="HAND:"><color red="0.81" green="0.8" blue="0.79" /></text></element> - <element name="text_uih2"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string="REMOVE"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> + <element name="text_uih2"><text string="REMOVE"><color red="0.01" green="0.01" blue="0.01" /></text></element> <element name="text_uiu1"><text string="UNDO:"><color red="0.81" green="0.8" blue="0.79" /></text></element> - <element name="text_uiu2a"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string=" <<"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> - <element name="text_uiu2b"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string=" < "><color red="0.01" green="0.01" blue="0.01" /></text> - </element> - <element name="text_uiu2c"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string=" >"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> - <element name="text_uiu2d"> - <rect><color red="0.84" green="0.75" blue="0.50" /></rect> - <text string=" >>"><color red="0.01" green="0.01" blue="0.01" /></text> - </element> + <element name="text_uiu2a"><text string=" <<"><color red="0.01" green="0.01" blue="0.01" /></text></element> + <element name="text_uiu2b"><text string=" < "><color red="0.01" green="0.01" blue="0.01" /></text></element> + <element name="text_uiu2c"><text string=" >"><color red="0.01" green="0.01" blue="0.01" /></text></element> + <element name="text_uiu2d"><text string=" >>"><color red="0.01" green="0.01" blue="0.01" /></text></element> + <element name="text_uiu3b"><text string="/"><color red="0.81" green="0.8" blue="0.79" /></text></element> + <element name="text_uiu3a" defstate="0"> <simplecounter maxstate="999" digits="1" align="2"> <color red="0.81" green="0.8" blue="0.79" /> </simplecounter> </element> - <element name="text_uiu3b"><text string="/"><color red="0.81" green="0.8" blue="0.79" /></text></element> <element name="text_uiu3c" defstate="0"> <simplecounter maxstate="999" digits="1" align="1"> <color red="0.81" green="0.8" blue="0.79" /> diff --git a/src/emu/layout/triphsxs.lay b/src/emu/layout/triphsxs.lay index 4988b808100..4d7c0733956 100644 --- a/src/emu/layout/triphsxs.lay +++ b/src/emu/layout/triphsxs.lay @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- -license:CC0 +license:CC0-1.0 --> <mamelayout version="2"> <view name="Triple Side-by-Side"> diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index b70ffb69931..573c1b9e095 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -10,26 +10,31 @@ #include "emu.h" -#include "emuopts.h" -#include "osdepend.h" #include "config.h" -#include "debugger.h" -#include "render.h" -#include "uiinput.h" #include "crsshair.h" -#include "debug/debugvw.h" #include "debug/debugcpu.h" +#include "debug/debugvw.h" +#include "debugger.h" #include "dirtc.h" +#include "emuopts.h" +#include "fileio.h" +#include "http.h" #include "image.h" +#include "main.h" +#include "natkeyboard.h" #include "network.h" +#include "render.h" #include "romload.h" #include "tilemap.h" -#include "natkeyboard.h" +#include "uiinput.h" + #include "ui/uimain.h" #include "corestr.h" #include "unzip.h" +#include "osdepend.h" + #include <rapidjson/writer.h> #include <rapidjson/stringbuffer.h> @@ -55,29 +60,28 @@ osd_interface &running_machine::osd() const //------------------------------------------------- running_machine::running_machine(const machine_config &_config, machine_manager &manager) - : m_side_effects_disabled(0), - debug_flags(0), - m_config(_config), - m_system(_config.gamedrv()), - m_manager(manager), - m_current_phase(machine_phase::PREINIT), - m_paused(false), - m_hard_reset_pending(false), - m_exit_pending(false), - m_soft_reset_timer(nullptr), - m_rand_seed(0x9d14abd7), - m_ui_active(_config.options().ui_active()), - m_basename(_config.gamedrv().name), - m_sample_rate(_config.options().sample_rate()), - m_saveload_schedule(saveload_schedule::NONE), - m_saveload_schedule_time(attotime::zero), - m_saveload_searchpath(nullptr), - - m_save(*this), - m_memory(*this), - m_ioport(*this), - m_parameters(*this), - m_scheduler(*this) + : m_side_effects_disabled(0) + , debug_flags(0) + , m_config(_config) + , m_system(_config.gamedrv()) + , m_manager(manager) + , m_current_phase(machine_phase::PREINIT) + , m_paused(false) + , m_hard_reset_pending(false) + , m_exit_pending(false) + , m_soft_reset_timer(nullptr) + , m_rand_seed(0x9d14abd7) + , m_basename(_config.gamedrv().name) + , m_sample_rate(_config.options().sample_rate()) + , m_saveload_schedule(saveload_schedule::NONE) + , m_saveload_schedule_time(attotime::zero) + , m_saveload_searchpath(nullptr) + + , m_save(*this) + , m_memory(*this) + , m_ioport(*this) + , m_parameters(*this) + , m_scheduler(*this) { memset(&m_base_time, 0, sizeof(m_base_time)); @@ -120,7 +124,10 @@ std::string running_machine::describe_context() const } } - return std::string("(no context)"); + if (m_current_phase == machine_phase::RESET) + return std::string("(reset phase)"); + else + return std::string("(no context)"); } @@ -143,12 +150,13 @@ void running_machine::start() // initialize UI input m_ui_input = std::make_unique<ui_input_manager>(*this); - // init the osd layer + // init the OSD layer m_manager.osd().init(*this); - // create the video manager + // create the video manager and UI manager m_video = std::make_unique<video_manager>(*this); m_ui = manager().create_ui(*this); + m_ui->set_startup_text("Initializing...", true); // initialize the base time (needed for doing record/playback) ::time(&m_base_time); @@ -318,7 +326,7 @@ int running_machine::run(bool quiet) // run the CPUs until a reset or exit while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != saveload_schedule::NONE) { - g_profiler.start(PROFILER_EXTRA); + auto profile = g_profiler.start(PROFILER_EXTRA); // execute CPUs if not paused if (!m_paused) @@ -330,8 +338,6 @@ int running_machine::run(bool quiet) // handle save/load if (m_saveload_schedule != saveload_schedule::NONE) handle_saveload(); - - g_profiler.stop(); } m_manager.http()->clear(); @@ -344,29 +350,29 @@ int running_machine::run(bool quiet) nvram_save(); m_configuration->save_settings(); } - catch (emu_fatalerror &fatal) + catch (emu_fatalerror const &fatal) { osd_printf_error("Fatal error: %s\n", fatal.what()); error = EMU_ERR_FATALERROR; if (fatal.exitcode() != 0) error = fatal.exitcode(); } - catch (emu_exception &) + catch (emu_exception const &) { osd_printf_error("Caught unhandled emulator exception\n"); error = EMU_ERR_FATALERROR; } - catch (binding_type_exception &btex) + catch (binding_type_exception const &btex) { osd_printf_error("Error performing a late bind of function expecting type %s to instance of type %s\n", btex.target_type().name(), btex.actual_type().name()); error = EMU_ERR_FATALERROR; } - catch (tag_add_exception &aex) + catch (tag_add_exception const &aex) { osd_printf_error("Tag '%s' already exists in tagged map\n", aex.tag()); error = EMU_ERR_FATALERROR; } - catch (std::exception &ex) + catch (std::exception const &ex) { osd_printf_error("Caught unhandled %s exception: %s\n", typeid(ex).name(), ex.what()); error = EMU_ERR_FATALERROR; @@ -589,10 +595,10 @@ void running_machine::schedule_save(std::string &&filename) // immediate_save - save state. //------------------------------------------------- -void running_machine::immediate_save(const char *filename) +void running_machine::immediate_save(std::string_view filename) { // specify the filename to save or load - set_saveload_filename(filename); + set_saveload_filename(std::string(filename)); // set up some parameters for handle_saveload() m_saveload_schedule = saveload_schedule::SAVE; @@ -626,10 +632,10 @@ void running_machine::schedule_load(std::string &&filename) // immediate_load - load state. //------------------------------------------------- -void running_machine::immediate_load(const char *filename) +void running_machine::immediate_load(std::string_view filename) { // specify the filename to save or load - set_saveload_filename(filename); + set_saveload_filename(std::string(filename)); // set up some parameters for handle_saveload() m_saveload_schedule = saveload_schedule::LOAD; @@ -857,6 +863,7 @@ void running_machine::handle_saveload() if (!m_saveload_pending_file.empty()) { const char *const opname = (m_saveload_schedule == saveload_schedule::LOAD) ? "load" : "save"; + const char *const preposname = (m_saveload_schedule == saveload_schedule::LOAD) ? "from" : "to"; // if there are anonymous timers, we can't save just yet, and we can't load yet either // because the timers might overwrite data we have loaded @@ -864,7 +871,7 @@ void running_machine::handle_saveload() { // if more than a second has passed, we're probably screwed if ((this->time() - m_saveload_schedule_time) > attotime::from_seconds(1)) - popmessage("Unable to %s due to pending anonymous timers. See error.log for details.", opname); + popmessage("Error: Unable to %s state %s %s due to pending anonymous timers. See error.log for details.", opname, preposname, m_saveload_pending_file); else return; // return without cancelling the operation } @@ -877,39 +884,36 @@ void running_machine::handle_saveload() auto const filerr = file.open(m_saveload_pending_file); if (!filerr) { - const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "loaded" : "saved"; - // read/write the save state save_error saverr = (m_saveload_schedule == saveload_schedule::LOAD) ? m_save.read_file(file) : m_save.write_file(file); // handle the result switch (saverr) { - case STATERR_ILLEGAL_REGISTRATIONS: - popmessage("Error: Unable to %s state due to illegal registrations. See error.log for details.", opname); - break; - case STATERR_INVALID_HEADER: - popmessage("Error: Unable to %s state due to an invalid header. Make sure the save state is correct for this machine.", opname); + popmessage("Error: Unable to %s state %s %s due to an invalid header. Make sure the save state is correct for this system.", opname, preposname, m_saveload_pending_file); break; case STATERR_READ_ERROR: - popmessage("Error: Unable to %s state due to a read error (file is likely corrupt).", opname); + popmessage("Error: Unable to %s state %s %s due to a read error (file is likely corrupt).", opname, preposname, m_saveload_pending_file); break; case STATERR_WRITE_ERROR: - popmessage("Error: Unable to %s state due to a write error. Verify there is enough disk space.", opname); + popmessage("Error: Unable to %s state %s %s due to a write error. Verify there is enough disk space.", opname, preposname, m_saveload_pending_file); break; case STATERR_NONE: + { + const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "Loaded" : "Saved"; if (!(m_system.flags & MACHINE_SUPPORTS_SAVE)) - popmessage("State successfully %s.\nWarning: Save states are not officially supported for this machine.", opnamed); + popmessage("%s state %s %s.\nWarning: Save states are not officially supported for this system.", opnamed, preposname, m_saveload_pending_file); else - popmessage("State successfully %s.", opnamed); + popmessage("%s state %s %s.", opnamed, preposname, m_saveload_pending_file); break; + } default: - popmessage("Error: Unknown error during state %s.", opnamed); + popmessage("Error: Unknown error during %s state %s %s.", opname, preposname, m_saveload_pending_file); break; } @@ -920,11 +924,11 @@ void running_machine::handle_saveload() else if ((openflags == OPEN_FLAG_READ) && (std::errc::no_such_file_or_directory == filerr)) { // attempt to load a non-existent savestate, report empty slot - popmessage("Error: No savestate file to load.", opname); + popmessage("Error: Load state file %s not found.", m_saveload_pending_file); } else { - popmessage("Error: Failed to open file for %s operation.", opname); + popmessage("Error: Failed to open %s for %s state operation.", m_saveload_pending_file, opname); } } } @@ -941,7 +945,7 @@ void running_machine::handle_saveload() // of the system //------------------------------------------------- -void running_machine::soft_reset(void *ptr, s32 param) +void running_machine::soft_reset(s32 param) { logerror("Soft reset\n"); @@ -972,6 +976,17 @@ void running_machine::logfile_callback(const char *buffer) //------------------------------------------------- +// steal_debuglogfile - relinquish ownership of +// the debug.log file +//------------------------------------------------- + +std::unique_ptr<emu_file> running_machine::steal_debuglogfile() +{ + return std::move(m_debuglogfile); +} + + +//------------------------------------------------- // start_all_devices - start any unstarted devices //------------------------------------------------- @@ -1118,9 +1133,10 @@ void running_machine::nvram_load() for (device_nvram_interface &nvram : nvram_interface_enumerator(root_device())) { emu_file file(options().nvram_directory(), OPEN_FLAG_READ); - if (!file.open(nvram_filename(nvram.device()))) + if (nvram.nvram_backup_enabled() && !file.open(nvram_filename(nvram.device()))) { - nvram.nvram_load(file); + if (!nvram.nvram_load(file)) + osd_printf_error("Error reading NVRAM file %s\n", file.filename()); file.close(); } else @@ -1142,7 +1158,17 @@ void running_machine::nvram_save() emu_file file(options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); if (!file.open(nvram_filename(nvram.device()))) { - nvram.nvram_save(file); + bool error = false; + + if (!nvram.nvram_save(file)) + { + error = true; + osd_printf_error("Error writing NVRAM file %s\n", file.filename()); + } + + // close and perhaps delete the file + if (error || file.size() == 0) + file.remove_on_close(); file.close(); } } @@ -1159,7 +1185,7 @@ void running_machine::popup_clear() const ui().popup_time(0, " "); } -void running_machine::popup_message(util::format_argument_pack<std::ostream> const &args) const +void running_machine::popup_message(util::format_argument_pack<char> const &args) const { std::string const temp(string_format(args)); ui().popup_time(temp.length() / 40 + 2, "%s", temp); @@ -1281,7 +1307,7 @@ void running_machine::emscripten_main_loop() { running_machine *machine = emscripten_running_machine; - g_profiler.start(PROFILER_EXTRA); + auto profile = g_profiler.start(PROFILER_EXTRA); // execute CPUs if not paused if (!machine->m_paused) @@ -1314,8 +1340,6 @@ void running_machine::emscripten_main_loop() { emscripten_cancel_main_loop(); } - - g_profiler.stop(); } void running_machine::emscripten_set_running_machine(running_machine *machine) diff --git a/src/emu/machine.h b/src/emu/machine.h index f3aef08d265..7b4efec70da 100644 --- a/src/emu/machine.h +++ b/src/emu/machine.h @@ -128,7 +128,7 @@ public: sound_manager &sound() const { assert(m_sound != nullptr); return *m_sound; } video_manager &video() const { assert(m_video != nullptr); return *m_video; } network_manager &network() const { assert(m_network != nullptr); return *m_network; } - bookkeeping_manager &bookkeeping() const { assert(m_network != nullptr); return *m_bookkeeping; } + bookkeeping_manager &bookkeeping() const { assert(m_bookkeeping != nullptr); return *m_bookkeeping; } configuration_manager &configuration() const { assert(m_configuration != nullptr); return *m_configuration; } output_manager &output() const { assert(m_output != nullptr); return *m_output; } ui_manager &ui() const { assert(m_ui != nullptr); return *m_ui; } @@ -145,7 +145,6 @@ public: bool paused() const { return m_paused || (m_current_phase != machine_phase::RUNNING); } bool exit_pending() const { return m_exit_pending; } bool hard_reset_pending() const { return m_hard_reset_pending; } - bool ui_active() const { return m_ui_active; } const std::string &basename() const { return m_basename; } int sample_rate() const { return m_sample_rate; } bool save_or_load_pending() const { return !m_saveload_pending_file.empty(); } @@ -172,13 +171,12 @@ public: void add_notifier(machine_notification event, machine_notify_delegate callback, bool first = false); void call_notifiers(machine_notification which); void add_logerror_callback(logerror_callback callback); - void set_ui_active(bool active) { m_ui_active = active; } void debug_break(); void export_http_api(); // TODO: Do saves and loads still require scheduling? - void immediate_save(const char *filename); - void immediate_load(const char *filename); + void immediate_save(std::string_view filename); + void immediate_load(std::string_view filename); // rewind operations bool rewind_capture(); @@ -217,7 +215,7 @@ public: bool debug_enabled() { return (debug_flags & DEBUG_FLAG_ENABLED) != 0; } // used by debug_console to take ownership of the debug.log file - std::unique_ptr<emu_file> steal_debuglogfile() { return std::move(m_debuglogfile); } + std::unique_ptr<emu_file> steal_debuglogfile(); private: class side_effects_disabler { @@ -248,12 +246,12 @@ private: void start(); void set_saveload_filename(std::string &&filename); void handle_saveload(); - void soft_reset(void *ptr = nullptr, s32 param = 0); + void soft_reset(s32 param = 0); std::string nvram_filename(device_t &device) const; void nvram_load(); void nvram_save(); void popup_clear() const; - void popup_message(util::format_argument_pack<std::ostream> const &args) const; + void popup_message(util::format_argument_pack<char> const &args) const; // internal callbacks void logfile_callback(const char *buffer); @@ -297,7 +295,6 @@ private: // misc state u32 m_rand_seed; // current random number seed - bool m_ui_active; // ui active or not (useful for games / systems with keyboard inputs) time_t m_base_time; // real time at initial emulation time std::string m_basename; // basename used for game-related paths int m_sample_rate; // the digital audio sample rate @@ -400,7 +397,7 @@ inline void running_machine::logerror(Format &&fmt, Params &&... args) const // process only if there is a target if (allow_logging()) { - g_profiler.start(PROFILER_LOGERROR); + auto profile = g_profiler.start(PROFILER_LOGERROR); // dump to the buffer m_string_buffer.clear(); @@ -409,9 +406,7 @@ inline void running_machine::logerror(Format &&fmt, Params &&... args) const m_string_buffer.put('\0'); strlog(&m_string_buffer.vec()[0]); - - g_profiler.stop(); } } -#endif /* MAME_EMU_MACHINE_H */ +#endif // MAME_EMU_MACHINE_H diff --git a/src/emu/main.cpp b/src/emu/main.cpp index e5467238238..12cde5cf299 100644 --- a/src/emu/main.cpp +++ b/src/emu/main.cpp @@ -9,17 +9,32 @@ ***************************************************************************/ #include "emu.h" +#include "main.h" + #include "emuopts.h" +#include "http.h" + -machine_manager::machine_manager(emu_options& options, osd_interface& osd) - : m_osd(osd), +machine_manager::machine_manager(emu_options& options, osd_interface& osd) : + m_osd(osd), m_options(options), m_machine(nullptr) { } + +machine_manager::~machine_manager() +{ +} + + void machine_manager::start_http_server() { m_http = std::make_unique<http_manager>(options().http(), options().http_port(), options().http_root()); } + +http_manager *machine_manager::http() +{ + return m_http.get(); +} diff --git a/src/emu/main.h b/src/emu/main.h index 3c75205de14..78553ca5236 100644 --- a/src/emu/main.h +++ b/src/emu/main.h @@ -6,18 +6,17 @@ Controls execution of the core emulator system. ***************************************************************************/ +#ifndef MAME_EMU_MAIN_H +#define MAME_EMU_MAIN_H #pragma once -#ifndef __EMU_H__ -#error Dont include this file directly; include emu.h instead. -#endif +#include "emufwd.h" -#ifndef MAME_EMU_MAIN_H -#define MAME_EMU_MAIN_H +#include <memory> +#include <string> +#include <vector> -#include <thread> -#include <ctime> //************************************************************************** // CONSTANTS @@ -55,7 +54,7 @@ public: static void display_ui_chooser(running_machine &machine); static int start_frontend(emu_options &options, osd_interface &osd, std::vector<std::string> &args); static int start_frontend(emu_options &options, osd_interface &osd, int argc, char *argv[]); - static void draw_user_interface(running_machine& machine); + static bool draw_user_interface(running_machine& machine); static void periodic_check(); static bool frame_hook(); static void sound_hook(); @@ -66,12 +65,13 @@ public: class machine_manager { - DISABLE_COPYING(machine_manager); protected: // construction/destruction - machine_manager(emu_options& options, osd_interface& osd); + machine_manager(emu_options &options, osd_interface &osd); + machine_manager(machine_manager const &) = delete; + public: - virtual ~machine_manager() { } + virtual ~machine_manager(); osd_interface &osd() const { return m_osd; } emu_options &options() const { return m_options; } @@ -88,7 +88,7 @@ public: virtual void update_machine() { } - http_manager *http() { return m_http.get(); } + http_manager *http(); void start_http_server(); protected: diff --git a/src/emu/mconfig.cpp b/src/emu/mconfig.cpp index fb97c3138a3..2c8c1aa011b 100644 --- a/src/emu/mconfig.cpp +++ b/src/emu/mconfig.cpp @@ -257,24 +257,23 @@ std::pair<const char *, device_t *> machine_config::resolve_owner(const char *ta device_t *owner(m_current_device); // if the device path is absolute, start from the root - if (tag[0] == ':') - { - tag++; - owner = m_root_device.get(); - } + if (!*tag || (':' == *tag) || ('^' == *tag)) + throw emu_fatalerror("Attempting to add device with tag containing parent references '%s'\n", orig_tag); // go down the path until we're done with it - while (strchr(tag, ':')) + char const *next; + while ((next = strchr(tag, ':')) != nullptr) { - const char *next = strchr(tag, ':'); assert(next != tag); std::string_view part(tag, next - tag); owner = owner->subdevices().find(part); if (!owner) - throw emu_fatalerror("Could not find %s when looking up path for device %s\n", part, orig_tag); - tag = next+1; + throw emu_fatalerror("Could not find '%s' when looking up path for device '%s'\n", part, orig_tag); + tag = next + 1; + if ('^' == *tag) + throw emu_fatalerror("Attempting to add device with tag containing parent references '%s'\n", orig_tag); } - assert(tag[0] != '\0'); + assert(*tag != '\0'); return std::make_pair(tag, owner); } @@ -296,7 +295,7 @@ std::tuple<const char *, device_t *, device_t *> machine_config::prepare_replace if (old_device) remove_references(*old_device); else - osd_printf_warning("Warning: attempting to replace non-existent device '%s'\n", tag); + throw emu_fatalerror("Attempting to replace non-existent device '%s'\n", tag); return std::make_tuple(owner.first, owner.second, old_device); } diff --git a/src/emu/mconfig.h b/src/emu/mconfig.h index c600ca06665..c6cacde581f 100644 --- a/src/emu/mconfig.h +++ b/src/emu/mconfig.h @@ -133,7 +133,7 @@ public: /// replace an existing device. /// \return A device replacement helper to pass to a device type /// when replacing an existing device. - emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace(*this); }; + emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace(*this); } /// \brief Set internal layout for current device /// diff --git a/src/emu/memarray.cpp b/src/emu/memarray.cpp index 22bfa17b80a..eb03974ff1c 100644 --- a/src/emu/memarray.cpp +++ b/src/emu/memarray.cpp @@ -90,11 +90,6 @@ void memory_array::set(void *base, u32 bytes, int membits, endianness_t endianne // set - additional setter variants //------------------------------------------------- -void memory_array::set(const address_space &space, void *base, u32 bytes, int bpe) -{ - set(base, bytes, space.data_width(), space.endianness(), bpe); -} - void memory_array::set(const memory_share &share, int bpe) { set(share.ptr(), share.bytes(), share.bitwidth(), share.endianness(), bpe); @@ -139,8 +134,8 @@ void memory_array::write8_to_32le(int index, u32 data) { reinterpret_cast<u8 *>( u32 memory_array::read8_from_32be(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE4_XOR_BE(index)]; } void memory_array::write8_to_32be(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE4_XOR_BE(index)] = data; } -u32 memory_array::read8_from_64le(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)]; } -void memory_array::write8_to_64le(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)] = data; } +u32 memory_array::read8_from_64le(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_LE(index)]; } +void memory_array::write8_to_64le(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_LE(index)] = data; } u32 memory_array::read8_from_64be(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)]; } void memory_array::write8_to_64be(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)] = data; } diff --git a/src/emu/memarray.h b/src/emu/memarray.h index f9a7e406a8e..fc7e47c4b3c 100644 --- a/src/emu/memarray.h +++ b/src/emu/memarray.h @@ -42,14 +42,12 @@ public: memory_array(); memory_array(void *base, u32 bytes, int membits, endianness_t endianness, int bpe) { set(base, bytes, membits, endianness, bpe); } template <typename _Type> memory_array(std::vector<_Type> &array, endianness_t endianness, int bpe) { set(array, endianness, bpe); } - memory_array(const address_space &space, void *base, u32 bytes, int bpe) { set(space, base, bytes, bpe); } memory_array(const memory_share &share, int bpe) { set(share, bpe); } memory_array(const memory_array &array) { set(array); } // configuration void set(void *base, u32 bytes, int membits, endianness_t endianness, int bpe); template <typename _Type> void set(std::vector<_Type> &array, endianness_t endianness, int bpe) { set(&array[0], array.size(), 8*sizeof(_Type), endianness, bpe); } - void set(const address_space &space, void *base, u32 bytes, int bpe); void set(const memory_share &share, int bpe); void set(const memory_array &array); diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp index e5dcdc93dbc..681f64cd263 100644 --- a/src/emu/natkeyboard.cpp +++ b/src/emu/natkeyboard.cpp @@ -15,6 +15,9 @@ #include "emuopts.h" #include "unicode.h" +// FIXME: allow OSD module headers to be included in a less ugly way +#include "../osd/modules/lib/osdlib.h" + #include <algorithm> #include <cstring> @@ -505,10 +508,10 @@ void natural_keyboard::post_utf8(const char *text, size_t length, const attotime } -void natural_keyboard::post_utf8(const std::string &text, const attotime &rate) +void natural_keyboard::post_utf8(std::string_view text, const attotime &rate) { if (!text.empty()) - post_utf8(text.c_str(), text.size(), rate); + post_utf8(text.data(), text.size(), rate); } @@ -590,10 +593,10 @@ void natural_keyboard::post_coded(const char *text, size_t length, const attotim } -void natural_keyboard::post_coded(const std::string &text, const attotime &rate) +void natural_keyboard::post_coded(std::string_view text, const attotime &rate) { if (!text.empty()) - post_coded(text.c_str(), text.size(), rate); + post_coded(text.data(), text.size(), rate); } @@ -864,7 +867,7 @@ void natural_keyboard::internal_post(char32_t ch) // when posting a string of characters //------------------------------------------------- -void natural_keyboard::timer(void *ptr, int param) +void natural_keyboard::timer(s32 param) { if (!m_queue_chars.isnull()) { diff --git a/src/emu/natkeyboard.h b/src/emu/natkeyboard.h index c3454ee8dd4..c14de66fa66 100644 --- a/src/emu/natkeyboard.h +++ b/src/emu/natkeyboard.h @@ -16,6 +16,7 @@ #include <functional> #include <iosfwd> #include <string> +#include <string_view> #include <unordered_map> #include <vector> @@ -63,9 +64,9 @@ public: void post_char(char32_t ch, bool normalize_crlf = false); void post(const char32_t *text, size_t length = 0, const attotime &rate = attotime::zero); void post_utf8(const char *text, size_t length = 0, const attotime &rate = attotime::zero); - void post_utf8(const std::string &text, const attotime &rate = attotime::zero); + void post_utf8(std::string_view text, const attotime &rate = attotime::zero); void post_coded(const char *text, size_t length = 0, const attotime &rate = attotime::zero); - void post_coded(const std::string &text, const attotime &rate = attotime::zero); + void post_coded(std::string_view text, const attotime &rate = attotime::zero); void paste(); // debugging @@ -109,7 +110,7 @@ private: bool can_post_alternate(char32_t ch); attotime choose_delay(char32_t ch); void internal_post(char32_t ch); - void timer(void *ptr, int param); + void timer(s32 param); std::string unicode_to_string(char32_t ch) const; const keycode_map_entry *find_code(char32_t ch) const; diff --git a/src/emu/network.cpp b/src/emu/network.cpp index 68c9f93c196..f5e065ac9cb 100644 --- a/src/emu/network.cpp +++ b/src/emu/network.cpp @@ -8,13 +8,16 @@ ***************************************************************************/ -#include <cctype> - #include "emu.h" #include "network.h" + #include "config.h" +#include "dinetwork.h" + #include "xmlfile.h" +#include <cctype> + //************************************************************************** // NETWORK MANAGER //************************************************************************** @@ -54,7 +57,7 @@ void network_manager::config_load(config_type cfg_type, config_level cfg_level, network.set_interface(interface); const char *mac_addr = node->get_attribute_string("mac", nullptr); if (mac_addr != nullptr && strlen(mac_addr) == 17) { - char mac[7]; + uint8_t mac[6]; unsigned int mac_num[6]; sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_num[0], &mac_num[1], &mac_num[2], &mac_num[3], &mac_num[4], &mac_num[5]); for (int i = 0; i<6; i++) mac[i] = mac_num[i]; @@ -84,9 +87,9 @@ void network_manager::config_save(config_type cfg_type, util::xml::data_node *pa { node->set_attribute("tag", network.device().tag()); node->set_attribute_int("interface", network.get_interface()); - const char *mac = network.get_mac(); + const std::array<u8, 6> &mac = network.get_mac(); char mac_addr[6 * 3]; - sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", u8(mac[0]), u8(mac[1]), u8(mac[2]), u8(mac[3]), u8(mac[4]), u8(mac[5])); + sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); node->set_attribute("mac", mac_addr); } } diff --git a/src/emu/profiler.cpp b/src/emu/profiler.cpp index 765373e34e7..19f3908f097 100644 --- a/src/emu/profiler.cpp +++ b/src/emu/profiler.cpp @@ -89,8 +89,11 @@ real_profiler_state::real_profiler_state() // reset - initializes state //------------------------------------------------- -void real_profiler_state::reset(bool enabled) +void real_profiler_state::reset(bool enabled) noexcept { + // disabling the profiler from the UI happens while PROFILER_EXTRA is active + //assert(!m_filoptr || (m_filoptr == m_filo)); + m_text_time = attotime::never; if (enabled) @@ -117,10 +120,10 @@ void real_profiler_state::reset(bool enabled) const char *real_profiler_state::text(running_machine &machine) { - start(PROFILER_PROFILER); + auto profile = start(PROFILER_PROFILER); // get the current time - attotime current_time = machine.scheduler().time(); + attotime const current_time = machine.scheduler().time(); // we only want to update the text periodically if ((m_text_time == attotime::never) || ((current_time - m_text_time).as_double() >= TEXT_UPDATE_TIME)) @@ -129,7 +132,6 @@ const char *real_profiler_state::text(running_machine &machine) m_text_time = current_time; } - stop(); return m_text.c_str(); } diff --git a/src/emu/profiler.h b/src/emu/profiler.h index 8341e075eae..8ea65ac7f07 100644 --- a/src/emu/profiler.h +++ b/src/emu/profiler.h @@ -8,11 +8,11 @@ **************************************************************************** - Profiling is scope-based. To start profiling, put a profiler_scope + Profiling is scope-based. To start profiling, put a profiler scope object on the stack. To end profiling, just end the scope: { - profiler_scope scope(PROFILER_VIDEO); + auto scope = g_profiler.start(PROFILER_VIDEO); your_work_here(); } @@ -26,6 +26,17 @@ #pragma once +#include "emufwd.h" + +#include "attotime.h" + +#include "eminline.h" // for get_profile_ticks() +#include "osdcore.h" + +#include <cstdio> +#include <cstdlib> +#include <string> + //************************************************************************** // CONSTANTS @@ -83,18 +94,57 @@ DECLARE_ENUM_INCDEC_OPERATORS(profile_type) class real_profiler_state { public: + class scope + { + private: + real_profiler_state &m_host; + bool m_active; + + public: + scope(scope const &) = delete; + scope &operator=(scope const &) = delete; + + scope(scope &&that) noexcept : m_host(that.m_host), m_active(that.m_active) + { + that.m_active = false; + } + + scope(real_profiler_state &host, profile_type type) noexcept : m_host(host), m_active(false) + { + if (m_host.enabled()) + { + m_host.real_start(type); + m_active = true; + } + } + + ~scope() + { + stop(); + } + + void stop() noexcept + { + if (m_active) + { + m_host.real_stop(); + m_active = false; + } + } + }; + // construction/destruction real_profiler_state(); // getters - bool enabled() const + bool enabled() const noexcept { return m_filoptr != nullptr; } const char *text(running_machine &machine); // enable/disable - void enable(bool state = true) + void enable(bool state = true) noexcept { if (state != enabled()) { @@ -103,22 +153,31 @@ public: } // start/stop - void start(profile_type type) { if (enabled()) real_start(type); } - void stop() { if (enabled()) real_stop(); } + [[nodiscard]] auto start(profile_type type) noexcept { return scope(*this, type); } private: - void reset(bool enabled); + // an entry in the FILO + struct filo_entry + { + int type; // type of entry + osd_ticks_t start; // start time + }; + + void reset(bool enabled) noexcept; void update_text(running_machine &machine); //------------------------------------------------- // real_start - mark the beginning of a // profiler entry //------------------------------------------------- - ATTR_FORCE_INLINE void real_start(profile_type type) + ATTR_FORCE_INLINE void real_start(profile_type type) noexcept { // fail if we overflow - if (m_filoptr >= &m_filo[std::size(m_filo) - 1]) - throw emu_fatalerror("Profiler FILO overflow (type = %d)\n", type); + if (UNEXPECTED(m_filoptr >= &m_filo[std::size(m_filo) - 1])) + { + std::fprintf(stderr, "Profiler FILO overflow (type = %d)\n", int(type)); + std::abort(); + } // get current tick count osd_ticks_t curticks = get_profile_ticks(); @@ -137,7 +196,7 @@ private: //------------------------------------------------- // real_stop - mark the end of a profiler entry //------------------------------------------------- - ATTR_FORCE_INLINE void real_stop() + ATTR_FORCE_INLINE void real_stop() noexcept { // degenerate scenario if (UNEXPECTED(m_filoptr <= m_filo)) @@ -156,13 +215,6 @@ private: m_filoptr->start = curticks; } - // an entry in the FILO - struct filo_entry - { - int type; // type of entry - osd_ticks_t start; // start time - }; - // internal state filo_entry * m_filoptr; // current FILO index std::string m_text; // profiler text @@ -177,19 +229,35 @@ private: class dummy_profiler_state { public: + class scope + { + private: + dummy_profiler_state &m_host; + + public: + scope(scope const &) = delete; + scope &operator=(scope const &) = delete; + scope(scope &&that) noexcept = default; + scope(dummy_profiler_state &host, profile_type type) noexcept : m_host(host) { } + ~scope() { m_host.real_stop(); } + void stop() noexcept { } + }; + // construction/destruction dummy_profiler_state(); // getters - bool enabled() const { return false; } + bool enabled() const noexcept { return false; } const char *text(running_machine &machine) { return ""; } // enable/disable - void enable(bool state = true) { } + void enable(bool state = true) noexcept { } // start/stop - void start(profile_type type) { } - void stop() { } + [[nodiscard]] auto start(profile_type type) noexcept { return scope(*this, type); } + +private: + void real_stop() noexcept { } }; @@ -210,4 +278,4 @@ typedef dummy_profiler_state profiler_state; extern profiler_state g_profiler; -#endif /* MAME_EMU_PROFILER_H */ +#endif // MAME_EMU_PROFILER_H diff --git a/src/emu/recording.cpp b/src/emu/recording.cpp index 9e3c1f3f4ae..d9c25c57767 100644 --- a/src/emu/recording.cpp +++ b/src/emu/recording.cpp @@ -9,7 +9,11 @@ ***************************************************************************/ #include "emu.h" + +#include "fileio.h" +#include "main.h" #include "screen.h" + #include "aviio.h" #include "png.h" @@ -175,8 +179,8 @@ bool avi_movie_recording::initialize(running_machine &machine, std::unique_ptr<e // build up information about this new movie avi_file::movie_info info; info.video_format = 0; - info.video_timescale = 1000 * (screen() ? screen()->frame_period().as_hz() : screen_device::DEFAULT_FRAME_RATE); - info.video_sampletime = 1000; + info.video_timescale = 0x3fff'fffc; // multiple of 60, for screenless machines + info.video_sampletime = screen() ? screen()->frame_period().as_ticks(info.video_timescale) : 0x0111'1111; info.video_numsamples = 0; info.video_width = width; info.video_height = height; @@ -191,7 +195,7 @@ bool avi_movie_recording::initialize(running_machine &machine, std::unique_ptr<e info.audio_samplerate = machine.sample_rate(); // compute the frame time - set_frame_period(attotime::from_seconds(1000) / info.video_timescale); + set_frame_period(attotime::from_ticks(info.video_sampletime, info.video_timescale)); // create the file avi_file::error avierr = avi_file::create(fullpath, info, m_avi_file); @@ -218,14 +222,13 @@ bool avi_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const bool avi_movie_recording::add_sound_to_recording(const s16 *sound, int numsamples) { - g_profiler.start(PROFILER_MOVIE_REC); + auto profile = g_profiler.start(PROFILER_MOVIE_REC); // write the next frame avi_file::error avierr = m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1); if (avierr == avi_file::error::NONE) avierr = m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1); - g_profiler.stop(); return avierr == avi_file::error::NONE; } diff --git a/src/emu/render.cpp b/src/emu/render.cpp index 1f9918539d5..571f4e79084 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -41,6 +41,7 @@ #include "corestr.h" #include "emuopts.h" +#include "fileio.h" #include "rendfont.h" #include "rendlay.h" #include "rendutil.h" @@ -56,6 +57,7 @@ #include "util/xmlfile.h" #include <algorithm> +#include <limits> @@ -98,6 +100,40 @@ struct render_target::object_transform }; +struct render_target::pointer_info +{ + pointer_info() noexcept + : type(osd::ui_event_handler::pointer::UNKNOWN) + , oldpos(std::numeric_limits<float>::min(), std::numeric_limits<float>::min()) + , newpos(std::numeric_limits<float>::min(), std::numeric_limits<float>::min()) + , oldbuttons(0U) + , newbuttons(0U) + , edges(0U, 0U) + { + } + + osd::ui_event_handler::pointer type; + std::pair<float, float> oldpos; + std::pair<float, float> newpos; + u32 oldbuttons, newbuttons; + std::pair<size_t, size_t> edges; +}; + + +struct render_target::hit_test +{ + hit_test() noexcept + : inbounds(0U, 0U) + , hit(0U) + { + } + + std::pair<u64, u64> inbounds; + u64 hit; +}; + + + //************************************************************************** // GLOBAL VARIABLES @@ -300,7 +336,8 @@ render_texture::render_texture() m_curseq(0) { m_sbounds.set(0, -1, 0, -1); - memset(m_scaled, 0, sizeof(m_scaled)); + for (auto &elem : m_scaled) + elem.seqid = 0; } @@ -352,6 +389,7 @@ void render_texture::release() m_bitmap = nullptr; m_sbounds.set(0, -1, 0, -1); m_format = TEXFORMAT_ARGB32; + m_scaler = nullptr; m_curseq = 0; } @@ -430,6 +468,7 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo texinfo.base = m_bitmap->raw_pixptr(m_sbounds.top(), m_sbounds.left()); texinfo.rowpixels = m_bitmap->rowpixels(); texinfo.width = swidth; + texinfo.width_margin = m_sbounds.left(); texinfo.height = sheight; // palette will be set later texinfo.seqid = ++m_curseq; @@ -690,7 +729,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length, m_bcglookup.resize(palette->max_index()); recompute_lookups(); } - assert (palette == &m_palclient->palette()); + assert(palette == &m_palclient->palette()); out_length = palette->max_index(); return &m_bcglookup[0]; @@ -880,19 +919,21 @@ render_container::user_settings::user_settings() // render_target - constructor //------------------------------------------------- -render_target::render_target(render_manager &manager, const internal_layout *layoutfile, u32 flags) - : render_target(manager, layoutfile, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags) + : render_target(manager, ui, layoutfile, flags, CONSTRUCTOR_IMPL) { } -render_target::render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags) - : render_target(manager, layout, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags) + : render_target(manager, ui, layout, flags, CONSTRUCTOR_IMPL) { } -template <typename T> render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t) +template <typename T> +render_target::render_target(render_manager &manager, render_container *ui, T &&layout, u32 flags, constructor_impl_t) : m_next(nullptr) , m_manager(manager) + , m_ui_container(ui) , m_curview(0U) , m_flags(flags) , m_listindex(0) @@ -1012,9 +1053,9 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect) m_width = width; m_height = height; m_bounds.x0 = m_bounds.y0 = 0; - m_bounds.x1 = (float)width; - m_bounds.y1 = (float)height; - m_pixel_aspect = pixel_aspect != 0.0? pixel_aspect : 1.0; + m_bounds.x1 = float(width); + m_bounds.y1 = float(height); + m_pixel_aspect = pixel_aspect != 0.0F ? pixel_aspect : 1.0F; } @@ -1027,9 +1068,12 @@ void render_target::set_view(unsigned viewindex) { if (m_views.size() > viewindex) { + forget_pointers(); m_curview = viewindex; current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } } @@ -1047,6 +1091,229 @@ void render_target::set_max_texture_size(int maxwidth, int maxheight) //------------------------------------------------- +// pointer_updated - pointer activity within +// target +//------------------------------------------------- + +void render_target::pointer_updated( + osd::ui_event_handler::pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 buttons, + u32 pressed, + u32 released, + s16 clicks) +{ + auto const target_f(map_point_layout(x, y)); + current_view().pointer_updated(type, ptrid, device, target_f.first, target_f.second, buttons, pressed, released, clicks); + + // 64 pointers ought to be enough for anyone + if (64 <= ptrid) + return; + + // just store the updated pointer state + if (m_pointers.size() <= ptrid) + m_pointers.resize(ptrid + 1); + m_pointers[ptrid].type = type; + m_pointers[ptrid].newpos = target_f; + m_pointers[ptrid].newbuttons = buttons; +} + + +//------------------------------------------------- +// pointer_left - pointer left target normally +//------------------------------------------------- + +void render_target::pointer_left( + osd::ui_event_handler::pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 released, + s16 clicks) +{ + auto const target_f(map_point_layout(x, y)); + current_view().pointer_left(type, ptrid, device, target_f.first, target_f.second, released, clicks); + + // store the updated state if relevant + if (m_pointers.size() > ptrid) + { + m_pointers[ptrid].newpos = std::make_pair(std::numeric_limits<float>::min(), std::numeric_limits<float>::min()); + m_pointers[ptrid].newbuttons = 0; + } +} + + +//------------------------------------------------- +// pointer_aborted - pointer left target +// abnormally +//------------------------------------------------- + +void render_target::pointer_aborted( + osd::ui_event_handler::pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 released, + s16 clicks) +{ + // let layout scripts handle pointer input + auto const target_f(map_point_layout(x, y)); + current_view().pointer_aborted(type, ptrid, device, target_f.first, target_f.second, released, clicks); + + // store the updated state if relevant + if (m_pointers.size() > ptrid) + { + m_pointers[ptrid].newpos = std::make_pair(std::numeric_limits<float>::min(), std::numeric_limits<float>::min()); + m_pointers[ptrid].newbuttons = 0; + } +} + + +//------------------------------------------------- +// forget_pointers - stop processing pointer +// input +//------------------------------------------------- + +void render_target::forget_pointers() +{ + current_view().forget_pointers(); + m_pointers.clear(); + for (size_t i = 0; m_clickable_items.size() > i; ++i) + { + if (m_clickable_items[i].hit) + { + layout_view_item const &item(current_view().interactive_items()[i]); + auto const [port, mask] = item.input_tag_and_mask(); + ioport_field *const field(port ? port->field(mask) : nullptr); + if (field) + field->set_value(0); + } + m_clickable_items[i] = hit_test(); + } +} + + +//------------------------------------------------- +// update_pointer_fields - update inputs for new +// pointer state +//------------------------------------------------- + +void render_target::update_pointer_fields() +{ + auto const &x_edges(current_view().interactive_edges_x()); + auto const &y_edges(current_view().interactive_edges_y()); + + // update items bounds intersection checks for pointers + for (size_t ptr = 0; m_pointers.size() > ptr; ++ptr) + { + auto const [x, y] = m_pointers[ptr].newpos; + auto edges = m_pointers[ptr].edges; + + // check for moving across horizontal edges + if (x < m_pointers[ptr].oldpos.first) + { + while (edges.first && (x < x_edges[edges.first - 1].position())) + { + --edges.first; + auto const &edge(x_edges[edges.first]); + if (edge.trailing()) + m_clickable_items[edge.index()].inbounds.first |= u64(1) << ptr; + else + m_clickable_items[edge.index()].inbounds.first &= ~(u64(1) << ptr); + } + } + else if (x > m_pointers[ptr].oldpos.first) + { + while ((x_edges.size() > edges.first) && (x >= x_edges[edges.first].position())) + { + auto const &edge(x_edges[edges.first]); + if (edge.trailing()) + m_clickable_items[edge.index()].inbounds.first &= ~(u64(1) << ptr); + else + m_clickable_items[edge.index()].inbounds.first |= u64(1) << ptr; + ++edges.first; + } + } + + // check for moving across vertical edges + if (y < m_pointers[ptr].oldpos.second) + { + while (edges.second && (y < y_edges[edges.second - 1].position())) + { + --edges.second; + auto const &edge(y_edges[edges.second]); + if (edge.trailing()) + m_clickable_items[edge.index()].inbounds.second |= u64(1) << ptr; + else + m_clickable_items[edge.index()].inbounds.second &= ~(u64(1) << ptr); + } + } + else if (y > m_pointers[ptr].oldpos.second) + { + while ((y_edges.size() > edges.second) && (y >= y_edges[edges.second].position())) + { + auto const &edge(y_edges[edges.second]); + if (edge.trailing()) + m_clickable_items[edge.index()].inbounds.second &= ~(u64(1) << ptr); + else + m_clickable_items[edge.index()].inbounds.second |= u64(1) << ptr; + ++edges.second; + } + } + + // update the pointer's state + m_pointers[ptr].oldpos = m_pointers[ptr].newpos; + m_pointers[ptr].oldbuttons = m_pointers[ptr].newbuttons; + m_pointers[ptr].edges = edges; + } + + // update item hit states + u64 obscured(0U); + for (size_t i = 0; m_clickable_items.size() > i; ++i) + { + layout_view_item const &item(current_view().interactive_items()[i]); + u64 const inbounds(m_clickable_items[i].inbounds.first & m_clickable_items[i].inbounds.second); + u64 hit(m_clickable_items[i].hit); + for (unsigned ptr = 0; m_pointers.size() > ptr; ++ptr) + { + pointer_info const &pointer(m_pointers[ptr]); + bool const prefilter(BIT(~obscured & inbounds, ptr)); + if (!prefilter || !BIT(pointer.newbuttons, 0) || !item.bounds().includes(pointer.newpos.first, pointer.newpos.second)) + { + hit &= ~(u64(1) << ptr); + } + else + { + hit |= u64(1) << ptr; + if (!item.clickthrough()) + obscured |= u64(1) << ptr; + } + } + + // update field state + if (bool(hit) != bool(m_clickable_items[i].hit)) + { + auto const [port, mask] = item.input_tag_and_mask(); + ioport_field *const field(port ? port->field(mask) : nullptr); + if (field) + { + if (hit) + field->set_value(1); + else + field->clear_value(); + } + } + m_clickable_items[i].hit = hit; + } +} + + +//------------------------------------------------- // set_visibility_toggle - show or hide selected // parts of a view //------------------------------------------------- @@ -1058,7 +1325,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) m_views[m_curview].second |= u32(1) << index; else m_views[m_curview].second &= ~(u32(1) << index); - current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + update_layer_config(); current_view().preload(); } @@ -1070,28 +1337,29 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets) { - layout_view *view = nullptr; - // if it isn't "auto" or an empty string, try to match it as a view name prefix if (viewname && *viewname && strcmp(viewname, "auto")) { // scan for a matching view name size_t const viewlen = strlen(viewname); - for (unsigned i = 0; !view && (m_views.size() > i); ++i) + for (unsigned i = 0; m_views.size() > i; ++i) + { if (!core_strnicmp(m_views[i].first.name().c_str(), viewname, viewlen)) - view = &m_views[i].first; + return i; + } } // if we don't have a match, default to the nth view std::vector<std::reference_wrapper<screen_device> > screens; for (screen_device &screen : screen_device_enumerator(m_manager.machine().root_device())) screens.push_back(screen); - if (!view && !screens.empty()) + if (!screens.empty()) { // if we have enough targets to be one per screen, assign in order if (numtargets >= screens.size()) { // find the first view with this screen and this screen only + layout_view *view = nullptr; screen_device const &screen = screens[index() % screens.size()]; for (unsigned i = 0; !view && (m_views.size() > i); ++i) { @@ -1109,22 +1377,21 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i } } } + if (view) + return view_index(*view); } // otherwise, find the first view that has all the screens - if (!view) + for (unsigned i = 0; m_views.size() > i; ++i) { - for (unsigned i = 0; !view && (m_views.size() > i); ++i) - { - layout_view &curview = m_views[i].first; - if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) - view = &curview; - } + layout_view &curview = m_views[i].first; + if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) + return i; } } - // make sure it's a valid view - return view ? view_index(*view) : 0; + // default to the first view + return 0; } @@ -1197,63 +1464,103 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl // apply orientation if required if (target_orientation & ORIENTATION_SWAP_XY) - src_aspect = 1.0 / src_aspect; + src_aspect = 1.0f / src_aspect; - // get target aspect - float target_aspect = (float)target_width / (float)target_height * target_pixel_aspect; + // we need the ratio of target to source aspect + float aspect_ratio = m_keepaspect ? (float)target_width / (float)target_height * target_pixel_aspect / src_aspect : 1.0f; + + // first compute (a, b) scale factors to fit the screen + float a = (float)target_width / src_width; + float b = (float)target_height / src_height; // apply automatic axial stretching if required int scale_mode = m_scale_mode; - if (m_scale_mode == SCALE_FRACTIONAL_AUTO) - { - bool is_rotated = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY); - scale_mode = is_rotated ? SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; - } + if (scale_mode == SCALE_FRACTIONAL_AUTO) + scale_mode = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY) ? + SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; - // first compute scale factors to fit the screen - float xscale = (float)target_width / src_width; - float yscale = (float)target_height / src_height; + // determine the scaling method for each axis + bool a_is_fract = (scale_mode == SCALE_FRACTIONAL_X || scale_mode == SCALE_FRACTIONAL); + bool b_is_fract = (scale_mode == SCALE_FRACTIONAL_Y || scale_mode == SCALE_FRACTIONAL); - // apply aspect correction - if (m_keepaspect) - { - if (target_aspect > src_aspect) - xscale *= src_aspect / target_aspect; - else - yscale *= target_aspect / src_aspect; - } + // check if we have user defined scale factors, if so use them instead, but only on integer axes + int a_user = a_is_fract ? 0 : m_int_scale_x; + int b_user = b_is_fract ? 0 : m_int_scale_y; - bool x_fits = render_round_nearest(xscale) * src_width <= target_width; - bool y_fits = render_round_nearest(yscale) * src_height <= target_height; + // we allow overscan either explicitely or if integer scale factors are forced by user + bool int_overscan = m_int_overscan || (m_keepaspect && (a_user != 0 || b_user != 0)); + float a_max = std::max(a, (float)a_user); + float b_max = std::max(b, (float)b_user); - // compute integer scale factors - float integer_x = std::max(1.0f, float(m_int_overscan || x_fits ? render_round_nearest(xscale) : floor(xscale))); - float integer_y = std::max(1.0f, float(m_int_overscan || y_fits ? render_round_nearest(yscale) : floor(yscale))); - // check if we have user defined scale factors, if so use them instead - integer_x = m_int_scale_x > 0 ? m_int_scale_x : integer_x; - integer_y = m_int_scale_y > 0 ? m_int_scale_y : integer_y; + // get the usable bounding box considering the type of scaling for each axis + float usable_aspect = (a_is_fract ? a : std::max(1.0f, floorf(a))) * src_width / + ((b_is_fract ? b : std::max(1.0f, floorf(b))) * src_height) * target_pixel_aspect; - // now apply desired scale mode - if (scale_mode == SCALE_FRACTIONAL_X) + // depending on the relative shape between target and source, let's define 'a' and 'b' so that: + // * a is the leader axis (first to hit a boundary) + // * b is the follower axis + if (usable_aspect > src_aspect) { - if (m_keepaspect) xscale *= integer_y / yscale; - yscale = integer_y; + std::swap(a, b); + std::swap(a_user, b_user); + std::swap(a_is_fract, b_is_fract); + std::swap(a_max, b_max); + aspect_ratio = 1.0f / aspect_ratio; } - else if (scale_mode == SCALE_FRACTIONAL_Y) - { - if (m_keepaspect) yscale *= integer_x / xscale; - xscale = integer_x; - } - else + + // now find an (a, b) pair that best fits our boundaries and scale options + float a_best = 1.0f, b_best = 1.0f; + float diff = 1000; + + // fill (a0, a1) range + float u = a_user == 0 ? a : (float)a_user; + float a_range[] = {a_is_fract ? u : std::max(1.0f, floorf(u)), a_is_fract ? u : std::max(1.0f, roundf(u))}; + + for (float aa : a_range) { - xscale = integer_x; - yscale = integer_y; + // apply aspect correction to 'b' axis if needed, considering resulting 'a' borders + float ba = b * (m_keepaspect ? aspect_ratio * (aa / a) : 1.0f); + + // fill (b0, b1) range + float v = b_user == 0 ? ba : (float)b_user; + float b_range[] = {b_is_fract ? v : std::max(1.0f, floorf(v)), b_is_fract ? v : std::max(1.0f, roundf(v))}; + + for (float bb : b_range) + { + // we may need to propagate proportions back to 'a' axis + float ab = aa; + if (m_keepaspect && a_user == 0) + { + if (a_is_fract) ab *= (bb / ba); + else if (b_user != 0) ab = std::max(1.0f, roundf(ab * (bb / ba))); + } + + // if overscan isn't allowed, discard values that exceed the usable bounding box, except a minimum of 1.0f + if (!int_overscan && ((ab > a_max && bb > 1.0f) || (bb > b_max && ab > 1.0f))) + continue; + + // score the result + float new_diff = fabsf(aspect_ratio * (a / b) - (ab / bb)); + + if (new_diff <= diff) + { + diff = new_diff; + a_best = ab; + b_best = bb; + } + } } + a = a_best; + b = b_best; + + // restore orientation + if (usable_aspect > src_aspect) + std::swap(a, b); // set the final width/height - visible_width = render_round_nearest(src_width * xscale); - visible_height = render_round_nearest(src_height * yscale); + visible_width = render_round_nearest(src_width * a); + visible_height = render_round_nearest(src_height * b); break; } } @@ -1338,10 +1645,6 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight) render_primitive_list &render_target::get_primitives() { - // remember the base values if this is the first frame - if (!m_base_view) - m_base_view = ¤t_view(); - // switch to the next primitive list render_primitive_list &list = m_primlist[m_listindex]; m_listindex = (m_listindex + 1) % std::size(m_primlist); @@ -1415,8 +1718,8 @@ render_primitive_list &render_target::get_primitives() } } - // process the UI if we are the UI target - if (is_ui_target()) + // process UI elements if applicable + if (m_ui_container) { // compute the transform for the UI object_transform ui_xform; @@ -1429,7 +1732,7 @@ render_primitive_list &render_target::get_primitives() ui_xform.no_center = false; // add UI elements - add_container_primitives(list, root_xform, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA); + add_container_primitives(list, root_xform, ui_xform, *m_ui_container, BLENDMODE_ALPHA); } // optimize the list before handing it off @@ -1450,7 +1753,7 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta std::pair<float, float> target_f(map_point_internal(target_x, target_y)); // explicitly check for the UI container - if (&container == &m_manager.ui_container()) + if (&container == m_ui_container) { // this hit test went against the UI container if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f)) @@ -1497,74 +1800,6 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta //------------------------------------------------- -// map_point_input - attempts to map a point on -// the specified render_target to an input port -// field, if possible -//------------------------------------------------- - -bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y) -{ - std::pair<float, float> target_f(map_point_internal(target_x, target_y)); - if (m_orientation & ORIENTATION_FLIP_X) - target_f.first = 1.0f - target_f.first; - if (m_orientation & ORIENTATION_FLIP_Y) - target_f.second = 1.0f - target_f.second; - if (m_orientation & ORIENTATION_SWAP_XY) - std::swap(target_f.first, target_f.second); - - auto const &items(current_view().interactive_items()); - m_hit_test.resize(items.size() * 2); - std::fill(m_hit_test.begin(), m_hit_test.end(), false); - - for (auto const &edge : current_view().interactive_edges_x()) - { - if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing())) - break; - else - m_hit_test[edge.index()] = !edge.trailing(); - } - - for (auto const &edge : current_view().interactive_edges_y()) - { - if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing())) - break; - else - m_hit_test[items.size() + edge.index()] = !edge.trailing(); - } - - for (unsigned i = 0; items.size() > i; ++i) - { - if (m_hit_test[i] && m_hit_test[items.size() + i]) - { - layout_view_item &item(items[i]); - render_bounds const bounds(item.bounds()); - if (bounds.includes(target_f.first, target_f.second)) - { - if (item.has_input()) - { - // point successfully mapped - std::tie(input_port, input_mask) = item.input_tag_and_mask(); - input_x = (target_f.first - bounds.x0) / bounds.width(); - input_y = (target_f.second - bounds.y0) / bounds.height(); - return true; - } - else - { - break; - } - } - } - } - - // default to point not mapped - input_port = nullptr; - input_mask = 0; - input_x = input_y = -1.0f; - return false; -} - - -//------------------------------------------------- // invalidate_all - if any of our primitive lists // contain a reference to the given pointer, // clear them @@ -1593,7 +1828,7 @@ void render_target::resolve_tags() for (layout_file &file : m_filelist) file.resolve_tags(); - current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + update_layer_config(); current_view().preload(); } @@ -1605,7 +1840,10 @@ void render_target::resolve_tags() void render_target::update_layer_config() { + forget_pointers(); current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } @@ -1668,14 +1906,6 @@ void render_target::load_additional_layout_files(const char *basename, bool have else m_external_artwork = true; - // if a default view has been specified, use that as a fallback - bool have_default = false; - if (system.default_layout) - have_default |= load_layout_file(nullptr, *system.default_layout); - m_manager.machine().config().apply_default_layouts( - [this, &have_default] (device_t &dev, internal_layout const &layout) - { have_default |= load_layout_file(nullptr, layout, &dev); }); - // try to load another file based on the parent driver name int cloneof = driver_list::clone(system); while (0 <= cloneof) @@ -1693,6 +1923,14 @@ void render_target::load_additional_layout_files(const char *basename, bool have cloneof = driver_list::clone(parent); } + // if a default view has been specified, use that as a fallback + bool have_default = false; + if (system.default_layout) + have_default |= load_layout_file(nullptr, *system.default_layout); + m_manager.machine().config().apply_default_layouts( + [this, &have_default] (device_t &dev, internal_layout const &layout) + { have_default |= load_layout_file(nullptr, layout, &dev); }); + have_artwork |= m_external_artwork; // Use fallback artwork if defined and no artwork has been found yet @@ -2080,11 +2318,10 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout size_t decompressed = 0; do { - size_t actual; - std::error_condition const err = inflater->read( + auto const [err, actual] = read( + *inflater, &tempout[decompressed], - layout_data.decompressed_size - decompressed, - actual); + layout_data.decompressed_size - decompressed); decompressed += actual; if (err) { @@ -2177,7 +2414,7 @@ bool render_target::load_layout_file(device_t &device, util::xml::data_node cons { m_filelist.emplace_back(device, rootnode, searchpath, dirname); } - catch (emu_fatalerror &err) + catch (emu_fatalerror const &err) { osd_printf_warning("%s\n", err.what()); return false; @@ -2313,11 +2550,11 @@ void render_target::add_container_primitives(render_primitive_list &list, const // clip the primitive if (!m_transform_container && PRIMFLAG_GET_VECTOR(curitem.flags())) { - clipped = render_clip_line(&prim->bounds, &root_cliprect); + clipped = render_clip_line(prim->bounds, root_cliprect); } else { - clipped = render_clip_line(&prim->bounds, &cliprect); + clipped = render_clip_line(prim->bounds, cliprect); } break; @@ -2350,7 +2587,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2410,7 +2647,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2426,7 +2663,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, nullptr); + clipped = render_clip_quad(prim->bounds, cliprect, nullptr); } } break; @@ -2551,7 +2788,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob } // add to the list or free if we're clipped out - bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + bool const clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); list.append_or_return(*prim, clipped); } } @@ -2582,6 +2819,25 @@ std::pair<float, float> render_target::map_point_internal(s32 target_x, s32 targ //------------------------------------------------- +// map_point_layout - map point from screen +// coordinates to layout coordinates +//------------------------------------------------- + +std::pair<float, float> render_target::map_point_layout(s32 target_x, s32 target_y) +{ + using std::swap; + std::pair<float, float> result(map_point_internal(target_x, target_y)); + if (m_orientation & ORIENTATION_FLIP_X) + result.first = 1.0f - result.first; + if (m_orientation & ORIENTATION_FLIP_Y) + result.second = 1.0f - result.second; + if (m_orientation & ORIENTATION_SWAP_XY) + swap(result.first, result.second); + return result; +} + + +//------------------------------------------------- // view_name - return the name of the indexed // view, or nullptr if it doesn't exist //------------------------------------------------- @@ -2613,30 +2869,40 @@ int render_target::view_index(layout_view &targetview) const // config_load - process config information //------------------------------------------------- -void render_target::config_load(util::xml::data_node const &targetnode) +void render_target::config_load(util::xml::data_node const *targetnode) { + // remember the view selected via command line and INI options + if (!m_base_view) + m_base_view = ¤t_view(); + + // bail if no configuration + if (!targetnode) + return; + + // TODO: consider option priority - command line should take precedence over CFG + // not practical at the moment because view selection options are in the OSD layer + // find the view - const char *viewname = targetnode.get_attribute_string("view", nullptr); - if (viewname != nullptr) - for (int viewnum = 0; viewnum < 1000; viewnum++) + const char *viewname = targetnode->get_attribute_string("view", nullptr); + if (viewname) + { + for (unsigned viewnum = 0; m_views.size() > viewnum; viewnum++) { - const char *testname = view_name(viewnum); - if (testname == nullptr) - break; - if (!strcmp(viewname, testname)) + if (!strcmp(viewname, view_name(viewnum))) { set_view(viewnum); break; } } + } // modify the artwork config - int const zoom = targetnode.get_attribute_int("zoom", -1); + int const zoom = targetnode->get_attribute_int("zoom", -1); if (zoom == 0 || zoom == 1) set_zoom_to_screen(zoom); // apply orientation - int rotate = targetnode.get_attribute_int("rotate", -1); + int rotate = targetnode->get_attribute_int("rotate", -1); if (rotate != -1) { if (rotate == 90) @@ -2650,17 +2916,16 @@ void render_target::config_load(util::xml::data_node const &targetnode) set_orientation(orientation_add(rotate, orientation())); // apply the opposite orientation to the UI - if (is_ui_target()) + if (m_ui_container) { - render_container &ui_container = m_manager.ui_container(); - render_container::user_settings settings = ui_container.get_user_settings(); + render_container::user_settings settings = m_ui_container->get_user_settings(); settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation); - ui_container.set_user_settings(settings); + m_ui_container->set_user_settings(settings); } } // apply per-view settings - for (util::xml::data_node const *viewnode = targetnode.get_child("view"); viewnode; viewnode = viewnode->get_next_sibling("view")) + for (util::xml::data_node const *viewnode = targetnode->get_child("view"); viewnode; viewnode = viewnode->get_next_sibling("view")) { char const *const viewname = viewnode->get_attribute_string("name", nullptr); if (!viewname) @@ -2695,6 +2960,8 @@ void render_target::config_load(util::xml::data_node const &targetnode) { current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } } } @@ -3056,7 +3323,6 @@ render_manager::render_manager(running_machine &machine) , m_ui_target(nullptr) , m_live_textures(0) , m_texture_id(0) - , m_ui_container(std::make_unique<render_container>(*this)) { // register callbacks machine.configuration().config_register( @@ -3077,7 +3343,7 @@ render_manager::render_manager(running_machine &machine) render_manager::~render_manager() { // free all the containers since they may own textures - m_ui_container.reset(); + m_ui_containers.clear(); m_screen_container_list.clear(); // better not be any outstanding textures when we die @@ -3133,12 +3399,14 @@ float render_manager::max_update_rate() const render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags) { - return &m_targetlist.append(*new render_target(*this, layoutfile, flags)); + render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); + return &m_targetlist.append(*new render_target(*this, ui, layoutfile, flags)); } render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags) { - return &m_targetlist.append(*new render_target(*this, layout, flags)); + render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); + return &m_targetlist.append(*new render_target(*this, ui, layout, flags)); } @@ -3175,35 +3443,56 @@ render_target *render_manager::target_by_index(int index) const float render_manager::ui_aspect(render_container *rc) { - int orient; + // work out if this is a UI container + render_target *target = nullptr; + if (!rc) + { + target = &ui_target(); + rc = target->ui_container(); + assert(rc); + } + else + { + for (render_target &t : m_targetlist) + { + if (t.ui_container() == rc) + { + target = &t; + break; + } + } + } + float aspect; - if (rc == m_ui_container.get() || rc == nullptr) { - // ui container, aggregated multi-screen target + if (target) + { + // UI container, aggregated multi-screen target - orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation()); // based on the orientation of the target, compute height/width or width/height + int const orient = orientation_add(target->orientation(), rc->orientation()); if (!(orient & ORIENTATION_SWAP_XY)) - aspect = (float)m_ui_target->height() / (float)m_ui_target->width(); + aspect = float(target->height()) / float(target->width()); else - aspect = (float)m_ui_target->width() / (float)m_ui_target->height(); + aspect = float(target->width()) / float(target->height()); // if we have a valid pixel aspect, apply that and return - if (m_ui_target->pixel_aspect() != 0.0f) + if (target->pixel_aspect() != 0.0f) { - float pixel_aspect = m_ui_target->pixel_aspect(); + float pixel_aspect = target->pixel_aspect(); if (orient & ORIENTATION_SWAP_XY) pixel_aspect = 1.0f / pixel_aspect; return aspect /= pixel_aspect; } - - } else { + } + else + { // single screen container - orient = rc->orientation(); // based on the orientation of the target, compute height/width or width/height + int const orient = rc->orientation(); if (!(orient & ORIENTATION_SWAP_XY)) aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width(); else @@ -3211,12 +3500,7 @@ float render_manager::ui_aspect(render_container *rc) } // clamp for extreme proportions - if (aspect < 0.66f) - aspect = 0.66f; - if (aspect > 1.5f) - aspect = 1.5f; - - return aspect; + return std::clamp(aspect, 0.66f, 1.5f); } @@ -3297,8 +3581,20 @@ void render_manager::resolve_tags() void render_manager::config_load(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode) { // we only care about system-specific configuration with matching nodes - if ((cfg_type != config_type::SYSTEM) || !parentnode) + if (cfg_type == config_type::DEFAULT) + { + // let the targets stabilise themselves + for (render_target &target : m_targetlist) + { + if (!target.hidden()) + target.config_load(nullptr); + } return; + } + else if ((cfg_type != config_type::SYSTEM) || !parentnode) + { + return; + } // check the UI target util::xml::data_node const *const uinode = parentnode->get_child("interface"); @@ -3314,7 +3610,7 @@ void render_manager::config_load(config_type cfg_type, config_level cfg_level, u { render_target *const target = target_by_index(targetnode->get_attribute_int("index", -1)); if (target && !target->hidden()) - target->config_load(*targetnode); + target->config_load(targetnode); } // iterate over screen nodes diff --git a/src/emu/render.h b/src/emu/render.h index d4f99377d70..c4c0f504edd 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -47,18 +47,13 @@ #define MAME_EMU_RENDER_H #include "rendertypes.h" -#include "screen.h" -#include <array> +#include "interface/uievents.h" + #include <cmath> -#include <functional> -#include <map> +#include <list> #include <memory> #include <mutex> -#include <string> -#include <string_view> -#include <tuple> -#include <unordered_map> #include <utility> #include <vector> @@ -164,6 +159,7 @@ struct render_texinfo void * base; // base of the data u32 rowpixels; // pixels per row u32 width; // width of the image + u32 width_margin; // left margin of the scaled bounds, if applicable u32 height; // height of the image u32 seqid; // sequence ID u64 unique_id; // unique identifier to pass to osd @@ -346,7 +342,7 @@ private: void get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, u32 flags = 0); const rgb_t *get_adjusted_palette(render_container &container, u32 &out_length); - static constexpr int MAX_TEXTURE_SCALES = 20; + static constexpr int MAX_TEXTURE_SCALES = 100; // a scaled_texture contains a single scaled entry for a texture struct scaled_texture @@ -498,14 +494,15 @@ class render_target friend class render_manager; // construction/destruction - render_target(render_manager &manager, const internal_layout *layoutfile = nullptr, u32 flags = 0); - render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags = 0); + render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags); + render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags); ~render_target(); public: // getters render_target *next() const { return m_next; } render_manager &manager() const { return m_manager; } + render_container *ui_container() const { return m_ui_container; } u32 width() const { return m_width; } u32 height() const { return m_height; } float pixel_aspect() const { return m_pixel_aspect; } @@ -531,6 +528,13 @@ public: void set_keepaspect(bool keepaspect) { m_keepaspect = keepaspect; } void set_scale_mode(int scale_mode) { m_scale_mode = scale_mode; } + // pointer input handling + void pointer_updated(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 buttons, u32 pressed, u32 released, s16 clicks); + void pointer_left(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks); + void pointer_aborted(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks); + void forget_pointers(); + void update_pointer_fields(); + // layer config getters bool screen_overlay_enabled() const { return m_layerconfig.screen_overlay_enabled(); } bool zoom_to_screen() const { return m_layerconfig.zoom_to_screen(); } @@ -556,7 +560,6 @@ public: // hit testing bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y); - bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y); // reference tracking void invalidate_all(void *refptr); @@ -565,15 +568,24 @@ public: void resolve_tags(); private: + // constants + static inline constexpr int NUM_PRIMLISTS = 3; + static inline constexpr int MAX_CLEAR_EXTENTS = 1000; + using view_mask_pair = std::pair<layout_view &, u32>; using view_mask_vector = std::vector<view_mask_pair>; // private classes declared in render.cpp struct object_transform; + struct pointer_info; + struct hit_test; + + using pointer_info_vector = std::vector<pointer_info>; + using hit_test_vector = std::vector<hit_test>; // internal helpers enum constructor_impl_t { CONSTRUCTOR_IMPL }; - template <typename T> render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t); + template <typename T> render_target(render_manager &manager, render_container *ui, T&& layout, u32 flags, constructor_impl_t); void update_layer_config(); void load_layout_files(const internal_layout *layoutfile, bool singlefile); void load_layout_files(util::xml::data_node const &rootnode, bool singlefile); @@ -584,9 +596,10 @@ private: void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode); void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item); std::pair<float, float> map_point_internal(s32 target_x, s32 target_y); + std::pair<float, float> map_point_layout(s32 target_x, s32 target_y); // config callbacks - void config_load(util::xml::data_node const &targetnode); + void config_load(util::xml::data_node const *targetnode); bool config_save(util::xml::data_node &targetnode); // view lookups @@ -599,13 +612,10 @@ private: void add_clear_extents(render_primitive_list &list); void add_clear_and_optimize_primitive_list(render_primitive_list &list); - // constants - static constexpr int NUM_PRIMLISTS = 3; - static constexpr int MAX_CLEAR_EXTENTS = 1000; - // internal state render_target * m_next; // link to next target render_manager & m_manager; // reference to our owning manager + render_container *const m_ui_container; // container for drawing UI elements std::list<layout_file> m_filelist; // list of layout files view_mask_vector m_views; // views we consider unsigned m_curview; // current view index @@ -624,7 +634,8 @@ private: float m_max_refresh; // maximum refresh rate, 0 or if none int m_orientation; // orientation render_layer_config m_layerconfig; // layer configuration - std::vector<bool> m_hit_test; // used when mapping points to inputs + pointer_info_vector m_pointers; // state of pointers over this target + hit_test_vector m_clickable_items; // for tracking clicked elements layout_view * m_base_view; // the view at the time of first frame int m_base_orientation; // the orientation at the time of first frame render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame @@ -671,7 +682,7 @@ public: float ui_aspect(render_container *rc = nullptr); // UI containers - render_container &ui_container() const { assert(m_ui_container != nullptr); return *m_ui_container; } + render_container &ui_container() const { assert(ui_target().ui_container()); return *ui_target().ui_container(); } // textures render_texture *texture_alloc(texture_scaler_func scaler = nullptr, void *param = nullptr); @@ -692,20 +703,20 @@ private: void config_save(config_type cfg_type, util::xml::data_node *parentnode); // internal state - running_machine & m_machine; // reference back to the machine + running_machine & m_machine; // reference back to the machine // array of live targets - simple_list<render_target> m_targetlist; // list of targets - render_target * m_ui_target; // current UI target + simple_list<render_target> m_targetlist; // list of targets + render_target * m_ui_target; // current UI target // texture lists - u32 m_live_textures; // number of live textures - u64 m_texture_id; // rolling texture ID counter - fixed_allocator<render_texture> m_texture_allocator;// texture allocator + u32 m_live_textures; // number of live textures + u64 m_texture_id; // rolling texture ID counter + fixed_allocator<render_texture> m_texture_allocator; // texture allocator - // containers for the UI and for screens - std::unique_ptr<render_container> m_ui_container; // UI container - std::list<render_container> m_screen_container_list; // list of containers for the screen + // containers for UI elements and for screens + std::list<render_container> m_ui_containers; // containers for drawing UI elements + std::list<render_container> m_screen_container_list; // list of containers for the screen }; #endif // MAME_EMU_RENDER_H diff --git a/src/emu/rendersw.hxx b/src/emu/rendersw.hxx index aa7b2253795..5561928e7df 100644 --- a/src/emu/rendersw.hxx +++ b/src/emu/rendersw.hxx @@ -153,7 +153,10 @@ private: } else { - u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16); + s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1); + s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1); + + u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + v * texture.rowpixels + u; return palbase[texbase[0]]; } } @@ -185,7 +188,10 @@ private: } else { - u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16); + s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1); + s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1); + + u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + v * texture.rowpixels + u; return palbase[texbase[0]]; } } @@ -247,8 +253,11 @@ private: } else { - const u16 *texbase = reinterpret_cast<const u16 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 17) * 2; - return (texbase[(curu >> 16) & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16); + s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1); + s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1); + + const u16 *texbase = reinterpret_cast<const u16 *>(texture.base) + v * texture.rowpixels + (u >> 1) * 2; + return (texbase[u & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16); } } diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h index 43f2ebb85e7..b3eed6ad9bd 100644 --- a/src/emu/rendertypes.h +++ b/src/emu/rendertypes.h @@ -20,6 +20,16 @@ //************************************************************************** +// texture formats +enum texture_format +{ + TEXFORMAT_UNDEFINED = 0, // require a format to be specified + TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha + TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB + TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB + TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence +}; + // blending modes enum { diff --git a/src/emu/rendfont.cpp b/src/emu/rendfont.cpp index ae295e39e2d..259d7731fe5 100644 --- a/src/emu/rendfont.cpp +++ b/src/emu/rendfont.cpp @@ -10,9 +10,14 @@ #include "emu.h" #include "rendfont.h" + #include "emuopts.h" +#include "fileio.h" +#include "render.h" + #include "corestr.h" -#include "coreutil.h" +#include "multibyte.h" +#include "path.h" #include "osdepend.h" #include "uismall.fh" @@ -121,13 +126,14 @@ public: static constexpr unsigned MAJVERSION = 1; static constexpr unsigned MINVERSION = 0; - bool read(emu_file &f) + bool read(util::read_stream &f) { - return f.read(m_data, sizeof(m_data)) == sizeof(m_data); + auto const [err, actual] = util::read(f, m_data, sizeof(m_data)); + return !err && (actual == sizeof(m_data)); } - bool write(emu_file &f) + bool write(util::write_stream &f) { - return f.write(m_data, sizeof(m_data)) == sizeof(m_data); + return !util::write(f, m_data, sizeof(m_data)).first; } bool check_magic() const @@ -144,51 +150,27 @@ public: } u64 get_original_length() const { - return - (u64(m_data[OFFS_ORIGLENGTH + 0]) << (7 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 1]) << (6 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 2]) << (5 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 3]) << (4 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 4]) << (3 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 5]) << (2 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 6]) << (1 * 8)) | - (u64(m_data[OFFS_ORIGLENGTH + 7]) << (0 * 8)); + return get_u64be(m_data + OFFS_ORIGLENGTH); } u32 get_original_hash() const { - return - (u32(m_data[OFFS_ORIGHASH + 0]) << (3 * 8)) | - (u32(m_data[OFFS_ORIGHASH + 1]) << (2 * 8)) | - (u32(m_data[OFFS_ORIGHASH + 2]) << (1 * 8)) | - (u32(m_data[OFFS_ORIGHASH + 3]) << (0 * 8)); + return get_u32be(m_data + OFFS_ORIGHASH); } u32 get_glyph_count() const { - return - (u32(m_data[OFFS_GLYPHCOUNT + 0]) << (3 * 8)) | - (u32(m_data[OFFS_GLYPHCOUNT + 1]) << (2 * 8)) | - (u32(m_data[OFFS_GLYPHCOUNT + 2]) << (1 * 8)) | - (u32(m_data[OFFS_GLYPHCOUNT + 3]) << (0 * 8)); + return get_u32be(m_data + OFFS_GLYPHCOUNT); } u16 get_height() const { - return - (u16(m_data[OFFS_HEIGHT + 0]) << (1 * 8)) | - (u16(m_data[OFFS_HEIGHT + 1]) << (0 * 8)); + return get_u16be(m_data + OFFS_HEIGHT); } s16 get_y_offset() const { - return - (u16(m_data[OFFS_YOFFSET + 0]) << (1 * 8)) | - (u16(m_data[OFFS_YOFFSET + 1]) << (0 * 8)); + return get_u16be(m_data + OFFS_YOFFSET); } s32 get_default_character() const { - return - (u32(m_data[OFFS_DEFCHAR + 0]) << (3 * 8)) | - (u32(m_data[OFFS_DEFCHAR + 1]) << (2 * 8)) | - (u32(m_data[OFFS_DEFCHAR + 2]) << (1 * 8)) | - (u32(m_data[OFFS_DEFCHAR + 3]) << (0 * 8)); + return get_u32be(m_data + OFFS_DEFCHAR); } void set_magic() @@ -202,45 +184,27 @@ public: } void set_original_length(u64 value) { - m_data[OFFS_ORIGLENGTH + 0] = u8((value >> (7 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 1] = u8((value >> (6 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 2] = u8((value >> (5 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 3] = u8((value >> (4 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 4] = u8((value >> (3 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 5] = u8((value >> (2 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 6] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_ORIGLENGTH + 7] = u8((value >> (0 * 8)) & 0x00ff); + put_u64be(m_data + OFFS_ORIGLENGTH, value); } void set_original_hash(u32 value) { - m_data[OFFS_ORIGHASH + 0] = u8((value >> (3 * 8)) & 0x00ff); - m_data[OFFS_ORIGHASH + 1] = u8((value >> (2 * 8)) & 0x00ff); - m_data[OFFS_ORIGHASH + 2] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_ORIGHASH + 3] = u8((value >> (0 * 8)) & 0x00ff); + put_u32be(m_data + OFFS_ORIGHASH, value); } void set_glyph_count(u32 value) { - m_data[OFFS_GLYPHCOUNT + 0] = u8((value >> (3 * 8)) & 0x00ff); - m_data[OFFS_GLYPHCOUNT + 1] = u8((value >> (2 * 8)) & 0x00ff); - m_data[OFFS_GLYPHCOUNT + 2] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_GLYPHCOUNT + 3] = u8((value >> (0 * 8)) & 0x00ff); + put_u32be(m_data + OFFS_GLYPHCOUNT, value); } void set_height(u16 value) { - m_data[OFFS_HEIGHT + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_HEIGHT + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_data + OFFS_HEIGHT, value); } void set_y_offset(s16 value) { - m_data[OFFS_YOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_YOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_data + OFFS_YOFFSET, value); } void set_default_character(s32 value) { - m_data[OFFS_DEFCHAR + 0] = u8((value >> (3 * 8)) & 0x00ff); - m_data[OFFS_DEFCHAR + 1] = u8((value >> (2 * 8)) & 0x00ff); - m_data[OFFS_DEFCHAR + 2] = u8((value >> (1 * 8)) & 0x00ff); - m_data[OFFS_DEFCHAR + 3] = u8((value >> (0 * 8)) & 0x00ff); + put_u32be(m_data + OFFS_DEFCHAR, value); } private: @@ -280,74 +244,52 @@ public: u32 get_encoding() const { - return - (u32(m_ptr[OFFS_ENCODING + 0]) << (3 * 8)) | - (u32(m_ptr[OFFS_ENCODING + 1]) << (2 * 8)) | - (u32(m_ptr[OFFS_ENCODING + 2]) << (1 * 8)) | - (u32(m_ptr[OFFS_ENCODING + 3]) << (0 * 8)); + return get_u32be(m_ptr + OFFS_ENCODING); } u16 get_x_advance() const { - return - (u16(m_ptr[OFFS_XADVANCE + 0]) << (1 * 8)) | - (u16(m_ptr[OFFS_XADVANCE + 1]) << (0 * 8)); + return get_u16be(m_ptr + OFFS_XADVANCE); } s16 get_bb_x_offset() const { - return - (u16(m_ptr[OFFS_BBXOFFSET + 0]) << (1 * 8)) | - (u16(m_ptr[OFFS_BBXOFFSET + 1]) << (0 * 8)); + return get_u16be(m_ptr + OFFS_BBXOFFSET); } s16 get_bb_y_offset() const { - return - (u16(m_ptr[OFFS_BBYOFFSET + 0]) << (1 * 8)) | - (u16(m_ptr[OFFS_BBYOFFSET + 1]) << (0 * 8)); + return get_u16be(m_ptr + OFFS_BBYOFFSET); } u16 get_bb_width() const { - return - (u16(m_ptr[OFFS_BBWIDTH + 0]) << (1 * 8)) | - (u16(m_ptr[OFFS_BBWIDTH + 1]) << (0 * 8)); + return get_u16be(m_ptr + OFFS_BBWIDTH); } u16 get_bb_height() const { - return - (u16(m_ptr[OFFS_BBHEIGHT + 0]) << (1 * 8)) | - (u16(m_ptr[OFFS_BBHEIGHT + 1]) << (0 * 8)); + return get_u16be(m_ptr + OFFS_BBHEIGHT); } void set_encoding(u32 value) { - m_ptr[OFFS_ENCODING + 0] = u8((value >> (3 * 8)) & 0x00ff); - m_ptr[OFFS_ENCODING + 1] = u8((value >> (2 * 8)) & 0x00ff); - m_ptr[OFFS_ENCODING + 2] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_ENCODING + 3] = u8((value >> (0 * 8)) & 0x00ff); + put_u32be(m_ptr + OFFS_ENCODING, value); } void set_x_advance(u16 value) { - m_ptr[OFFS_XADVANCE + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_XADVANCE + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_ptr + OFFS_XADVANCE, value); } void set_bb_x_offset(s16 value) { - m_ptr[OFFS_BBXOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_BBXOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_ptr + OFFS_BBXOFFSET, value); } void set_bb_y_offset(s16 value) { - m_ptr[OFFS_BBYOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_BBYOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_ptr + OFFS_BBYOFFSET, value); } void set_bb_width(u16 value) { - m_ptr[OFFS_BBWIDTH + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_BBWIDTH + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_ptr + OFFS_BBWIDTH, value); } void set_bb_height(u16 value) { - m_ptr[OFFS_BBHEIGHT + 0] = u8((value >> (1 * 8)) & 0x00ff); - m_ptr[OFFS_BBHEIGHT + 1] = u8((value >> (0 * 8)) & 0x00ff); + put_u16be(m_ptr + OFFS_BBHEIGHT, value); } bdc_table_entry &operator=(bdc_table_entry const &that) = default; @@ -593,10 +535,9 @@ render_font::render_font(render_manager &manager, const char *filename) } // load the compiled in data instead - emu_file ramfile(OPEN_FLAG_READ); - std::error_condition const filerr(ramfile.open_ram(font_uismall, sizeof(font_uismall))); - if (!filerr) - load_cached(ramfile, 0, 0); + util::random_read::ptr ramfile = util::ram_read(font_uismall, sizeof(font_uismall)); + if (ramfile) + load_cached(*ramfile, 0, 0); render_font_command_glyph(); } @@ -668,7 +609,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl) if (accumbit == 7) accum = *ptr++; if (dest != nullptr) - *dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol; + *dest++ = BIT(accum, accumbit) ? fgcol : bgcol; accumbit = (accumbit - 1) & 7; } } @@ -764,7 +705,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl) if (accumbit == 7) accum = *ptr++; if (dest != nullptr) - *dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol; + *dest++ = BIT(accum, accumbit) ? fgcol : bgcol; accumbit = (accumbit - 1) & 7; } } @@ -817,7 +758,8 @@ void render_font::get_scaled_bitmap_and_bounds(bitmap_argb32 &dest, float height bounds.min_y = 0; // compute x1,y1 from there based on the bitmap size - bounds.set_width(float(gl.bmwidth) * scale * aspect); + float width = float(gl.bmwidth) * scale * aspect; + bounds.set_width(width < 0.5f ? 0 : std::max(int(width), 1)); bounds.set_height(float(m_height) * scale); // if the bitmap isn't big enough, bail @@ -861,14 +803,15 @@ float render_font::string_width(float height, float aspect, std::string_view str char32_t schar; // loop over characters - while (!string.empty()) + int scharcount; + while ((scharcount = uchar_from_utf8(&schar, string)) != 0) { - int scharcount = uchar_from_utf8(&schar, string); + if (0 > scharcount) + schar = 0xfffd; + string.remove_prefix((0 > scharcount) ? 1 : scharcount); totwidth += get_char(schar).width; - string.remove_prefix(scharcount); } - // scale the final result based on height return float(totwidth) * m_scale * height * aspect; } @@ -906,11 +849,11 @@ float render_font::utf8string_width(float height, float aspect, std::string_view // and create a new cached version //------------------------------------------------- -bool render_font::load_cached_bdf(const char *filename) +bool render_font::load_cached_bdf(std::string_view filename) { std::error_condition filerr; u32 chunk; - u64 bytes; + std::size_t bytes; // first try to open the BDF itself emu_file file(m_manager.machine().options().font_path(), OPEN_FLAG_READ); @@ -940,12 +883,10 @@ bool render_font::load_cached_bdf(const char *filename) m_rawdata.clear(); return false; } - u32 const hash(core_crc32(0, reinterpret_cast<u8 const *>(&m_rawdata[0]), bytes)); + u32 const hash(util::crc32_creator::simple(&m_rawdata[0], bytes)); // create the cached filename, changing the 'F' to a 'C' on the extension - std::string cachedname(filename); - if ((4U < cachedname.length()) && !core_stricmp(&cachedname[cachedname.length() - 4], ".bdf")) - cachedname.erase(cachedname.length() - 4); + std::string cachedname(filename, 0, filename.length() - ((4U < filename.length()) && core_filename_ends_with(filename, ".bdf") ? 4 : 0)); cachedname.append(".bdc"); // attempt to open the cached version of the font @@ -978,11 +919,25 @@ bool render_font::load_cached_bdf(const char *filename) m_rawdata[m_rawsize] = '\0'; // load the BDF - bool const result = load_bdf(); + bool result = load_bdf(); // if we loaded okay, create a cached one if (result) - save_cached(cachedname.c_str(), m_rawsize, hash); + { + osd_printf_info("Generating cached BDF font...\n"); + + // attempt to open the file + emu_file cachefile(m_manager.machine().options().font_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + filerr = cachefile.open(cachedname); + if (filerr) + result = false; + else + { + result = save_cached(cachefile, m_rawsize, hash); + if (!result) + cachefile.remove_on_close(); + } + } else m_rawdata.clear(); @@ -1324,7 +1279,7 @@ bool render_font::load_bdf() // some progress for big fonts if (0 == (++charcount % 256)) - osd_printf_warning("Loading BDF font... (%d characters loaded)\n", charcount); + osd_printf_info("Loading BDF font... (%d characters loaded)\n", charcount); } } @@ -1344,12 +1299,17 @@ bool render_font::load_bdf() // load_cached - load a font in cached format //------------------------------------------------- -bool render_font::load_cached(emu_file &file, u64 length, u32 hash) +bool render_font::load_cached(util::random_read &file, u64 length, u32 hash) { // get the file size, read the header, and check that it looks good - u64 const filesize(file.size()); + u64 filesize; bdc_header header; - if (!header.read(file)) + if (file.length(filesize)) + { + LOG("render_font::load_cached: error determining size of BDC file\n"); + return false; + } + else if (!header.read(file)) { osd_printf_warning("render_font::load_cached: error reading BDC header\n"); return false; @@ -1371,14 +1331,25 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash) m_yoffs = header.get_y_offset(); m_defchar = header.get_default_character(); u32 const numchars(header.get_glyph_count()); - if ((file.tell() + (u64(numchars) * bdc_table_entry::size())) > filesize) + u64 filepos; + if (file.tell(filepos)) + { + LOG("render_font::load_cached: failed to determine position in BDC file\n"); + return false; + } + else if ((filepos + (u64(numchars) * bdc_table_entry::size())) > filesize) { LOG("render_font::load_cached: BDC file is too small to hold glyph table\n"); return false; } // now read the rest of the data - u64 const remaining(filesize - file.tell()); + u64 const remaining(filesize - filepos); + if (remaining > std::numeric_limits<std::size_t>::max()) + { + osd_printf_error("render_font::load_cached: BDC file is too large to read into memory\n"); + return false; + } try { m_rawdata.resize(std::size_t(remaining)); @@ -1386,17 +1357,14 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash) catch (...) { osd_printf_error("render_font::load_cached: allocation error\n"); + return false; } - for (u64 bytes_read = 0; remaining > bytes_read; ) + auto const [err, bytes] = read(file, &m_rawdata[0], remaining); + if (err || (bytes != remaining)) { - u32 const chunk((std::min)(u64(std::numeric_limits<u32>::max()), remaining)); - if (file.read(&m_rawdata[bytes_read], chunk) != chunk) - { - osd_printf_error("render_font::load_cached: error reading BDC data\n"); - m_rawdata.clear(); - return false; - } - bytes_read += chunk; + osd_printf_error("render_font::load_cached: error reading BDC data\n"); + m_rawdata.clear(); + return false; } // extract the data from the data @@ -1450,16 +1418,8 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash) // save_cached - save a font in cached format //------------------------------------------------- -bool render_font::save_cached(const char *filename, u64 length, u32 hash) +bool render_font::save_cached(util::random_write &file, u64 length, u32 hash) { - osd_printf_warning("Generating cached BDF font...\n"); - - // attempt to open the file - emu_file file(m_manager.machine().options().font_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - std::error_condition const filerr = file.open(filename); - if (filerr) - return false; - // count glyphs unsigned numchars = 0; for (glyph const *const page : m_glyphs) @@ -1474,8 +1434,6 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) try { - u32 bytes_written; - { LOG("render_font::save_cached: writing header\n"); bdc_header hdr; @@ -1488,9 +1446,11 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) hdr.set_y_offset(m_yoffs); hdr.set_default_character(m_defchar); if (!hdr.write(file)) - throw emu_fatalerror("Error writing cached file"); + throw emu_fatalerror("Error writing cached font file"); } - u64 const table_offs(file.tell()); + u64 table_offs; + if (file.tell(table_offs)) + throw emu_fatalerror("Error writing cached font file"); // allocate an array to hold the character data std::vector<u8> chartable(std::size_t(numchars) * bdc_table_entry::size(), 0); @@ -1499,9 +1459,8 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) std::vector<u8> tempbuffer(65536); // write the empty table to the beginning of the file - bytes_written = file.write(&chartable[0], chartable.size()); - if (bytes_written != chartable.size()) - throw emu_fatalerror("Error writing cached file"); + if (write(file, &chartable[0], chartable.size()).first) + throw emu_fatalerror("Error writing cached font file"); // loop over all characters bdc_table_entry table_entry(chartable.empty() ? nullptr : &chartable[0]); @@ -1543,9 +1502,8 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) *dest++ = accum; // write the data - bytes_written = file.write(&tempbuffer[0], dest - &tempbuffer[0]); - if (bytes_written != dest - &tempbuffer[0]) - throw emu_fatalerror("Error writing cached file"); + if (write(file, &tempbuffer[0], dest - &tempbuffer[0]).first) + throw emu_fatalerror("Error writing cached font file"); // free the bitmap and texture m_manager.texture_free(gl.texture); @@ -1568,17 +1526,10 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) if (!chartable.empty()) { LOG("render_font::save_cached: writing character table\n"); - file.seek(table_offs, SEEK_SET); - u8 const *bytes(&chartable[0]); - for (u64 remaining = chartable.size(); remaining; ) - { - u32 const chunk((std::min<u64>)(std::numeric_limits<u32>::max(), remaining)); - bytes_written = file.write(bytes, chunk); - if (chunk != bytes_written) - throw emu_fatalerror("Error writing cached file"); - bytes += chunk; - remaining -= chunk; - } + if (file.seek(table_offs, SEEK_SET)) + return false; + if (write(file, &chartable[0], chartable.size()).first) + throw emu_fatalerror("Error writing cached font file"); } // no trouble? @@ -1586,7 +1537,6 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) } catch (...) { - file.remove_on_close(); return false; } } @@ -1595,13 +1545,13 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash) void render_font::render_font_command_glyph() { // FIXME: this is copy/pasta from the BDC loading, and it shouldn't be injected into every font - emu_file file(OPEN_FLAG_READ); - if (!file.open_ram(font_uicmd14, sizeof(font_uicmd14))) + util::random_read::ptr file = util::ram_read(font_uicmd14, sizeof(font_uicmd14)); + if (file) { // get the file size, read the header, and check that it looks good - u64 const filesize(file.size()); + u64 const filesize = sizeof(font_uicmd14); bdc_header header; - if (!header.read(file)) + if (!header.read(*file)) { osd_printf_warning("render_font::render_font_command_glyph: error reading BDC header\n"); return; @@ -1616,14 +1566,25 @@ void render_font::render_font_command_glyph() m_height_cmd = header.get_height(); m_yoffs_cmd = header.get_y_offset(); u32 const numchars(header.get_glyph_count()); - if ((file.tell() + (u64(numchars) * bdc_table_entry::size())) > filesize) + u64 filepos; + if (file->tell(filepos)) + { + LOG("render_font::render_font_command_glyph: failed to determine position in BDC file\n"); + return; + } + else if ((filepos + (u64(numchars) * bdc_table_entry::size())) > filesize) { LOG("render_font::render_font_command_glyph: BDC file is too small to hold glyph table\n"); return; } // now read the rest of the data - u64 const remaining(filesize - file.tell()); + u64 const remaining(filesize - filepos); + if (remaining > std::numeric_limits<std::size_t>::max()) + { + osd_printf_error("render_font::render_font_command_glyph: BDC file is too large to read into memory\n"); + return; + } try { m_rawdata_cmd.resize(std::size_t(remaining)); @@ -1631,17 +1592,14 @@ void render_font::render_font_command_glyph() catch (...) { osd_printf_error("render_font::render_font_command_glyph: allocation error\n"); + return; } - for (u64 bytes_read = 0; remaining > bytes_read; ) + auto const [err, bytes] = read(*file, &m_rawdata_cmd[0], remaining); + if (err || (bytes != remaining)) { - u32 const chunk((std::min)(u64(std::numeric_limits<u32>::max()), remaining)); - if (file.read(&m_rawdata_cmd[bytes_read], chunk) != chunk) - { - osd_printf_error("render_font::render_font_command_glyph: error reading BDC data\n"); - m_rawdata_cmd.clear(); - return; - } - bytes_read += chunk; + osd_printf_error("render_font::render_font_command_glyph: error reading BDC data\n"); + m_rawdata_cmd.clear(); + return; } // extract the data from the data diff --git a/src/emu/rendfont.h b/src/emu/rendfont.h index 15f6754657b..9ada358ed5d 100644 --- a/src/emu/rendfont.h +++ b/src/emu/rendfont.h @@ -11,8 +11,6 @@ #ifndef MAME_EMU_RENDFONT_H #define MAME_EMU_RENDFONT_H -#include "render.h" - //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -82,10 +80,10 @@ private: // helpers glyph &get_char(char32_t chnum); void char_expand(char32_t chnum, glyph &ch); - bool load_cached_bdf(const char *filename); + bool load_cached_bdf(std::string_view filename); bool load_bdf(); - bool load_cached(emu_file &file, u64 length, u32 hash); - bool save_cached(const char *filename, u64 length, u32 hash); + bool load_cached(util::random_read &file, u64 length, u32 hash); + bool save_cached(util::random_write &file, u64 length, u32 hash); void render_font_command_glyph(); diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index 28011b8372c..be5413f99ae 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -13,6 +13,8 @@ #include "rendlay.h" #include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "rendfont.h" #include "rendutil.h" #include "video/rgbutil.h" @@ -58,6 +60,9 @@ // screenless layouts #include "noscreens.lh" +// single screen layouts +#include "monitors.lh" + // dual screen layouts #include "dualhsxs.lh" #include "dualhovu.lh" @@ -220,12 +225,18 @@ private: { if (m_float_valid) { - m_text = std::to_string(m_float); + std::ostringstream stream; + stream.imbue(std::locale::classic()); + stream << m_float; + m_text = std::move(stream).str(); m_text_valid = true; } else if (m_int_valid) { - m_text = std::to_string(m_int); + std::ostringstream stream; + stream.imbue(std::locale::classic()); + stream << m_int; + m_text = std::move(stream).str(); m_text_valid = true; } } @@ -1249,7 +1260,6 @@ layout_element::make_component_map const layout_element::s_make_component{ { "simplecounter", &make_component<simplecounter_component> }, { "reel", &make_component<reel_component> }, { "led7seg", &make_component<led7seg_component> }, - { "led8seg_gts1", &make_component<led8seg_gts1_component> }, { "led14seg", &make_component<led14seg_component> }, { "led14segsc", &make_component<led14segsc_component> }, { "led16seg", &make_component<led16seg_component> }, @@ -1267,6 +1277,7 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele , m_defstate(env.get_attribute_int(elemnode, "defstate", -1)) , m_statemask(0) , m_foldhigh(false) + , m_invalidated(false) { // parse components in order bool first = true; @@ -1637,6 +1648,17 @@ render_texture *layout_element::state_texture(int state) //------------------------------------------------- +// set_draw_callback - set handler called after +// drawing components +//------------------------------------------------- + +void layout_element::set_draw_callback(draw_delegate &&handler) +{ + m_draw = std::move(handler); +} + + +//------------------------------------------------- // preload - perform expensive loading upfront // for all components //------------------------------------------------- @@ -1649,6 +1671,25 @@ void layout_element::preload() //------------------------------------------------- +// prepare - perform additional tasks before +// drawing a frame +//------------------------------------------------- + +void layout_element::prepare() +{ + if (m_invalidated) + { + m_invalidated = false; + for (texture &tex : m_elemtex) + { + machine().render().texture_free(tex.m_texture); + tex.m_texture = nullptr; + } + } +} + + +//------------------------------------------------- // element_scale - scale an element by rendering // all the components at the appropriate // resolution @@ -1664,6 +1705,10 @@ void layout_element::element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, c if ((elemtex.m_state & curcomp->statemask()) == curcomp->stateval()) curcomp->draw(elemtex.m_element->machine(), dest, elemtex.m_state); } + + // if there's a callback for additional drawing, invoke it + if (!elemtex.m_element->m_draw.isnull()) + elemtex.m_element->m_draw(elemtex.m_state, dest); } @@ -1745,10 +1790,10 @@ private: { u8 const *const src(reinterpret_cast<u8 const *>(dst)); rgb_t const d( - u8((float(src[3]) * c.a) + 0.5), - u8((float(src[0]) * c.r) + 0.5), - u8((float(src[1]) * c.g) + 0.5), - u8((float(src[2]) * c.b) + 0.5)); + u8((float(src[3]) * c.a) + 0.5F), + u8((float(src[0]) * c.r) + 0.5F), + u8((float(src[1]) * c.g) + 0.5F), + u8((float(src[2]) * c.b) + 0.5F)); *dst = d; havealpha = havealpha || (d.a() < 255U); } @@ -2024,17 +2069,12 @@ private: return; } svgbuf[len] = '\0'; - for (char *ptr = svgbuf.get(); len; ) + size_t actual; + std::tie(filerr, actual) = read(file, svgbuf.get(), len); + if (filerr || (actual < len)) { - size_t read; - filerr = file.read(ptr, size_t(len), read); - if (filerr || !read) - { - osd_printf_warning("Error reading component image '%s'\n", m_imagefile); - return; - } - ptr += read; - len -= read; + osd_printf_warning("Error reading component image '%s'\n", m_imagefile); + return; } parse_svg(svgbuf.get()); } @@ -2109,7 +2149,7 @@ protected: } else if (c.a) { - // compute premultiplied colors + // compute premultiplied color u32 const a(c.a * 255.0F); u32 const r(u32(c.r * (255.0F * 255.0F)) * a); u32 const g(u32(c.g * (255.0F * 255.0F)) * a); @@ -2145,9 +2185,9 @@ public: render_color const c(color(state)); u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255))); u32 const a(c.a * 255.0F); - u32 const r(c.r * c.a * (255.0F * 255.0F * 255.0F)); - u32 const g(c.g * c.a * (255.0F * 255.0F * 255.0F)); - u32 const b(c.b * c.a * (255.0F * 255.0F * 255.0F)); + u32 const r(c.r * (255.0F * 255.0F) * a); + u32 const g(c.g * (255.0F * 255.0F) * a); + u32 const b(c.b * (255.0F * 255.0F) * a); u32 const inva(255 - a); if (!a) return; @@ -2258,17 +2298,13 @@ public: if ((x >= minfill) && (x <= maxfill)) { if (255 <= a) - { dst = std::fill_n(dst, maxfill - x + 1, f); - x = maxfill; - } else - { while (x++ <= maxfill) alpha_blend(*dst++, a, r, g, b, inva); - --x; - } + --dst; + x = maxfill; } else { @@ -2370,17 +2406,13 @@ public: if ((x >= minfill) && (x <= maxfill)) { if (255 <= a) - { dst = std::fill_n(dst, maxfill - x + 1, f); - x = maxfill; - } else - { while (x++ <= maxfill) alpha_blend(*dst++, a, r, g, b, inva); - --x; - } + --dst; + x = maxfill; } else { @@ -2465,6 +2497,7 @@ public: led7seg_component(environment &env, util::xml::data_node const &compnode) : component(env, compnode) { + m_invert = env.get_attribute_int(compnode, "invert", 0); } protected: @@ -2473,8 +2506,8 @@ protected: virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override { - rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff); - rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff); + rgb_t const onpen = rgb_t(m_invert ? 0x20 : 0xff, 0xff, 0xff, 0xff); + rgb_t const offpen = rgb_t(m_invert ? 0xff : 0x20, 0xff, 0xff, 0xff); // sizes for computation int const bmwidth = 250; @@ -2516,74 +2549,8 @@ protected: // resample to the target size render_resample_argb_bitmap_hq(dest, tempbitmap, color(state)); } -}; - - -// 8-segment fluorescent (Gottlieb System 1) -class layout_element::led8seg_gts1_component : public component -{ -public: - // construction/destruction - led8seg_gts1_component(environment &env, util::xml::data_node const &compnode) - : component(env, compnode) - { - } - -protected: - // overrides - virtual int maxstate() const override { return 255; } - - virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override - { - rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff); - rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff); - rgb_t const backpen = rgb_t(0x00, 0x00, 0x00, 0x00); - - // sizes for computation - int const bmwidth = 250; - int const bmheight = 400; - int const segwidth = 40; - int const skewwidth = 40; - - // allocate a temporary bitmap for drawing - bitmap_argb32 tempbitmap(bmwidth + skewwidth, bmheight); - tempbitmap.fill(backpen); - - // top bar - draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 0)) ? onpen : offpen); - - // top-right bar - draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 1)) ? onpen : offpen); - - // bottom-right bar - draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 2)) ? onpen : offpen); - - // bottom bar - draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (state & (1 << 3)) ? onpen : offpen); - - // bottom-left bar - draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 4)) ? onpen : offpen); - - // top-left bar - draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 5)) ? onpen : offpen); - - // horizontal bars - draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, 2*bmwidth/3 - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen); - draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3 + bmwidth/2, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen); - - // vertical bars - draw_segment_vertical(tempbitmap, 0 + segwidth/3 - 8, bmheight/2 - segwidth/3 + 2, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen); - draw_segment_vertical(tempbitmap, 0 + segwidth/3, bmheight/2 - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen); - - draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3 - 2, bmheight - segwidth/3 + 8, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen); - draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen); - - // apply skew - apply_skew(tempbitmap, 40); - - // resample to the target size - render_resample_argb_bitmap_hq(dest, tempbitmap, color(state)); - } +private: + int m_invert = 0; }; @@ -3177,7 +3144,7 @@ protected: // shift the reels a bit based on this param, allows fine tuning int use_state = (state + m_stateoffset) % max_state_used; - // compute premultiplied colors + // compute premultiplied color render_color const c(color(state)); u32 const r = c.r * 255.0f; u32 const g = c.g * 255.0f; @@ -3259,10 +3226,10 @@ protected: width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit]); if (width < bounds.width()) break; - aspect *= 0.9f; + aspect *= 0.95f; } - s32 curx = bounds.left() + (bounds.width() - width) / 2; + float curx = bounds.left() + (bounds.width() - width) / 2.0f; // loop over characters std::string_view s = m_stopnames[fruit]; @@ -3289,7 +3256,7 @@ protected: u32 *const d = &dest.pix(effy); for (int x = 0; x < chbounds.width(); x++) { - int effx = curx + x + chbounds.left(); + int effx = int(curx) + x + chbounds.left(); if (effx >= bounds.left() && effx <= bounds.right()) { u32 spix = rgb_t(src[x]).a(); @@ -3329,7 +3296,7 @@ private: // shift the reels a bit based on this param, allows fine tuning int use_state = (state + m_stateoffset) % max_state_used; - // compute premultiplied colors + // compute premultiplied color render_color const c(color(state)); u32 const r = c.r * 255.0f; u32 const g = c.g * 255.0f; @@ -3407,10 +3374,10 @@ private: width = font->string_width(dest.height(), aspect, m_stopnames[fruit]); if (width < bounds.width()) break; - aspect *= 0.9f; + aspect *= 0.95f; } - s32 curx = bounds.left(); + float curx = bounds.left(); // allocate a temporary bitmap bitmap_argb32 tempbitmap(dest.width(), dest.height()); @@ -3440,7 +3407,7 @@ private: u32 *const d = &dest.pix(effy); for (int x = 0; x < chbounds.width(); x++) { - int effx = basex + curx + x; + int effx = basex + int(curx) + x; if (effx >= bounds.left() && effx <= bounds.right()) { u32 spix = rgb_t(src[x]).a(); @@ -3545,7 +3512,7 @@ layout_element::texture::texture(texture &&that) : texture() layout_element::texture::~texture() { - if (m_element != nullptr) + if (m_element) m_element->machine().render().texture_free(m_texture); } @@ -3747,12 +3714,6 @@ void layout_element::component::draw_text( int align, const render_color &color) { - // compute premultiplied colors - u32 const r(color.r * 255.0f); - u32 const g(color.g * 255.0f); - u32 const b(color.b * 255.0f); - u32 const a(color.a * 255.0f); - // get the width of the string float aspect = 1.0f; s32 width; @@ -3762,11 +3723,11 @@ void layout_element::component::draw_text( width = font.string_width(bounds.height(), aspect, str); if (width < bounds.width()) break; - aspect *= 0.9f; + aspect *= 0.95f; } // get alignment - s32 curx; + float curx; switch (align) { // left @@ -3781,7 +3742,7 @@ void layout_element::component::draw_text( // default to center default: - curx = bounds.left() + (bounds.width() - width) / 2; + curx = bounds.left() + (bounds.width() - width) / 2.0f; break; } @@ -3811,18 +3772,13 @@ void layout_element::component::draw_text( u32 *const d = &dest.pix(effy); for (int x = 0; x < chbounds.width(); x++) { - int effx = curx + x + chbounds.left(); + int effx = int(curx) + x + chbounds.left(); if (effx >= bounds.left() && effx <= bounds.right()) { u32 spix = rgb_t(src[x]).a(); if (spix != 0) { - rgb_t dpix = d[effx]; - u32 ta = (a * (spix + 1)) >> 8; - u32 tr = (r * ta + dpix.r() * (0x100 - ta)) >> 8; - u32 tg = (g * ta + dpix.g() * (0x100 - ta)) >> 8; - u32 tb = (b * ta + dpix.b() * (0x100 - ta)) >> 8; - d[effx] = rgb_t(tr, tg, tb); + alpha_blend(d[effx], color, spix / 255.0); } } } @@ -4041,9 +3997,20 @@ layout_view::layout_view( : m_effaspect(1.0f) , m_name(make_name(env, viewnode)) , m_unqualified_name(env.get_attribute_string(viewnode, "name")) + , m_elemmap(elemmap) , m_defvismask(0U) , m_has_art(false) + , m_show_ptr(false) + , m_ptr_time_out(true) // FIXME: add attribute for this + , m_exp_show_ptr(-1) { + // check for explicit pointer display setting + if (viewnode.get_attribute_string_ptr("showpointers")) + { + m_show_ptr = env.get_attribute_bool(viewnode, "showpointers", false); + m_exp_show_ptr = m_show_ptr ? 1 : 0; + } + // parse the layout m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0; view_environment local(env, m_name.c_str()); @@ -4187,6 +4154,21 @@ bool layout_view::has_visible_screen(screen_device const &screen) const //------------------------------------------------- +// prepare_items - perform additional tasks +// before rendering a frame +//------------------------------------------------- + +void layout_view::prepare_items() +{ + if (!m_prepare_items.isnull()) + m_prepare_items(); + + for (auto &[name, element] : m_elemmap) + element.prepare(); +} + + +//------------------------------------------------- // recompute - recompute the bounds and aspect // ratio of a view and all of its contained items //------------------------------------------------- @@ -4206,6 +4188,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen) // loop over items and filter by visibility mask bool first = true; bool scrfirst = true; + bool haveinput = false; for (item &curitem : m_items) { if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask()) @@ -4237,9 +4220,15 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen) // accumulate interactive elements if (!curitem.clickthrough() || curitem.has_input()) m_interactive_items.emplace_back(curitem); + if (curitem.has_input()) + haveinput = true; } } + // if show pointers isn't explicitly, update it based on visible items + if (0 > m_exp_show_ptr) + m_show_ptr = haveinput; + // if we have an explicit bounds, override it if (m_expbounds.x1 > m_expbounds.x0) m_bounds = m_expbounds; @@ -4279,6 +4268,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen) // sort edges of interactive items LOGMASKED(LOG_INTERACTIVE_ITEMS, "Recalculated view '%s' with %u interactive items\n", name(), m_interactive_items.size()); + //std::reverse(m_interactive_items.begin(), m_interactive_items.end()); TODO: flip hit test order to match visual order m_interactive_edges_x.reserve(m_interactive_items.size() * 2); m_interactive_edges_y.reserve(m_interactive_items.size() * 2); for (unsigned i = 0; m_interactive_items.size() > i; ++i) @@ -4310,6 +4300,29 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen) //------------------------------------------------- +// set_show_pointers - set whether pointers +// should be displayed +//------------------------------------------------- + +void layout_view::set_show_pointers(bool value) noexcept +{ + m_show_ptr = value; + m_exp_show_ptr = value ? 1 : 0; +} + + +//------------------------------------------------- +// set_pointers_time_out - set whether pointers +// should be hidden after inactivity +//------------------------------------------------- + +void layout_view::set_hide_inactive_pointers(bool value) noexcept +{ + m_ptr_time_out = value; +} + + +//------------------------------------------------- // set_prepare_items_callback - set handler called // before adding items to render target //------------------------------------------------- @@ -4343,6 +4356,50 @@ void layout_view::set_recomputed_callback(recomputed_delegate &&handler) //------------------------------------------------- +// set_pointer_updated_callback - set handler +// called for pointer input +//------------------------------------------------- + +void layout_view::set_pointer_updated_callback(pointer_updated_delegate &&handler) +{ + m_pointer_updated = std::move(handler); +} + + +//------------------------------------------------- +// set_pointer_left_callback - set handler for +// pointer leaving normally +//------------------------------------------------- + +void layout_view::set_pointer_left_callback(pointer_left_delegate &&handler) +{ + m_pointer_left = std::move(handler); +} + + +//------------------------------------------------- +// set_pointer_aborted_callback - set handler for +// pointer leaving abnormally +//------------------------------------------------- + +void layout_view::set_pointer_aborted_callback(pointer_left_delegate &&handler) +{ + m_pointer_aborted = std::move(handler); +} + + +//------------------------------------------------- +// set_forget_pointers_callback - set handler for +// abandoning pointer input +//------------------------------------------------- + +void layout_view::set_forget_pointers_callback(forget_pointers_delegate &&handler) +{ + m_forget_pointers = std::move(handler); +} + + +//------------------------------------------------- // preload - perform expensive loading upfront // for visible elements //------------------------------------------------- diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h index da9edfcf752..23431e7fd92 100644 --- a/src/emu/rendlay.h +++ b/src/emu/rendlay.h @@ -16,6 +16,18 @@ #include "rendertypes.h" #include "screen.h" +#include "interface/uievents.h" + +#include <array> +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <string_view> +#include <tuple> +#include <unordered_map> +#include <vector> + //************************************************************************** // TYPE DEFINITIONS @@ -61,6 +73,7 @@ class layout_element { public: using environment = emu::render::detail::layout_environment; + using draw_delegate = delegate<void (int, bitmap_argb32 &)>; // construction/destruction layout_element(environment &env, util::xml::data_node const &elemnode); @@ -71,8 +84,13 @@ public: int default_state() const { return m_defstate; } render_texture *state_texture(int state); + // set handlers + void set_draw_callback(draw_delegate &&handler); + // operations void preload(); + void invalidate() { m_invalidated = true; } + void prepare(); private: /// \brief A drawing component within a layout element @@ -113,16 +131,16 @@ private: virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state); // drawing helpers - void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, std::string_view str, int align, const render_color &color); - void draw_segment_horizontal_caps(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color); - void draw_segment_horizontal(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, rgb_t color); - void draw_segment_vertical_caps(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color); - void draw_segment_vertical(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, rgb_t color); - void draw_segment_diagonal_1(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); - void draw_segment_diagonal_2(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); - void draw_segment_decimal(bitmap_argb32 &dest, int midx, int midy, int width, rgb_t color); - void draw_segment_comma(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); - void apply_skew(bitmap_argb32 &dest, int skewwidth); + static void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, std::string_view str, int align, const render_color &color); + static void draw_segment_horizontal_caps(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color); + static void draw_segment_horizontal(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, rgb_t color); + static void draw_segment_vertical_caps(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color); + static void draw_segment_vertical(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, rgb_t color); + static void draw_segment_diagonal_1(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + static void draw_segment_diagonal_2(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + static void draw_segment_decimal(bitmap_argb32 &dest, int midx, int midy, int width, rgb_t color); + static void draw_segment_comma(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + static void apply_skew(bitmap_argb32 &dest, int skewwidth); private: using bounds_vector = emu::render::detail::bounds_vector; @@ -141,7 +159,6 @@ private: class disk_component; class text_component; class led7seg_component; - class led8seg_gts1_component; class led14seg_component; class led16seg_component; class led14segsc_component; @@ -173,7 +190,6 @@ private: // internal helpers static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param); template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode); - template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode); static make_component_map const s_make_component; // maps component XML names to creator functions @@ -184,6 +200,8 @@ private: int m_statemask; // mask to apply to state values bool m_foldhigh; // whether we need to fold state values above the mask range std::vector<texture> m_elemtex; // array of element textures used for managing the scaled bitmaps + draw_delegate m_draw; // draw delegate (called after components are drawn) + bool m_invalidated; // force redrawing on next frame if set }; @@ -281,7 +299,7 @@ public: // interactivity bool has_input() const { return bool(m_input_port); } - std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); }; + std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); } bool clickthrough() const { return m_clickthrough; } // fetch state based on configured source @@ -420,6 +438,9 @@ public: using prepare_items_delegate = delegate<void ()>; using preload_delegate = delegate<void ()>; using recomputed_delegate = delegate<void ()>; + using pointer_updated_delegate = delegate<void (osd::ui_event_handler::pointer, u16, u16, float, float, u32, u32, u32, s16)>; + using pointer_left_delegate = delegate<void (osd::ui_event_handler::pointer, u16, u16, float, float, u32, s16)>; + using forget_pointers_delegate = delegate<void ()>; using item = layout_view_item; using item_list = std::list<item>; @@ -506,20 +527,52 @@ public: const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; } u32 default_visibility_mask() const { return m_defvismask; } bool has_art() const { return m_has_art; } + bool show_pointers() const { return m_show_ptr; } + bool hide_inactive_pointers() const { return m_ptr_time_out; } + + // setters + void set_show_pointers(bool value) noexcept; + void set_hide_inactive_pointers(bool value) noexcept ATTR_COLD; // set handlers - void set_prepare_items_callback(prepare_items_delegate &&handler); - void set_preload_callback(preload_delegate &&handler); - void set_recomputed_callback(recomputed_delegate &&handler); + void set_prepare_items_callback(prepare_items_delegate &&handler) ATTR_COLD; + void set_preload_callback(preload_delegate &&handler) ATTR_COLD; + void set_recomputed_callback(recomputed_delegate &&handler) ATTR_COLD; + void set_pointer_updated_callback(pointer_updated_delegate &&handler) ATTR_COLD; + void set_pointer_left_callback(pointer_left_delegate &&handler) ATTR_COLD; + void set_pointer_aborted_callback(pointer_left_delegate &&handler) ATTR_COLD; + void set_forget_pointers_callback(forget_pointers_delegate &&handler) ATTR_COLD; // operations - void prepare_items() { if (!m_prepare_items.isnull()) m_prepare_items(); } + void prepare_items(); void recompute(u32 visibility_mask, bool zoom_to_screens); void preload(); // resolve tags, if any void resolve_tags(); + // pointer input + void pointer_updated(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 buttons, u32 pressed, u32 released, s16 clicks) + { + if (!m_pointer_updated.isnull()) + m_pointer_updated(type, ptrid, device, x, y, buttons, pressed, released, clicks); + } + void pointer_left(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 released, s16 clicks) + { + if (!m_pointer_left.isnull()) + m_pointer_left(type, ptrid, device, x, y, released, clicks); + } + void pointer_aborted(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 released, s16 clicks) + { + if (!m_pointer_aborted.isnull()) + m_pointer_aborted(type, ptrid, device, x, y, released, clicks); + } + void forget_pointers() + { + if (!m_forget_pointers.isnull()) + m_forget_pointers(); + } + private: struct layer_lists; @@ -560,15 +613,23 @@ private: prepare_items_delegate m_prepare_items; // prepare items for adding to render container preload_delegate m_preload; // additional actions when visible items change recomputed_delegate m_recomputed; // additional actions on resizing/visibility change + pointer_updated_delegate m_pointer_updated; // pointer state updated + pointer_left_delegate m_pointer_left; // pointer left normally + pointer_left_delegate m_pointer_aborted; // pointer left abnormally + forget_pointers_delegate m_forget_pointers; // stop processing pointer input // cold items std::string m_name; // display name for the view std::string m_unqualified_name; // the name exactly as specified in the layout file + element_map & m_elemmap; // reference to shared elements item_id_map m_items_by_id; // items with non-empty ID indexed by ID visibility_toggle_vector m_vistoggles; // collections of items that can be shown/hidden render_bounds m_expbounds; // explicit bounds of the view u32 m_defvismask; // default visibility mask bool m_has_art; // true if the layout contains non-screen elements + bool m_show_ptr; // whether pointers should be displayed + bool m_ptr_time_out; // whether pointers should be hidden after inactivity + s8 m_exp_show_ptr; // explicitly configured pointer visibility }; @@ -590,6 +651,7 @@ public: // getters device_t &device() const { return m_device; } + element_map &elements() { return m_elemmap; } element_map const &elements() const { return m_elemmap; } view_list &views() { return m_viewlist; } view_list const &views() const { return m_viewlist; } diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp index 2d0a823db28..5d09061ab70 100644 --- a/src/emu/rendutil.cpp +++ b/src/emu/rendutil.cpp @@ -19,29 +19,29 @@ #include <csetjmp> #include <cstdlib> +#include <tuple> namespace { struct jpeg_corefile_source : public jpeg_source_mgr { - static void source(j_decompress_ptr cinfo, util::random_read &file); + static void source(j_decompress_ptr cinfo, util::random_read &file) noexcept; private: static constexpr unsigned INPUT_BUF_SIZE = 4096; - static void do_init(j_decompress_ptr cinfo) + static void do_init(j_decompress_ptr cinfo) noexcept { jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src); src.start_of_file = true; } - static boolean do_fill(j_decompress_ptr cinfo) + static boolean do_fill(j_decompress_ptr cinfo) noexcept { jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src); - size_t nbytes; - src.infile->read(src.buffer, INPUT_BUF_SIZE, nbytes); // TODO: check error return + auto [err, nbytes] = read(*src.infile, src.buffer, INPUT_BUF_SIZE); // TODO: check error return if (0 >= nbytes) { @@ -60,7 +60,7 @@ private: return TRUE; } - static void do_skip(j_decompress_ptr cinfo, long num_bytes) + static void do_skip(j_decompress_ptr cinfo, long num_bytes) noexcept { jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src); @@ -69,14 +69,14 @@ private: while (long(src.bytes_in_buffer) < num_bytes) { num_bytes -= long(src.bytes_in_buffer); - (void)(*src.fill_input_buffer)(cinfo); + std::ignore = (*src.fill_input_buffer)(cinfo); } src.next_input_byte += size_t(num_bytes); src.bytes_in_buffer -= size_t(num_bytes); } } - static void do_term(j_decompress_ptr cinfo) + static void do_term(j_decompress_ptr cinfo) noexcept { } @@ -85,7 +85,7 @@ private: bool start_of_file; }; -void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &file) +void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &file) noexcept { jpeg_corefile_source *src; if (!cinfo->src) @@ -120,7 +120,7 @@ void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &fil struct jpeg_setjmp_error_mgr : public jpeg_error_mgr { - jpeg_setjmp_error_mgr() + jpeg_setjmp_error_mgr() noexcept { jpeg_std_error(this); error_exit = [] (j_common_ptr cinfo) { std::longjmp(static_cast<jpeg_setjmp_error_mgr *>(cinfo->err)->m_jump_buffer, 1); }; @@ -137,9 +137,9 @@ struct jpeg_setjmp_error_mgr : public jpeg_error_mgr ***************************************************************************/ /* utilities */ -static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy); -static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy); -static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png); +static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept; +static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept; +static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png) noexcept; @@ -152,15 +152,15 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info quality resampling of a texture -------------------------------------------------*/ -void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force) +void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force) noexcept { if (dest.width() == 0 || dest.height() == 0) return; - /* adjust the source base */ + // adjust the source base const u32 *sbase = &source.pix(0); - /* determine the steppings */ + // determine the steppings u32 swidth = source.width(); u32 sheight = source.height(); u32 dwidth = dest.width(); @@ -168,7 +168,7 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, u32 dx = (swidth << 12) / dwidth; u32 dy = (sheight << 12) / dheight; - /* if the source is higher res than the target, use full averaging */ + // if the source is higher res than the target, use full averaging if (dx > 0x1000 || dy > 0x1000 || force) resample_argb_bitmap_average(&dest.pix(0), dest.rowpixels(), dwidth, dheight, sbase, source.rowpixels(), swidth, sheight, color, dx, dy); else @@ -182,62 +182,58 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, all contributing pixels -------------------------------------------------*/ -static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) +static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept { - u64 sumscale = u64(dx) * u64(dy); - u32 r, g, b, a; - u32 x, y; - - /* precompute premultiplied R/G/B/A factors */ - r = color.r * color.a * 256.0f; - g = color.g * color.a * 256.0f; - b = color.b * color.a * 256.0f; - a = color.a * 256.0f; - - /* loop over the target vertically */ - for (y = 0; y < dheight; y++) + u64 const sumscale = u64(dx) * u64(dy); + + // precompute premultiplied R/G/B/A factors + u32 const r = color.r * color.a * 256.0f; + u32 const g = color.g * color.a * 256.0f; + u32 const b = color.b * color.a * 256.0f; + u32 const a = color.a * 256.0f; + + // loop over the target vertically + for (u32 y = 0; y < dheight; y++) { - u32 starty = y * dy; + u32 const starty = y * dy; - /* loop over the target horizontally */ - for (x = 0; x < dwidth; x++) + // loop over the target horizontally + for (u32 x = 0; x < dwidth; x++) { u64 sumr = 0, sumg = 0, sumb = 0, suma = 0; - u32 startx = x * dx; - u32 xchunk, ychunk; - u32 curx, cury; + u32 const startx = x * dx; u32 yremaining = dy; + u32 ychunk; - /* accumulate all source pixels that contribute to this pixel */ - for (cury = starty; yremaining; cury += ychunk) + // accumulate all source pixels that contribute to this pixel + for (u32 cury = starty; yremaining; cury += ychunk) { u32 xremaining = dx; + u32 xchunk; - /* determine the Y contribution, clamping to the amount remaining */ + // determine the Y contribution, clamping to the amount remaining ychunk = 0x1000 - (cury & 0xfff); if (ychunk > yremaining) ychunk = yremaining; yremaining -= ychunk; - /* loop over all source pixels in the X direction */ - for (curx = startx; xremaining; curx += xchunk) + // loop over all source pixels in the X direction + for (u32 curx = startx; xremaining; curx += xchunk) { - u32 factor; - - /* determine the X contribution, clamping to the amount remaining */ + // determine the X contribution, clamping to the amount remaining xchunk = 0x1000 - (curx & 0xfff); if (xchunk > xremaining) xchunk = xremaining; xremaining -= xchunk; - /* total contribution = x * y */ - factor = xchunk * ychunk; + // total contribution = x * y + u32 const factor = xchunk * ychunk; - /* fetch the source pixel */ - rgb_t pix = source[(cury >> 12) * srowpixels + (curx >> 12)]; + // fetch the source pixel + rgb_t const pix = source[(cury >> 12) * srowpixels + (curx >> 12)]; - /* accumulate the RGBA values */ + // accumulate the RGBA values sumr += factor * pix.r(); sumg += factor * pix.g(); sumb += factor * pix.b(); @@ -245,23 +241,23 @@ static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, } } - /* apply scaling */ + // apply scaling suma = (suma / sumscale) * a / 256; sumr = (sumr / sumscale) * r / 256; sumg = (sumg / sumscale) * g / 256; sumb = (sumb / sumscale) * b / 256; - /* if we're translucent, add in the destination pixel contribution */ + // if we're translucent, add in the destination pixel contribution if (a < 256) { - rgb_t dpix = dest[y * drowpixels + x]; + rgb_t const dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } - /* store the target pixel, dividing the RGBA values by the overall scale factor */ + // store the target pixel, dividing the RGBA values by the overall scale factor dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } @@ -273,44 +269,37 @@ static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, sampling via a bilinear filter -------------------------------------------------*/ -static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) +static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept { - u32 maxx = swidth << 12, maxy = sheight << 12; - u32 r, g, b, a; - u32 x, y; - - /* precompute premultiplied R/G/B/A factors */ - r = color.r * color.a * 256.0f; - g = color.g * color.a * 256.0f; - b = color.b * color.a * 256.0f; - a = color.a * 256.0f; - - /* loop over the target vertically */ - for (y = 0; y < dheight; y++) + u32 const maxx = swidth << 12, maxy = sheight << 12; + + // precompute premultiplied R/G/B/A factors + u32 const r = color.r * color.a * 256.0f; + u32 const g = color.g * color.a * 256.0f; + u32 const b = color.b * color.a * 256.0f; + u32 const a = color.a * 256.0f; + + // loop over the target vertically + for (u32 y = 0; y < dheight; y++) { - u32 starty = y * dy; + u32 const starty = y * dy; - /* loop over the target horizontally */ - for (x = 0; x < dwidth; x++) + // loop over the target horizontally + for (u32 x = 0; x < dwidth; x++) { - u32 startx = x * dx; - rgb_t pix0, pix1, pix2, pix3; - u32 sumr, sumg, sumb, suma; - u32 nextx, nexty; - u32 curx, cury; - u32 factor; + u32 const startx = x * dx; - /* adjust start to the center; note that this math will tend to produce */ - /* negative results on the first pixel, which is why we clamp below */ - curx = startx + dx / 2 - 0x800; - cury = starty + dy / 2 - 0x800; + // adjust start to the center; note that this math will tend to produce + // negative results on the first pixel, which is why we clamp below + u32 curx = startx + dx / 2 - 0x800; + u32 cury = starty + dy / 2 - 0x800; - /* compute the neighboring pixel */ - nextx = curx + 0x1000; - nexty = cury + 0x1000; + // compute the neighboring pixel + u32 const nextx = curx + 0x1000; + u32 const nexty = cury + 0x1000; - /* fetch the four relevant pixels */ - pix0 = pix1 = pix2 = pix3 = 0; + // fetch the four relevant pixels + rgb_t pix0 = 0, pix1 = 0, pix2 = 0, pix3 = 0; if (s32(cury) >= 0 && cury < maxy && s32(curx) >= 0 && curx < maxx) pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)]; if (s32(cury) >= 0 && cury < maxy && s32(nextx) >= 0 && nextx < maxx) @@ -320,173 +309,176 @@ static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, if (s32(nexty) >= 0 && nexty < maxy && s32(nextx) >= 0 && nextx < maxx) pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)]; - /* compute the x/y scaling factors */ + // compute the x/y scaling factors curx &= 0xfff; cury &= 0xfff; - /* contributions from pixel 0 (top,left) */ + u32 factor; + u32 sumr, sumg, sumb, suma; + + // contributions from pixel 0 (top,left) factor = (0x1000 - curx) * (0x1000 - cury); sumr = factor * pix0.r(); sumg = factor * pix0.g(); sumb = factor * pix0.b(); suma = factor * pix0.a(); - /* contributions from pixel 1 (top,right) */ + // contributions from pixel 1 (top,right) factor = curx * (0x1000 - cury); sumr += factor * pix1.r(); sumg += factor * pix1.g(); sumb += factor * pix1.b(); suma += factor * pix1.a(); - /* contributions from pixel 2 (bottom,left) */ + // contributions from pixel 2 (bottom,left) factor = (0x1000 - curx) * cury; sumr += factor * pix2.r(); sumg += factor * pix2.g(); sumb += factor * pix2.b(); suma += factor * pix2.a(); - /* contributions from pixel 3 (bottom,right) */ + // contributions from pixel 3 (bottom,right) factor = curx * cury; sumr += factor * pix3.r(); sumg += factor * pix3.g(); sumb += factor * pix3.b(); suma += factor * pix3.a(); - /* apply scaling */ + // apply scaling suma = (suma >> 24) * a / 256; sumr = (sumr >> 24) * r / 256; sumg = (sumg >> 24) * g / 256; sumb = (sumb >> 24) * b / 256; - /* if we're translucent, add in the destination pixel contribution */ + // if we're translucent, add in the destination pixel contribution if (a < 256) { - rgb_t dpix = dest[y * drowpixels + x]; + rgb_t const dpix = dest[y * drowpixels + x]; suma += dpix.a() * (256 - a); sumr += dpix.r() * (256 - a); sumg += dpix.g() * (256 - a); sumb += dpix.b() * (256 - a); } - /* store the target pixel, dividing the RGBA values by the overall scale factor */ + // store the target pixel, dividing the RGBA values by the overall scale factor dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb); } } } -/*------------------------------------------------- - render_clip_line - clip a line to a rectangle --------------------------------------------------*/ +//------------------------------------------------- +// render_clip_line - clip a line to a rectangle +//------------------------------------------------- -bool render_clip_line(render_bounds *bounds, const render_bounds *clip) +bool render_clip_line(render_bounds &bounds, const render_bounds &clip) { - /* loop until we get a final result */ - while (1) + // loop until we get a final result + while (true) { u8 code0 = 0, code1 = 0; u8 thiscode; float x, y; - /* compute Cohen Sutherland bits for first coordinate */ - if (bounds->y0 > clip->y1) + // compute Cohen Sutherland bits for first coordinate + if (bounds.y0 > clip.y1) code0 |= 1; - if (bounds->y0 < clip->y0) + if (bounds.y0 < clip.y0) code0 |= 2; - if (bounds->x0 > clip->x1) + if (bounds.x0 > clip.x1) code0 |= 4; - if (bounds->x0 < clip->x0) + if (bounds.x0 < clip.x0) code0 |= 8; - /* compute Cohen Sutherland bits for second coordinate */ - if (bounds->y1 > clip->y1) + // compute Cohen Sutherland bits for second coordinate + if (bounds.y1 > clip.y1) code1 |= 1; - if (bounds->y1 < clip->y0) + if (bounds.y1 < clip.y0) code1 |= 2; - if (bounds->x1 > clip->x1) + if (bounds.x1 > clip.x1) code1 |= 4; - if (bounds->x1 < clip->x0) + if (bounds.x1 < clip.x0) code1 |= 8; - /* trivial accept: just return false */ + // trivial accept: just return false if ((code0 | code1) == 0) return false; - /* trivial reject: just return true */ + // trivial reject: just return true if ((code0 & code1) != 0) return true; - /* fix one of the OOB cases */ + // fix one of the OOB cases thiscode = code0 ? code0 : code1; - /* off the bottom */ + // off the bottom if (thiscode & 1) { - x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y1 - bounds->y0) / (bounds->y1 - bounds->y0); - y = clip->y1; + x = bounds.x0 + (bounds.x1 - bounds.x0) * (clip.y1 - bounds.y0) / (bounds.y1 - bounds.y0); + y = clip.y1; } - /* off the top */ + // off the top else if (thiscode & 2) { - x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0); - y = clip->y0; + x = bounds.x0 + (bounds.x1 - bounds.x0) * (clip.y0 - bounds.y0) / (bounds.y1 - bounds.y0); + y = clip.y0; } - /* off the right */ + // off the right else if (thiscode & 4) { - y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x1 - bounds->x0) / (bounds->x1 - bounds->x0); - x = clip->x1; + y = bounds.y0 + (bounds.y1 - bounds.y0) * (clip.x1 - bounds.x0) / (bounds.x1 - bounds.x0); + x = clip.x1; } - /* off the left */ + // off the left else { - y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0); - x = clip->x0; + y = bounds.y0 + (bounds.y1 - bounds.y0) * (clip.x0 - bounds.x0) / (bounds.x1 - bounds.x0); + x = clip.x0; } - /* fix the appropriate coordinate */ + // fix the appropriate coordinate if (thiscode == code0) { - bounds->x0 = x; - bounds->y0 = y; + bounds.x0 = x; + bounds.y0 = y; } else { - bounds->x1 = x; - bounds->y1 = y; + bounds.x1 = x; + bounds.y1 = y; } } } -/*------------------------------------------------- - render_clip_quad - clip a quad to a rectangle --------------------------------------------------*/ +//------------------------------------------------- +// render_clip_quad - clip a quad to a rectangle +//------------------------------------------------- -bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords) +bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords) { - /* ensure our assumptions about the bounds are correct */ - assert(bounds->x0 <= bounds->x1); - assert(bounds->y0 <= bounds->y1); + // ensure our assumptions about the bounds are correct + assert(bounds.x0 <= bounds.x1); + assert(bounds.y0 <= bounds.y1); - /* trivial reject */ - if (bounds->y1 < clip->y0) + // trivial reject + if (bounds.y1 < clip.y0) return true; - if (bounds->y0 > clip->y1) + if (bounds.y0 > clip.y1) return true; - if (bounds->x1 < clip->x0) + if (bounds.x1 < clip.x0) return true; - if (bounds->x0 > clip->x1) + if (bounds.x0 > clip.x1) return true; - /* clip top (x0,y0)-(x1,y1) */ - if (bounds->y0 < clip->y0) + // clip top (x0,y0)-(x1,y1) + if (bounds.y0 < clip.y0) { - float frac = (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0); - bounds->y0 = clip->y0; + float frac = (clip.y0 - bounds.y0) / (bounds.y1 - bounds.y0); + bounds.y0 = clip.y0; if (texcoords != nullptr) { texcoords->tl.u += (texcoords->bl.u - texcoords->tl.u) * frac; @@ -496,11 +488,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q } } - /* clip bottom (x3,y3)-(x2,y2) */ - if (bounds->y1 > clip->y1) + // clip bottom (x3,y3)-(x2,y2) + if (bounds.y1 > clip.y1) { - float frac = (bounds->y1 - clip->y1) / (bounds->y1 - bounds->y0); - bounds->y1 = clip->y1; + float frac = (bounds.y1 - clip.y1) / (bounds.y1 - bounds.y0); + bounds.y1 = clip.y1; if (texcoords != nullptr) { texcoords->bl.u -= (texcoords->bl.u - texcoords->tl.u) * frac; @@ -510,11 +502,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q } } - /* clip left (x0,y0)-(x3,y3) */ - if (bounds->x0 < clip->x0) + // clip left (x0,y0)-(x3,y3) + if (bounds.x0 < clip.x0) { - float frac = (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0); - bounds->x0 = clip->x0; + float frac = (clip.x0 - bounds.x0) / (bounds.x1 - bounds.x0); + bounds.x0 = clip.x0; if (texcoords != nullptr) { texcoords->tl.u += (texcoords->tr.u - texcoords->tl.u) * frac; @@ -524,11 +516,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q } } - /* clip right (x1,y1)-(x2,y2) */ - if (bounds->x1 > clip->x1) + // clip right (x1,y1)-(x2,y2) + if (bounds.x1 > clip.x1) { - float frac = (bounds->x1 - clip->x1) / (bounds->x1 - bounds->x0); - bounds->x1 = clip->x1; + float frac = (bounds.x1 - clip.x1) / (bounds.x1 - bounds.x0); + bounds.x1 = clip.x1; if (texcoords != nullptr) { texcoords->tr.u -= (texcoords->tr.u - texcoords->tl.u) * frac; @@ -541,14 +533,14 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q } -/*------------------------------------------------- - render_line_to_quad - convert a line and a - width to four points --------------------------------------------------*/ +//------------------------------------------------- +// render_line_to_quad - convert a line and a +// width to four points +//----------------------------------------------- -void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1) +std::pair<render_bounds, render_bounds> render_line_to_quad(const render_bounds &bounds, float width, float length_extension) { - render_bounds modbounds = *bounds; + render_bounds modbounds = bounds; /* High-level logic -- due to math optimizations, this info is lost below. @@ -595,18 +587,18 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_ D.y = p1.y - 0.5 * w * u.x */ - /* we only care about the half-width */ + // we only care about the half-width float half_width = width * 0.5f; - /* compute a vector from point 0 to point 1 */ + // compute a vector from point 0 to point 1 float unitx = modbounds.x1 - modbounds.x0; float unity = modbounds.y1 - modbounds.y0; - /* points just use a +1/+1 unit vector; this gives a nice diamond pattern */ + // points just use a +1/+1 unit vector; this gives a nice diamond pattern if (unitx == 0 && unity == 0) { - /* length of a unit vector (1,1) */ - float unit_length = 0.70710678f; + // length of a unit vector (1,1) + constexpr float unit_length = 0.70710678f; unitx = unity = unit_length * half_width; modbounds.x0 -= unitx; @@ -615,12 +607,12 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_ modbounds.y1 += unity; } - /* lines need to be divided by their length */ + // lines need to be divided by their length else { float length = sqrtf(unitx * unitx + unity * unity); - /* extend line length */ + // extend line length if (length_extension > 0.0f) { float half_length_extension = length_extension *0.5f; @@ -634,27 +626,16 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_ modbounds.y1 += directiony * half_length_extension; } - /* prescale unitx and unity by the half-width */ + // prescale unitx and unity by the half-width float invlength = half_width / length; unitx *= invlength; unity *= invlength; } - /* rotate the unit vector by 90 degrees and add to point 0 */ - bounds0->x0 = modbounds.x0 - unity; - bounds0->y0 = modbounds.y0 + unitx; - - /* rotate the unit vector by -90 degrees and add to point 0 */ - bounds0->x1 = modbounds.x0 + unity; - bounds0->y1 = modbounds.y0 - unitx; - - /* rotate the unit vector by 90 degrees and add to point 1 */ - bounds1->x0 = modbounds.x1 - unity; - bounds1->y0 = modbounds.y1 + unitx; - - /* rotate the unit vector by -90 degrees and add to point 1 */ - bounds1->x1 = modbounds.x1 + unity; - bounds1->y1 = modbounds.y1 - unitx; + // rotate the unit vector by 90 and -90 degrees and add to points 0 and 1 + return std::make_pair( + render_bounds{ modbounds.x0 - unity, modbounds.y0 + unitx, modbounds.x0 + unity, modbounds.y0 - unitx }, + render_bounds{ modbounds.x1 - unity, modbounds.y1 + unitx, modbounds.x1 + unity, modbounds.y1 - unitx }); } @@ -663,7 +644,7 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_ into a bitmap -------------------------------------------------*/ -void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) +void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept { // deallocate previous bitmap bitmap.reset(); @@ -683,7 +664,7 @@ void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) bitmap -------------------------------------------------*/ -void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) +void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept { // deallocate previous bitmap bitmap.reset(); @@ -721,30 +702,39 @@ void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) // allocates a buffer to receive the information and copy them into the bitmap row_stride = cinfo.output_width * cinfo.output_components; buffer = reinterpret_cast<JSAMPARRAY>(std::malloc(sizeof(JSAMPROW))); - buffer[0] = reinterpret_cast<JSAMPROW>(std::malloc(sizeof(JSAMPLE) * row_stride)); + if (buffer) + buffer[0] = reinterpret_cast<JSAMPROW>(std::malloc(sizeof(JSAMPLE) * row_stride)); - while (cinfo.output_scanline < cinfo.output_height) + if (bitmap.valid() && buffer && buffer[0]) { - j = cinfo.output_scanline; - jpeg_read_scanlines(&cinfo, buffer, 1); - - if (s == 1) + while (cinfo.output_scanline < cinfo.output_height) { - for (i = 0; i < w; ++i) - bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i], buffer[0][i], buffer[0][i]); + j = cinfo.output_scanline; + jpeg_read_scanlines(&cinfo, buffer, 1); + if (s == 1) + { + for (i = 0; i < w; ++i) + bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i], buffer[0][i], buffer[0][i]); + + } + else if (s == 3) + { + for (i = 0; i < w; ++i) + bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]); + } + else + { + osd_printf_error("Cannot read JPEG data from file.\n"); + bitmap.reset(); + break; + } } - else if (s == 3) - { - for (i = 0; i < w; ++i) - bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]); - } - else - { - osd_printf_error("Cannot read JPEG data from file.\n"); - bitmap.reset(); - break; - } + } + else + { + osd_printf_error("Error allocating memory for JPEG image.\n"); + bitmap.reset(); } // finish decompression and free the memory @@ -765,7 +755,7 @@ cleanup: bitmap -------------------------------------------------*/ -bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing) +bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing) noexcept { // deallocate if we're not overlaying alpha if (!load_as_alpha_to_existing) @@ -820,7 +810,7 @@ bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_a to the alpha channel of a bitmap -------------------------------------------------*/ -static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png) +static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png) noexcept { // FIXME: this function is basically copy/pasted from the PNG code in util, and should be unified with it u8 accumalpha = 0xff; @@ -931,7 +921,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info render_detect_image - detect image format -------------------------------------------------*/ -ru_imgformat render_detect_image(util::random_read &file) +ru_imgformat render_detect_image(util::random_read &file) noexcept { // PNG: check for valid header { diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h index 4d2b89567e3..71e5bdc95c3 100644 --- a/src/emu/rendutil.h +++ b/src/emu/rendutil.h @@ -15,8 +15,11 @@ #include "rendertypes.h" +#include "utilfwd.h" + #include <algorithm> #include <cmath> +#include <utility> /* ----- image formats ----- */ @@ -39,14 +42,14 @@ enum ru_imgformat /* ----- render utilities ----- */ -void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false); -bool render_clip_line(render_bounds *bounds, const render_bounds *clip); -bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords); -void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1); -void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file); -void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file); -bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false); -ru_imgformat render_detect_image(util::random_read &file); +void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false) noexcept; +bool render_clip_line(render_bounds &bounds, const render_bounds &clip); +bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords); +std::pair<render_bounds, render_bounds> render_line_to_quad(const render_bounds &bounds, float width, float length_extension); +void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept; +void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept; +bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false) noexcept; +ru_imgformat render_detect_image(util::random_read &file) noexcept; diff --git a/src/emu/romentry.h b/src/emu/romentry.h index ff73e432c65..2a315c2a03e 100644 --- a/src/emu/romentry.h +++ b/src/emu/romentry.h @@ -29,18 +29,17 @@ CONSTANTS #define ROMENTRY_TYPEMASK 0x0000000f /* type of entry */ enum { - ROMENTRYTYPE_ROM = 0, /* this entry is an actual ROM definition */ - ROMENTRYTYPE_REGION, /* this entry marks the start of a region */ - ROMENTRYTYPE_END, /* this entry marks the end of a region */ - ROMENTRYTYPE_RELOAD, /* this entry reloads the previous ROM */ - ROMENTRYTYPE_CONTINUE, /* this entry continues loading the previous ROM */ - ROMENTRYTYPE_FILL, /* this entry fills an area with a constant value */ - ROMENTRYTYPE_COPY, /* this entry copies data from another region/offset */ - ROMENTRYTYPE_CARTRIDGE, /* this entry specifies a cartridge (MESS) */ - ROMENTRYTYPE_IGNORE, /* this entry continues loading the previous ROM but throws the data away */ - ROMENTRYTYPE_SYSTEM_BIOS, /* this entry specifies a bios */ - ROMENTRYTYPE_DEFAULT_BIOS, /* this entry specifies a default bios */ - ROMENTRYTYPE_PARAMETER, /* this entry specifies a per-game parameter */ + ROMENTRYTYPE_ROM = 0, // starts loading a ROM file + ROMENTRYTYPE_REGION, // starts a new ROM region + ROMENTRYTYPE_END, // sentinel marking the end of a ROM definition + ROMENTRYTYPE_RELOAD, // starts loading the current ROM file from the beginning again + ROMENTRYTYPE_CONTINUE, // continues loading the current ROM file at a different offset + ROMENTRYTYPE_FILL, // fills an area with a constant value + ROMENTRYTYPE_COPY, // copies data from another region/offset + ROMENTRYTYPE_IGNORE, // ignores a portion of the current ROM file + ROMENTRYTYPE_SYSTEM_BIOS, // specifies a BIOS option + ROMENTRYTYPE_DEFAULT_BIOS, // specifies the default BIOS option + ROMENTRYTYPE_PARAMETER, // specifies a per-game parameter ROMENTRYTYPE_COUNT }; diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp index bdff58a4a41..a429153be3f 100644 --- a/src/emu/romload.cpp +++ b/src/emu/romload.cpp @@ -11,13 +11,19 @@ #include "emu.h" #include "romload.h" -#include "corestr.h" -#include "emuopts.h" #include "drivenum.h" +#include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "softlist_dev.h" + #include "ui/uimain.h" +#include "corestr.h" +#include "path.h" + #include <algorithm> +#include <cstdarg> #include <set> @@ -37,6 +43,25 @@ namespace { +/*------------------------------------------------- + debugload - log data to a file +-------------------------------------------------*/ + +void ATTR_PRINTF(1,2) debugload(const char *string, ...) +{ + static int opened = 0; + FILE *const f(fopen("romload.log", opened++ ? "a" : "w")); + if (f) + { + va_list arg; + va_start(arg, string); + vfprintf(f, string, arg); + va_end(arg); + fclose(f); + } +} + + auto next_parent_system(game_driver const &system) { return @@ -48,13 +73,41 @@ auto next_parent_system(game_driver const &system) if (0 > parent) { sys = nullptr; + roms.clear(); + roms.shrink_to_fit(); return nullptr; } else { sys = &driver_list::driver(parent); roms = rom_build_entries(sys->rom); - return &roms[0]; + return &roms.front(); + } + }; +} + + +auto next_parent_device(device_t const &device, emu_options &options) +{ + return + [&options, type = &device.type(), roms = std::vector<rom_entry>()] () mutable -> rom_entry const * + { + if (!type) + return nullptr; + type = type->parent_rom_device_type(); + if (!type) + { + roms.clear(); + roms.shrink_to_fit(); + return nullptr; + } + else + { + machine_config config(GAME_NAME(___empty), options); + machine_config::token const tok(config.begin_configuration(config.root_device())); + roms = config.device_add("_tmp", *type, 0)->rom_region_vector(); + config.device_remove("_tmp"); + return &roms.front(); } }; } @@ -89,7 +142,7 @@ std::vector<std::string> make_software_searchpath(software_list_device &swlist, if (std::find(parents.begin(), parents.end(), i) != parents.end()) break; parents.emplace_back(i); - result.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->shortname())); + result.emplace_back(util::path_concat(swlist.list_name(), i->shortname())); i = i->parentname().empty() ? nullptr : swlist.find(i->parentname()); } @@ -101,13 +154,19 @@ std::vector<std::string> make_software_searchpath(software_list_device &swlist, } -std::error_condition do_open_disk(const emu_options &options, std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, chd_file &chd, std::function<const rom_entry * ()> next_parent) +std::error_condition do_open_disk( + emu_options const &options, + std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath, + rom_entry const *romp, + chd_file &chd, + std::function<rom_entry const * ()> next_parent, + chd_file::open_parent_func const &open_parent) { // hashes are fixed, but we might need to try multiple filenames std::set<std::string> tried; - const util::hash_collection hashes(romp->hashdata()); + util::hash_collection const hashes(romp->hashdata()); std::string filename, fullpath; - const rom_entry *parent(nullptr); + rom_entry const *parent(nullptr); std::error_condition result(std::errc::no_such_file_or_directory); while (romp && result) { @@ -116,11 +175,11 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l { // piggyback on emu_file to find the disk image file std::unique_ptr<emu_file> imgfile; - for (const std::vector<std::string> &paths : searchpath) + for (std::vector<std::string> const &paths : searchpath) { imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ)); imgfile->set_restrict_to_mediapath(1); - const std::error_condition filerr(imgfile->open(filename, OPEN_FLAG_READ)); + std::error_condition const filerr(imgfile->open(filename, OPEN_FLAG_READ)); if (!filerr) break; else @@ -132,7 +191,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l { fullpath = imgfile->fullpath(); imgfile.reset(); - result = chd.open(fullpath); + result = chd.open(fullpath, false, nullptr, open_parent); } } @@ -154,10 +213,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l romp = nullptr; break; } - while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent)) - ++parent; - if (ROMENTRY_ISEND(parent)) - parent = nullptr; + parent = rom_first_region(parent); } else { @@ -178,6 +234,46 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l return result; } + +auto open_parent_disk( + emu_options const &options, + std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath, + std::function<rom_entry const * ()> const &next_parent) +{ + return + [&options, searchpath, next_parent] (util::sha1_t const &sha1) -> std::unique_ptr<chd_file> + { + util::hash_collection hashes; + hashes.add_sha1(sha1); + std::function<rom_entry const * ()> np(next_parent); // important - copy mutable lambda + for (rom_entry const *parent = np(); parent; parent = np()) + { + parent = rom_first_region(parent); + while (parent) + { + while (parent && !ROMREGION_ISDISKDATA(parent)) + parent = rom_next_region(parent); + if (parent) + { + rom_entry const *romp(rom_first_file(parent)); + while (romp) + { + if (util::hash_collection(romp->hashdata()) == hashes) + { + std::unique_ptr<chd_file> chd(new chd_file); + if (!do_open_disk(options, searchpath, romp, *chd, next_parent, nullptr)) + return chd; + } + romp = rom_next_file(romp); + } + parent = rom_next_region(parent); + } + } + } + return nullptr; + }; +} + } // anonymous namespace @@ -257,7 +353,7 @@ const rom_entry *rom_first_parameter(const device_t &device) const rom_entry *romp = &device.rom_region_vector().front(); while (romp && !ROMENTRY_ISEND(romp) && !ROMENTRY_ISPARAMETER(romp)) romp++; - return (romp != nullptr && !ROMENTRY_ISEND(romp)) ? romp : nullptr; + return (romp && !ROMENTRY_ISEND(romp)) ? romp : nullptr; } @@ -282,17 +378,17 @@ const rom_entry *rom_next_parameter(const rom_entry *romp) u32 rom_file_size(const rom_entry *romp) { - u32 maxlength = 0; + u32 maxlength(0); - /* loop until we run out of reloads */ + // loop until we run out of reloads do { - /* loop until we run out of continues/ignores */ + // loop until we run out of continues/ignores u32 curlength = ROM_GETLENGTH(romp++); while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)) curlength += ROM_GETLENGTH(romp++); - /* track the maximum length */ + // track the maximum length maxlength = std::max(maxlength, curlength); } while (ROMENTRY_ISRELOAD(romp)); @@ -301,27 +397,6 @@ u32 rom_file_size(const rom_entry *romp) } -/*------------------------------------------------- - debugload - log data to a file --------------------------------------------------*/ - -static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...) -{ - static int opened; - va_list arg; - FILE *f; - - f = fopen("romload.log", opened++ ? "a" : "w"); - if (f) - { - va_start(arg, string); - vfprintf(f, string, arg); - va_end(arg); - fclose(f); - } -} - - /*************************************************************************** HARD DISK HANDLING ***************************************************************************/ @@ -334,8 +409,10 @@ static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...) chd_file *rom_load_manager::get_disk_handle(std::string_view region) { for (auto &curdisk : m_chd_list) + { if (curdisk->region() == region) return &curdisk->chd(); + } return nullptr; } @@ -345,37 +422,36 @@ chd_file *rom_load_manager::get_disk_handle(std::string_view region) file associated with the given region -------------------------------------------------*/ -std::error_condition rom_load_manager::set_disk_handle(std::string_view region, const char *fullpath) +std::error_condition rom_load_manager::set_disk_handle(std::string_view region, std::string_view fullpath) { - auto chd = std::make_unique<open_chd>(region); - auto err = chd->orig_chd().open(fullpath); + auto chd(std::make_unique<open_chd>(region)); + std::error_condition const err(chd->orig_chd().open(fullpath)); if (!err) - m_chd_list.push_back(std::move(chd)); + m_chd_list.emplace_back(std::move(chd)); return err; } /*------------------------------------------------- determine_bios_rom - determine system_bios - from SystemBios structure and OPTION_BIOS + from SYSTEM_BIOS structure and OPTION_BIOS -------------------------------------------------*/ -void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios) +void rom_load_manager::determine_bios_rom(device_t &device, std::string_view specbios) { // default is applied by the device at config complete time - if (specbios && *specbios && core_stricmp(specbios, "default")) + using namespace std::literals; + if (!specbios.empty() && !util::streqlower(specbios, "default"sv)) { bool found(false); - for (const rom_entry &rom : device.rom_region_vector()) + for (rom_entry const &rom : device.rom_region_vector()) { if (ROMENTRY_ISSYSTEM_BIOS(&rom)) { char const *const biosname = ROM_GETNAME(&rom); int const bios_flags = ROM_GETBIOSFLAGS(&rom); - char bios_number[20]; // Allow '-bios n' to still be used - sprintf(bios_number, "%d", bios_flags - 1); - if (!core_stricmp(bios_number, specbios) || !core_stricmp(biosname, specbios)) + if ((specbios == std::to_string(bios_flags - 1)) || util::streqlower(specbios, biosname)) { found = true; device.set_system_bios(bios_flags); @@ -404,21 +480,29 @@ void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios void rom_load_manager::count_roms() { - const rom_entry *region, *rom; - - /* start with 0 */ + // start with 0 m_romstotal = 0; m_romstotalsize = 0; - /* loop over regions, then over files */ + // loop over regions, and files within regions for (device_t &device : device_enumerator(machine().config().root_device())) - for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region)) - for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom)) - if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == device.system_bios()) + { + rom_entry const *region(rom_first_region(device)); + while (region) + { + rom_entry const *rom(rom_first_file(region)); + while (rom) + { + if ((ROM_GETBIOSFLAGS(rom) == 0) || (ROM_GETBIOSFLAGS(rom) == device.system_bios())) { m_romstotal++; m_romstotalsize += rom_file_size(rom); } + rom = rom_next_file(rom); + } + region = rom_next_region(region); + } + } } @@ -456,7 +540,7 @@ void rom_load_manager::handle_missing_file(const rom_entry *romp, const std::vec const bool is_chd(chderr); const std::string name(is_chd ? romp->name() + ".chd" : romp->name()); - const bool is_chd_error(is_chd && chderr != std::errc::no_such_file_or_directory); + const bool is_chd_error(is_chd && (chderr != std::errc::no_such_file_or_directory)); if (is_chd_error) m_errorstring.append(string_format("%s CHD ERROR: %s\n", name, chderr.message())); @@ -509,7 +593,7 @@ void rom_load_manager::verify_length_and_hash(emu_file *file, std::string_view n return; // verify length - u64 const actlength = file->size(); + u64 const actlength(file->size()); if (explength != actlength) { m_errorstring.append(string_format("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength)); @@ -525,7 +609,7 @@ void rom_load_manager::verify_length_and_hash(emu_file *file, std::string_view n else { // verify checksums - util::hash_collection const &acthashes = file->hashes(hashes.hash_types()); + util::hash_collection const &acthashes(file->hashes(hashes.hash_types())); if (hashes != acthashes) { // otherwise, it's just bad @@ -571,19 +655,19 @@ void rom_load_manager::display_loading_rom_message(const char *name, bool from_l void rom_load_manager::display_rom_load_results(bool from_list) { - /* final status display */ + // final status display display_loading_rom_message(nullptr, from_list); - /* if we had errors, they are fatal */ + // if we had errors, they are fatal if (m_errors != 0) { - /* create the error message and exit fatally */ + // create the error message and exit fatally osd_printf_error("%s", m_errorstring); throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run."); } - /* if we had warnings, output them, but continue */ - if ((m_warnings) || (m_knownbad)) + // if we had warnings, output them, but continue + if (m_warnings || m_knownbad) { m_errorstring.append("WARNING: the machine might not run correctly."); osd_printf_warning("%s\n", m_errorstring); @@ -599,27 +683,28 @@ void rom_load_manager::display_rom_load_results(bool from_list) void rom_load_manager::region_post_process(memory_region *region, bool invert) { // do nothing if no region - if (region == nullptr) + if (!region) return; - LOG("+ datawidth=%dbit endian=%s\n", region->bitwidth(), - region->endianness() == ENDIANNESS_LITTLE ? "little" : "big"); + LOG("+ datawidth=%dbit endian=%s\n", + region->bitwidth(), + (region->endianness() == ENDIANNESS_LITTLE) ? "little" : "big"); - /* if the region is inverted, do that now */ + // if the region is inverted, do that now if (invert) { LOG("+ Inverting region\n"); - u8 *base = region->base(); + u8 *base(region->base()); for (int i = 0; i < region->bytes(); i++) *base++ ^= 0xff; } - /* swap the endianness if we need to */ - if (region->bytewidth() > 1 && region->endianness() != ENDIANNESS_NATIVE) + // swap the endianness if we need to + int const datawidth(region->bytewidth()); + if ((datawidth > 1) && (region->endianness() != ENDIANNESS_NATIVE)) { LOG("+ Byte swapping region\n"); - int datawidth = region->bytewidth(); - u8 *base = region->base(); + u8 *base(region->base()); for (int i = 0; i < region->bytes(); i += datawidth) { u8 temp[8]; @@ -636,7 +721,11 @@ void rom_load_manager::region_post_process(memory_region *region, bool invert) up the parent and loading by checksum -------------------------------------------------*/ -std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list) +std::unique_ptr<emu_file> rom_load_manager::open_rom_file( + const std::vector<std::string> &searchpath, + const rom_entry *romp, + std::vector<std::string> &tried_file_names, + bool from_list) { std::error_condition filerr = std::errc::no_such_file_or_directory; u32 const romsize = rom_file_size(romp); @@ -651,13 +740,8 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list< // attempt reading up the chain through the parents // it also automatically attempts any kind of load by checksum supported by the archives. - std::unique_ptr<emu_file> result; - for (const std::vector<std::string> &paths : searchpath) - { - result = open_rom_file(paths, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr); - if (result) - break; - } + std::unique_ptr<emu_file> result( + open_rom_file(searchpath, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr)); // update counters m_romsloaded++; @@ -671,7 +755,13 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list< } -std::unique_ptr<emu_file> rom_load_manager::open_rom_file(const std::vector<std::string> &paths, std::vector<std::string> &tried, bool has_crc, u32 crc, std::string_view name, std::error_condition &filerr) +std::unique_ptr<emu_file> rom_load_manager::open_rom_file( + const std::vector<std::string> &paths, + std::vector<std::string> &tried, + bool has_crc, + u32 crc, + std::string_view name, + std::error_condition &filerr) { // record the set names we search tried.insert(tried.end(), paths.begin(), paths.end()); @@ -714,50 +804,52 @@ int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const ro entry -------------------------------------------------*/ -int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp) +int rom_load_manager::read_rom_data( + emu_file *file, + memory_region ®ion, + const rom_entry *parent_region, + const rom_entry *romp) { - int datashift = ROM_GETBITSHIFT(romp); - int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift; - int numbytes = ROM_GETLENGTH(romp); - int groupsize = ROM_GETGROUPSIZE(romp); - int skip = ROM_GETSKIPCOUNT(romp); - int reversed = ROM_ISREVERSED(romp); - int numgroups = (numbytes + groupsize - 1) / groupsize; - u8 *base = m_region->base() + ROM_GETOFFSET(romp); - u32 tempbufsize; - int i; + int const datashift(ROM_GETBITSHIFT(romp)); + int const datamask(((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift); + int numbytes(ROM_GETLENGTH(romp)); + int const groupsize(ROM_GETGROUPSIZE(romp)); + int skip(ROM_GETSKIPCOUNT(romp)); + int const reversed(ROM_ISREVERSED(romp)); + int const numgroups((numbytes + groupsize - 1) / groupsize); + u8 *base = region.base() + ROM_GETOFFSET(romp); LOG("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed); - /* make sure the length was an even multiple of the group size */ - if (numbytes % groupsize != 0) + // make sure the length was a whole multiple of the group size + if ((numbytes % groupsize) != 0) osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", romp->name()); - /* make sure we only fill within the region space */ - if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes()) + // make sure we only fill within the region space + if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > region.bytes()) throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", romp->name()); - /* make sure the length was valid */ + // make sure the length was valid if (numbytes == 0) throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", romp->name()); - /* special case for simple loads */ - if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0) + // special case for simple loads + if ((datamask == 0xff) && ((groupsize == 1) || !reversed) && (skip == 0)) return rom_fread(file, base, numbytes, parent_region); - /* use a temporary buffer for complex loads */ - tempbufsize = std::min(TEMPBUFFER_MAX_SIZE, numbytes); - std::vector<u8> tempbuf(tempbufsize); + // use a temporary buffer for complex loads + u32 const tempbufsize(std::min(TEMPBUFFER_MAX_SIZE, numbytes)); + std::unique_ptr<u8 []> const tempbuf(new u8 [tempbufsize]); - /* chunky reads for complex loads */ + // chunky reads for complex loads skip += groupsize; while (numbytes > 0) { - int evengroupcount = (tempbufsize / groupsize) * groupsize; - int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes; - u8 *bufptr = &tempbuf[0]; + int evengroupcount((tempbufsize / groupsize) * groupsize); + int bytesleft((numbytes > evengroupcount) ? evengroupcount : numbytes); + u8 *bufptr(tempbuf.get()); - /* read as much as we can */ + // read as much as we can LOG(" Reading %X bytes into buffer\n", bytesleft); if (rom_fread(file, bufptr, bytesleft, parent_region) != bytesleft) return 0; @@ -765,58 +857,65 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi LOG(" Copying to %p\n", base); - /* unmasked cases */ if (datamask == 0xff) { - /* non-grouped data */ + // unmasked cases if (groupsize == 1) - for (i = 0; i < bytesleft; i++, base += skip) + { + // non-grouped data + for (int i = 0; i < bytesleft; i++, base += skip) *base = *bufptr++; - - /* grouped data -- non-reversed case */ + } else if (!reversed) + { + // grouped data -- non-reversed case while (bytesleft) { - for (i = 0; i < groupsize && bytesleft; i++, bytesleft--) + for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--) base[i] = *bufptr++; base += skip; } - - /* grouped data -- reversed case */ + } else + { + // grouped data -- reversed case while (bytesleft) { - for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) + for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) base[i] = *bufptr++; base += skip; } + } } - - /* masked cases */ else { - /* non-grouped data */ + // masked cases if (groupsize == 1) - for (i = 0; i < bytesleft; i++, base += skip) + { + // non-grouped data + for (int i = 0; i < bytesleft; i++, base += skip) *base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask); - - /* grouped data -- non-reversed case */ + } else if (!reversed) + { + // grouped data -- non-reversed case while (bytesleft) { - for (i = 0; i < groupsize && bytesleft; i++, bytesleft--) + for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--) base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask); base += skip; } - - /* grouped data -- reversed case */ + } else + { + // grouped data -- reversed case while (bytesleft) { - for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) + for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask); base += skip; } + } } } @@ -829,14 +928,14 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi fill_rom_data - fill a region of ROM space -------------------------------------------------*/ -void rom_load_manager::fill_rom_data(const rom_entry *romp) +void rom_load_manager::fill_rom_data(memory_region ®ion, const rom_entry *romp) { u32 numbytes = ROM_GETLENGTH(romp); int skip = ROM_GETSKIPCOUNT(romp); - u8 *base = m_region->base() + ROM_GETOFFSET(romp); + u8 *base = region.base() + ROM_GETOFFSET(romp); // make sure we fill within the region space - if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes()) + if (ROM_GETOFFSET(romp) + numbytes > region.bytes()) throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n"); // make sure the length was valid @@ -861,15 +960,15 @@ void rom_load_manager::fill_rom_data(const rom_entry *romp) copy_rom_data - copy a region of ROM space -------------------------------------------------*/ -void rom_load_manager::copy_rom_data(const rom_entry *romp) +void rom_load_manager::copy_rom_data(memory_region ®ion, const rom_entry *romp) { - u8 *base = m_region->base() + ROM_GETOFFSET(romp); + u8 *base = region.base() + ROM_GETOFFSET(romp); const std::string &srcrgntag = romp->name(); u32 numbytes = ROM_GETLENGTH(romp); u32 srcoffs = u32(strtol(romp->hashdata().c_str(), nullptr, 0)); /* srcoffset in place of hashdata */ /* make sure we copy within the region space */ - if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes()) + if (ROM_GETOFFSET(romp) + numbytes > region.bytes()) throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n"); /* make sure the length was valid */ @@ -877,16 +976,16 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp) throw emu_fatalerror("Error in RomModule definition: COPY has an invalid length\n"); /* make sure the source was valid */ - memory_region *region = machine().root_device().memregion(srcrgntag); - if (region == nullptr) + memory_region *src = machine().root_device().memregion(srcrgntag); + if (!src) throw emu_fatalerror("Error in RomModule definition: COPY from an invalid region\n"); /* make sure we find within the region space */ - if (srcoffs + numbytes > region->bytes()) + if (srcoffs + numbytes > src->bytes()) throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n"); /* fill the data */ - memcpy(base, region->base() + srcoffs, numbytes); + memcpy(base, src->base() + srcoffs, numbytes); } @@ -895,7 +994,13 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp) for a region -------------------------------------------------*/ -void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list) +void rom_load_manager::process_rom_entries( + const std::vector<std::string> &searchpath, + u8 bios, + memory_region ®ion, + const rom_entry *parent_region, + const rom_entry *romp, + bool from_list) { u32 lastflags = 0; std::vector<std::string> tried_file_names; @@ -917,13 +1022,13 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_ if (ROMENTRY_ISFILL(romp)) { if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios)) - fill_rom_data(romp); + fill_rom_data(region, romp); romp++; } else if (ROMENTRY_ISCOPY(romp)) { - copy_rom_data(romp++); + copy_rom_data(region, romp++); } else if (ROMENTRY_ISFILE(romp)) { @@ -961,7 +1066,7 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_ // attempt to read using the modified entry if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios) - /*readresult = */read_rom_data(file.get(), parent_region, &modified_romp); + /*readresult = */read_rom_data(file.get(), region, parent_region, &modified_romp); } while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)); @@ -1000,7 +1105,11 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_ open_disk_diff - open a DISK diff file -------------------------------------------------*/ -std::error_condition rom_load_manager::open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd) +std::error_condition rom_load_manager::open_disk_diff( + emu_options &options, + const rom_entry *romp, + chd_file &source, + chd_file &diff_chd) { // TODO: use system name and/or software list name in the path - the current setup doesn't scale std::string fname = romp->name() + ".dif"; @@ -1046,41 +1155,55 @@ std::error_condition rom_load_manager::open_disk_diff(emu_options &options, cons for a region -------------------------------------------------*/ -void rom_load_manager::process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent) +void rom_load_manager::process_disk_entries( + search_paths searchpath, + std::string_view regiontag, + rom_entry const *romp, + std::function<rom_entry const * ()> next_parent, + chd_file::open_parent_func const &open_parent) { - /* remove existing disk entries for this region */ - m_chd_list.erase(std::remove_if(m_chd_list.begin(), m_chd_list.end(), - [regiontag] (std::unique_ptr<open_chd> &chd) { return chd->region() == regiontag; }), m_chd_list.end()); + // remove existing disk entries for this region + m_chd_list.erase( + std::remove_if( + m_chd_list.begin(), + m_chd_list.end(), + [®iontag] (std::unique_ptr<open_chd> &chd) { return chd->region() == regiontag; }), + m_chd_list.end()); - /* loop until we hit the end of this region */ + // loop until we hit the end of this region for ( ; !ROMENTRY_ISREGIONEND(romp); romp++) { - /* handle files */ + // handle files if (ROMENTRY_ISFILE(romp)) { - auto chd = std::make_unique<open_chd>(regiontag); + auto chd(std::make_unique<open_chd>(regiontag)); std::error_condition err; - /* make the filename of the source */ - const std::string filename = romp->name() + ".chd"; + // make the filename of the source + std::string const filename(romp->name() + ".chd"); - /* first open the source drive */ - // FIXME: we've lost the ability to search parents here + // first open the reference disk image LOG("Opening disk image: %s\n", filename.c_str()); - err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent); + err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent, open_parent); + if (!err && chd->orig_chd().parent_missing()) + err = chd_file::error::REQUIRES_PARENT; if (err) { - handle_missing_file(romp, std::vector<std::string>(), err); - chd = nullptr; + std::vector<std::string> tried; + for (auto const &paths : searchpath) + { + for (std::string const &path : paths.get()) + tried.emplace_back(path); + } + handle_missing_file(romp, tried, err); + chd.reset(); continue; } - /* get the header and extract the SHA1 */ + // get the header and verify the SHA1 digest util::hash_collection acthashes; acthashes.add_sha1(chd->orig_chd().sha1()); - - /* verify the hash */ - const util::hash_collection hashes(romp->hashdata()); + util::hash_collection const hashes(romp->hashdata()); if (hashes != acthashes) { m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename)); @@ -1093,23 +1216,22 @@ void rom_load_manager::process_disk_entries(std::initializer_list<std::reference m_knownbad++; } - /* if not read-only, make the diff file */ + // if not read-only, open or create the diff file if (!DISK_ISREADONLY(romp)) { - /* try to open or create the diff */ err = open_disk_diff(machine().options(), romp, chd->orig_chd(), chd->diff_chd()); if (err) { m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, err.message())); m_errors++; - chd = nullptr; + chd.reset(); continue; } } - /* we're okay, add to the list of disks */ + // we're okay, add to the list of disks LOG("Assigning to handle %d\n", DISK_GETINDEX(romp)); - m_chd_list.push_back(std::move(chd)); + m_chd_list.emplace_back(std::move(chd)); } } } @@ -1132,7 +1254,11 @@ std::vector<std::string> rom_load_manager::get_software_searchpath(software_list device -------------------------------------------------*/ -std::error_condition rom_load_manager::open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd) +std::error_condition rom_load_manager::open_disk_image( + emu_options &options, + const device_t &device, + const rom_entry *romp, + chd_file &image_chd) { const std::vector<std::string> searchpath(device.searchpath()); @@ -1141,8 +1267,14 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option if (driver) next_parent = next_parent_system(driver->system()); else - next_parent = [] () { return nullptr; }; - return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent)); + next_parent = next_parent_device(device, options); + chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent)); + std::error_condition const err( + do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent)); + if (!err && image_chd.parent_missing()) + return chd_file::error::REQUIRES_PARENT; + else + return err; } @@ -1151,12 +1283,24 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option software item -------------------------------------------------*/ -std::error_condition rom_load_manager::open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd) +std::error_condition rom_load_manager::open_disk_image( + emu_options &options, + software_list_device &swlist, + const software_info &swinfo, + const rom_entry *romp, + chd_file &image_chd) { std::vector<software_info const *> parents; - std::vector<std::string> searchpath = make_software_searchpath(swlist, swinfo, parents); + std::vector<std::string> searchpath(make_software_searchpath(swlist, swinfo, parents)); searchpath.emplace_back(swlist.list_name()); // look for loose disk images in software list directory - return do_open_disk(options, { searchpath }, romp, image_chd, next_parent_software(parents)); + std::function<const rom_entry * ()> next_parent(next_parent_software(parents)); + chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent)); + std::error_condition const err( + do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent)); + if (!err && image_chd.parent_missing()) + return chd_file::error::REQUIRES_PARENT; + else + return err; } @@ -1216,11 +1360,11 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list m_romsloadedsize = 0; std::vector<const software_info *> parents; - std::vector<std::string> swsearch, disksearch, devsearch; + std::vector<std::string> swsearch, disksearch; const software_info *const swinfo = swlist.find(std::string(swname)); if (swinfo) { - // dispay a warning for unsupported software + // display a warning for unsupported software // TODO: list supported clones like we do for machines? if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) { @@ -1245,13 +1389,9 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list // this is convenient for CD-only lists so you don't need an extra level of directories containing one file each disksearch.emplace_back(swlist.list_name()); - // for historical reasons, add the search path for the software list device's owner - const device_t *const listowner = swlist.owner(); - if (listowner) - devsearch = listowner->searchpath(); - // loop until we hit the end std::function<const rom_entry * ()> next_parent; + chd_file::open_parent_func open_parent; for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region)) { u32 regionlength = ROMREGION_GETLENGTH(region); @@ -1266,7 +1406,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; u8 width = ROMREGION_GETWIDTH(region) / 8; memory_region *memregion = machine().root_device().memregion(regiontag); - if (memregion != nullptr) + if (memregion) { normalize_flags_for_device(regiontag, width, endianness); @@ -1275,16 +1415,16 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list } // remember the base and length - m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness); - LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base()); + memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness); + LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base()); if (ROMREGION_ISERASE(region)) // clear the region if it's requested - memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes()); - else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB) - memset(m_region->base(), 0, m_region->bytes()); + memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes()); + else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB) + memset(memregion->base(), 0, memregion->bytes()); #ifdef MAME_DEBUG else // if we're debugging, fill region with random data to catch errors - fill_random(m_region->base(), m_region->bytes()); + fill_random(memregion->base(), memregion->bytes()); #endif // update total number of roms @@ -1297,10 +1437,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list // now process the entries in the region if (ROMREGION_ISROMDATA(region)) { - if (devsearch.empty()) - process_rom_entries({ swsearch }, 0U, region, region + 1, true); - else - process_rom_entries({ swsearch, devsearch }, 0U, region, region + 1, true); + process_rom_entries(swsearch, 0U, *memregion, region, region + 1, true); } else if (ROMREGION_ISDISKDATA(region)) { @@ -1310,11 +1447,9 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list next_parent = next_parent_software(parents); else next_parent = [] () { return nullptr; }; + open_parent = open_parent_disk(machine().options(), { swsearch, disksearch }, next_parent); } - if (devsearch.empty()) - process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent); - else - process_disk_entries({ swsearch, disksearch, devsearch }, regiontag, region + 1, next_parent); + process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent, open_parent); } } @@ -1340,6 +1475,7 @@ void rom_load_manager::process_region_list() { searchpath.clear(); std::function<const rom_entry * ()> next_parent; + chd_file::open_parent_func open_parent; for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region)) { u32 regionlength = ROMREGION_GETLENGTH(region); @@ -1358,23 +1494,23 @@ void rom_load_manager::process_region_list() normalize_flags_for_device(regiontag, width, endianness); // remember the base and length - m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness); - LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base()); + memory_region *const memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness); + LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base()); if (ROMREGION_ISERASE(region)) // clear the region if it's requested - memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes()); - else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB) - memset(m_region->base(), 0, m_region->bytes()); + memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes()); + else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB) + memset(memregion->base(), 0, memregion->bytes()); #ifdef MAME_DEBUG else // if we're debugging, fill region with random data to catch errors - fill_random(m_region->base(), m_region->bytes()); + fill_random(memregion->base(), memregion->bytes()); #endif // now process the entries in the region if (searchpath.empty()) searchpath = device.searchpath(); assert(!searchpath.empty()); - process_rom_entries({ searchpath }, device.system_bios(), region, region + 1, false); + process_rom_entries(searchpath, device.system_bios(), *memregion, region, region + 1, false); } else if (ROMREGION_ISDISKDATA(region)) { @@ -1387,9 +1523,10 @@ void rom_load_manager::process_region_list() if (driver) next_parent = next_parent_system(driver->system()); else - next_parent = [] () { return nullptr; }; + next_parent = next_parent_device(device, machine().options()); + open_parent = open_parent_disk(machine().options(), { searchpath }, next_parent); } - process_disk_entries({ searchpath }, regiontag, region + 1, next_parent); + process_disk_entries({ searchpath }, regiontag, region + 1, next_parent, open_parent); } } } @@ -1426,7 +1563,6 @@ rom_load_manager::rom_load_manager(running_machine &machine) , m_romsloadedsize(0) , m_romstotalsize(0) , m_chd_list() - , m_region(nullptr) , m_errorstring() , m_softwarningstring() { @@ -1459,7 +1595,7 @@ rom_load_manager::rom_load_manager(running_machine &machine) card_bios.erase(found); } } - determine_bios_rom(device, specbios.c_str()); + determine_bios_rom(device, specbios); } } diff --git a/src/emu/romload.h b/src/emu/romload.h index 76fdb111cc6..4ad0303a9f6 100644 --- a/src/emu/romload.h +++ b/src/emu/romload.h @@ -17,7 +17,9 @@ #include <functional> #include <initializer_list> +#include <memory> #include <string> +#include <string_view> #include <system_error> #include <type_traits> #include <vector> @@ -102,11 +104,11 @@ protected: const_entry_iterator &operator=(const_entry_iterator &&) noexcept = default; public: - typedef T value_type; - typedef value_type const *pointer; - typedef value_type const &reference; - typedef std::ptrdiff_t difference_type; - typedef std::forward_iterator_tag iterator_category; + using value_type = T; + using pointer = value_type const *; + using reference = value_type const &; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; reference operator*() const noexcept { return reinterpret_cast<reference>(*m_data); } pointer operator->() const noexcept { return reinterpret_cast<pointer>(m_data); } @@ -387,6 +389,7 @@ class rom_load_manager { public: open_chd(std::string_view region) : m_region(region) { } + open_chd(std::string &®ion) : m_region(std::move(region)) { } std::string_view region() const { return m_region; } chd_file &chd() { return m_diffchd.opened() ? m_diffchd : m_origchd; } @@ -394,9 +397,9 @@ class rom_load_manager chd_file &diff_chd() { return m_diffchd; } private: - std::string m_region; /* disk region we came from */ - chd_file m_origchd; /* handle to the original CHD */ - chd_file m_diffchd; /* handle to the diff CHD */ + std::string m_region; // disk region we came from + chd_file m_origchd; // handle to the original CHD + chd_file m_diffchd; // handle to the diff CHD }; public: @@ -420,7 +423,7 @@ public: chd_file *get_disk_handle(std::string_view region); /* set a pointer to the CHD file associated with the given region */ - std::error_condition set_disk_handle(std::string_view region, const char *fullpath); + std::error_condition set_disk_handle(std::string_view region, std::string_view fullpath); void load_software_part_region(device_t &device, software_list_device &swlist, std::string_view swname, const rom_entry *start_region); @@ -428,11 +431,13 @@ public: static std::vector<std::string> get_software_searchpath(software_list_device &swlist, const software_info &swinfo); /* open a disk image, searching up the parent and loading by checksum */ - static std::error_condition open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd); - static std::error_condition open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd); + static std::error_condition open_disk_image(emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd); + static std::error_condition open_disk_image(emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd); private: - void determine_bios_rom(device_t &device, const char *specbios); + using search_paths = std::initializer_list<std::reference_wrapper<const std::vector<std::string> > >; + + void determine_bios_rom(device_t &device, std::string_view specbios); void count_roms(); void fill_random(u8 *base, u32 length); void handle_missing_file(const rom_entry *romp, const std::vector<std::string> &tried_file_names, std::error_condition chderr); @@ -441,15 +446,40 @@ private: void display_loading_rom_message(const char *name, bool from_list); void display_rom_load_results(bool from_list); void region_post_process(memory_region *region, bool invert); - std::unique_ptr<emu_file> open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list); - std::unique_ptr<emu_file> open_rom_file(const std::vector<std::string> &paths, std::vector<std::string> &tried, bool has_crc, u32 crc, std::string_view name, std::error_condition &filerr); + std::unique_ptr<emu_file> open_rom_file( + const std::vector<std::string> &searchpath, + const rom_entry *romp, + std::vector<std::string> &tried_file_names, + bool from_list); + std::unique_ptr<emu_file> open_rom_file( + const std::vector<std::string> &paths, + std::vector<std::string> &tried, + bool has_crc, + u32 crc, + std::string_view name, + std::error_condition &filerr); int rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region); - int read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp); - void fill_rom_data(const rom_entry *romp); - void copy_rom_data(const rom_entry *romp); - void process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list); - std::error_condition open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd); - void process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent); + int read_rom_data(emu_file *file, memory_region ®ion, const rom_entry *parent_region, const rom_entry *romp); + void fill_rom_data(memory_region ®ion, const rom_entry *romp); + void copy_rom_data(memory_region ®ion, const rom_entry *romp); + void process_rom_entries( + const std::vector<std::string> &searchpath, + u8 bios, + memory_region ®ion, + const rom_entry *parent_region, + const rom_entry *romp, + bool from_list); + std::error_condition open_disk_diff( + emu_options &options, + const rom_entry *romp, + chd_file &source, + chd_file &diff_chd); + void process_disk_entries( + search_paths searchpath, + std::string_view regiontag, + const rom_entry *romp, + std::function<const rom_entry * ()> next_parent, + const chd_file::open_parent_func &open_parent); void normalize_flags_for_device(std::string_view rgntag, u8 &width, endianness_t &endian); void process_region_list(); @@ -467,8 +497,6 @@ private: std::vector<std::unique_ptr<open_chd>> m_chd_list; /* disks */ - memory_region * m_region; // info about current region - std::string m_errorstring; // error string std::string m_softwarningstring; // software warning string }; diff --git a/src/emu/save.cpp b/src/emu/save.cpp index a27a98ee23c..8c3329e7b38 100644 --- a/src/emu/save.cpp +++ b/src/emu/save.cpp @@ -25,7 +25,8 @@ #include "emu.h" #include "emuopts.h" -#include "util/coreutil.h" +#include "main.h" + #include "util/ioprocs.h" #include "util/ioprocsfilter.h" @@ -66,7 +67,6 @@ enum save_manager::save_manager(running_machine &machine) : m_machine(machine) , m_reg_allowed(true) - , m_illegal_regs(0) { m_rewind = std::make_unique<rewinder>(*this); } @@ -185,9 +185,7 @@ void save_manager::save_memory(device_t *device, const char *module, const char if (!m_reg_allowed) { machine().logerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name); - if (machine().system().flags & machine_flags::SUPPORTS_SAVE) - fatalerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name); - m_illegal_regs++; + fatalerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name); return; } @@ -208,7 +206,7 @@ void save_manager::save_memory(device_t *device, const char *module, const char // state //------------------------------------------------- -save_error save_manager::check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)) +save_error save_manager::check_file(running_machine &machine, util::core_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)) { // if we want to validate the signature, compute it u32 sig; @@ -217,10 +215,11 @@ save_error save_manager::check_file(running_machine &machine, emu_file &file, co // seek to the beginning and read the header file.seek(0, SEEK_SET); u8 header[HEADER_SIZE]; - if (file.read(header, sizeof(header)) != sizeof(header)) + auto const [err, actual] = read(file, header, sizeof(header)); + if (err || (actual != sizeof(header))) { if (errormsg != nullptr) - (*errormsg)("Could not read %s save file header",emulator_info::get_appname()); + (*errormsg)("Could not read %s save file header", emulator_info::get_appname()); return STATERR_READ_ERROR; } @@ -257,16 +256,15 @@ void save_manager::dispatch_presave() // write_file - writes the data to a file //------------------------------------------------- -save_error save_manager::write_file(emu_file &file) +save_error save_manager::write_file(util::core_file &file) { util::write_stream::ptr writer; save_error err = do_write( [] (size_t total_size) { return true; }, [&writer] (const void *data, size_t size) { - size_t written; - std::error_condition filerr = writer->write(data, size, written); - return !filerr && (size == written); + auto const [filerr, written] = write(*writer, data, size); + return !filerr; }, [&file, &writer] () { @@ -290,16 +288,15 @@ save_error save_manager::write_file(emu_file &file) // read_file - read the data from a file //------------------------------------------------- -save_error save_manager::read_file(emu_file &file) +save_error save_manager::read_file(util::core_file &file) { util::read_stream::ptr reader; return do_read( [] (size_t total_size) { return true; }, [&reader] (void *data, size_t size) { - std::size_t read; - std::error_condition filerr = reader->read(data, size, read); - return !filerr && (read == size); + auto const [filerr, actual] = read(*reader, data, size); + return !filerr && (actual == size); }, [&file, &reader] () { @@ -405,10 +402,6 @@ save_error save_manager::read_buffer(const void *buf, size_t size) template <typename T, typename U, typename V, typename W> inline save_error save_manager::do_write(T check_space, U write_block, V start_header, W start_data) { - // if we have illegal registrations, return an error - if (m_illegal_regs > 0) - return STATERR_ILLEGAL_REGISTRATIONS; - // check for sufficient space size_t total_size = HEADER_SIZE; for (const auto &entry : m_entry_list) @@ -452,10 +445,6 @@ inline save_error save_manager::do_write(T check_space, U write_block, V start_h template <typename T, typename U, typename V, typename W> inline save_error save_manager::do_read(T check_length, U read_block, V start_header, W start_data) { - // if we have illegal registrations, return an error - if (m_illegal_regs > 0) - return STATERR_ILLEGAL_REGISTRATIONS; - // check for sufficient space size_t total_size = HEADER_SIZE; for (const auto &entry : m_entry_list) @@ -505,11 +494,11 @@ inline save_error save_manager::do_read(T check_length, U read_block, V start_he u32 save_manager::signature() const { // iterate over entries - u32 crc = 0; + util::crc32_creator crc; for (auto &entry : m_entry_list) { // add the entry name to the CRC - crc = core_crc32(crc, (u8 *)entry->m_name.c_str(), entry->m_name.length()); + crc.append(entry->m_name.data(), entry->m_name.length()); // add the type and size to the CRC u32 temp[4]; @@ -517,9 +506,9 @@ u32 save_manager::signature() const temp[1] = little_endianize_int32(entry->m_typecount); temp[2] = little_endianize_int32(entry->m_blockcount); temp[3] = little_endianize_int32(entry->m_stride); - crc = core_crc32(crc, (u8 *)&temp[0], sizeof(temp)); + crc.append(&temp[0], sizeof(temp)); } - return crc; + return crc.finish(); } @@ -547,7 +536,7 @@ save_error save_manager::validate_header(const u8 *header, const char *gamename, if (memcmp(header, STATE_MAGIC_NUM, 8)) { if (errormsg != nullptr) - (*errormsg)("%sThis is not a %s save file", error_prefix,emulator_info::get_appname()); + (*errormsg)("%sThis is not a %s save file", error_prefix, emulator_info::get_appname()); return STATERR_INVALID_HEADER; } @@ -660,10 +649,6 @@ save_error ram_state::load() // initialize m_data.seekg(0); - // if we have illegal registrations, return an error - if (m_save.m_illegal_regs > 0) - return STATERR_ILLEGAL_REGISTRATIONS; - // get the save manager to load state return m_save.read_stream(m_data); } @@ -913,11 +898,6 @@ void rewinder::report_error(save_error error, rewind_operation operation) switch (error) { // internal saveload failures - case STATERR_ILLEGAL_REGISTRATIONS: - m_save.machine().logerror("Rewind error: Unable to %s state due to illegal registrations.", opname); - m_save.machine().popmessage("Rewind error occured. See error.log for details."); - break; - case STATERR_INVALID_HEADER: m_save.machine().logerror("Rewind error: Unable to %s state due to an invalid header. " "Make sure the save state is correct for this machine.\n", opname); diff --git a/src/emu/save.h b/src/emu/save.h index 2ea17ab9921..e473f408317 100644 --- a/src/emu/save.h +++ b/src/emu/save.h @@ -34,7 +34,6 @@ enum save_error { STATERR_NONE, STATERR_NOT_FOUND, - STATERR_ILLEGAL_REGISTRATIONS, STATERR_INVALID_HEADER, STATERR_READ_ERROR, STATERR_WRITE_ERROR, @@ -300,9 +299,9 @@ public: { save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), element, valname, count); } // file processing - static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)); - save_error write_file(emu_file &file); - save_error read_file(emu_file &file); + static save_error check_file(running_machine &machine, util::core_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)); + save_error write_file(util::core_file &file); + save_error read_file(util::core_file &file); save_error write_stream(std::ostream &str); save_error read_stream(std::istream &str); @@ -334,7 +333,6 @@ private: running_machine & m_machine; // reference to our machine std::unique_ptr<rewinder> m_rewind; // rewinder bool m_reg_allowed; // are registrations allowed? - s32 m_illegal_regs; // number of illegal registrations std::vector<std::unique_ptr<state_entry>> m_entry_list; // list of registered entries std::vector<std::unique_ptr<ram_state>> m_ramstate_list; // list of ram states diff --git a/src/emu/schedule.cpp b/src/emu/schedule.cpp index e32afb68f00..acc596d6798 100644 --- a/src/emu/schedule.cpp +++ b/src/emu/schedule.cpp @@ -44,19 +44,16 @@ enum // emu_timer - constructor //------------------------------------------------- -emu_timer::emu_timer() : - m_machine(nullptr), +inline emu_timer::emu_timer() noexcept : + m_scheduler(nullptr), m_next(nullptr), m_prev(nullptr), m_param(0), - m_ptr(nullptr), m_enabled(false), m_temporary(false), m_period(attotime::zero), m_start(attotime::zero), - m_expire(attotime::never), - m_device(nullptr), - m_id(0) + m_expire(attotime::never) { } @@ -75,74 +72,35 @@ emu_timer::~emu_timer() // re-allocated as a non-device timer //------------------------------------------------- -inline emu_timer &emu_timer::init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary) +inline emu_timer &emu_timer::init( + running_machine &machine, + timer_expired_delegate &&callback, + attotime start_delay, + s32 param, + bool temporary) { // ensure the entire timer state is clean - m_machine = &machine; + m_scheduler = &machine.scheduler(); m_next = nullptr; m_prev = nullptr; - m_callback = callback; - m_param = 0; - m_ptr = ptr; - m_enabled = false; + m_callback = std::move(callback); + m_param = param; m_temporary = temporary; m_period = attotime::never; - m_start = machine.time(); - m_expire = attotime::never; - m_device = nullptr; - m_id = 0; - - // if we're not temporary, register ourselves with the save state system - if (!m_temporary) - register_save(); - - // insert into the list - machine.scheduler().timer_list_insert(*this); - return *this; -} - - -//------------------------------------------------- -// init - completely initialize the state when -// re-allocated as a device timer -//------------------------------------------------- -inline emu_timer &emu_timer::init(device_t &device, device_timer_id id, void *ptr, bool temporary) -{ - // ensure the entire timer state is clean - m_machine = &device.machine(); - m_next = nullptr; - m_prev = nullptr; - m_callback = timer_expired_delegate(FUNC(emu_timer::device_timer_expired), this); - m_param = 0; - m_ptr = ptr; - m_enabled = false; - m_temporary = temporary; - m_period = attotime::never; - m_start = machine().time(); - m_expire = attotime::never; - m_device = &device; - m_id = id; + m_start = m_scheduler->time(); + m_expire = m_start + start_delay; + m_enabled = !m_expire.is_never(); // if we're not temporary, register ourselves with the save state system if (!m_temporary) - register_save(); + register_save(machine.save()); // insert into the list - machine().scheduler().timer_list_insert(*this); - return *this; -} - + m_scheduler->timer_list_insert(*this); + if (this == m_scheduler->first_timer()) + m_scheduler->abort_timeslice(); -//------------------------------------------------- -// release - release us from the global list -// management when deallocating -//------------------------------------------------- - -inline emu_timer &emu_timer::release() -{ - // unhook us from the global list - machine().scheduler().timer_list_remove(*this); return *this; } @@ -151,8 +109,10 @@ inline emu_timer &emu_timer::release() // enable - enable/disable a timer //------------------------------------------------- -bool emu_timer::enable(bool enable) +bool emu_timer::enable(bool enable) noexcept { + assert(m_scheduler); + // reschedule only if the state has changed const bool old = m_enabled; if (old != enable) @@ -161,8 +121,8 @@ bool emu_timer::enable(bool enable) m_enabled = enable; // remove the timer and insert back into the list - machine().scheduler().timer_list_remove(*this); - machine().scheduler().timer_list_insert(*this); + m_scheduler->timer_list_remove(*this); + m_scheduler->timer_list_insert(*this); } return old; } @@ -174,12 +134,13 @@ bool emu_timer::enable(bool enable) // firings //------------------------------------------------- -void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period) +void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period) noexcept { + assert(m_scheduler); + // if this is the callback timer, mark it modified - device_scheduler &scheduler = machine().scheduler(); - if (scheduler.m_callback_timer == this) - scheduler.m_callback_timer_modified = true; + if (m_scheduler->m_callback_timer == this) + m_scheduler->m_callback_timer_modified = true; // compute the time of the next firing and insert into the list m_param = param; @@ -190,17 +151,17 @@ void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period) start_delay = attotime::zero; // set the start and expire times - m_start = scheduler.time(); + m_start = m_scheduler->time(); m_expire = m_start + start_delay; m_period = period; // remove and re-insert the timer in its new order - scheduler.timer_list_remove(*this); - scheduler.timer_list_insert(*this); + m_scheduler->timer_list_remove(*this); + m_scheduler->timer_list_insert(*this); // if this was inserted as the head, abort the current timeslice and resync - if (this == scheduler.first_timer()) - scheduler.abort_timeslice(); + if (this == m_scheduler->first_timer()) + m_scheduler->abort_timeslice(); } @@ -211,7 +172,9 @@ void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period) attotime emu_timer::elapsed() const noexcept { - return machine().time() - m_start; + assert(m_scheduler); + + return m_scheduler->time() - m_start; } @@ -222,7 +185,9 @@ attotime emu_timer::elapsed() const noexcept attotime emu_timer::remaining() const noexcept { - attotime curtime = machine().time(); + assert(m_scheduler); + + const attotime curtime = m_scheduler->time(); if (curtime >= m_expire) return attotime::zero; return m_expire - curtime; @@ -234,40 +199,37 @@ attotime emu_timer::remaining() const noexcept // state system //------------------------------------------------- -void emu_timer::register_save() +void emu_timer::register_save(save_manager &manager) { - // determine our instance number and name + // determine our instance number - timers are indexed based on the callback function name int index = 0; - std::string name; - - if (m_device == nullptr) + std::string name = m_callback.name() ? m_callback.name() : "unnamed"; + for (const emu_timer *curtimer = m_scheduler->first_timer(); curtimer; curtimer = curtimer->m_next) { - // for non-device timers, it is an index based on the callback function name - name = m_callback.name() ? m_callback.name() : "unnamed"; - for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next()) - if (!curtimer->m_temporary && curtimer->m_device == nullptr) - { - if (curtimer->m_callback.name() != nullptr && m_callback.name() != nullptr && strcmp(curtimer->m_callback.name(), m_callback.name()) == 0) - index++; - else if (curtimer->m_callback.name() == nullptr && m_callback.name() == nullptr) - index++; - } + if (!curtimer->m_temporary) + { + if (curtimer->m_callback.name() && m_callback.name() && !strcmp(curtimer->m_callback.name(), m_callback.name())) + index++; + else if (!curtimer->m_callback.name() && !m_callback.name()) + index++; + } } - else + for (const emu_timer *curtimer = m_scheduler->m_inactive_timers; curtimer; curtimer = curtimer->m_next) { - // for device timers, it is an index based on the device and timer ID - name = string_format("%s/%d", m_device->tag(), m_id); - for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next()) - if (!curtimer->m_temporary && curtimer->m_device == m_device && curtimer->m_id == m_id) - index++; + assert(!curtimer->m_temporary); + + if (curtimer->m_callback.name() && m_callback.name() && !strcmp(curtimer->m_callback.name(), m_callback.name())) + index++; + else if (!curtimer->m_callback.name() && !m_callback.name()) + index++; } // save the bits - machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_param)); - machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_enabled)); - machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_period)); - machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_start)); - machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_expire)); + manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_param)); + manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_enabled)); + manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_period)); + manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_start)); + manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_expire)); } @@ -276,16 +238,17 @@ void emu_timer::register_save() // period //------------------------------------------------- -inline void emu_timer::schedule_next_period() +inline void emu_timer::schedule_next_period() noexcept { + assert(m_scheduler); + // advance by one period m_start = m_expire; m_expire += m_period; // remove and re-insert us - device_scheduler &scheduler = machine().scheduler(); - scheduler.timer_list_remove(*this); - scheduler.timer_list_insert(*this); + m_scheduler->timer_list_remove(*this); + m_scheduler->timer_list_insert(*this); } @@ -296,25 +259,13 @@ inline void emu_timer::schedule_next_period() void emu_timer::dump() const { - machine().logerror("%p: en=%d temp=%d exp=%15s start=%15s per=%15s param=%d ptr=%p", this, m_enabled, m_temporary, m_expire.as_string(PRECISION), m_start.as_string(PRECISION), m_period.as_string(PRECISION), m_param, m_ptr); - if (m_device == nullptr) - if (m_callback.name() == nullptr) - machine().logerror(" cb=NULL\n"); - else - machine().logerror(" cb=%s\n", m_callback.name()); - else - machine().logerror(" dev=%s id=%d\n", m_device->tag(), m_id); -} + assert(m_scheduler); - -//------------------------------------------------- -// device_timer_expired - trampoline to avoid a -// conditional jump on the hot path -//------------------------------------------------- - -void emu_timer::device_timer_expired(emu_timer &timer, void *ptr, s32 param) -{ - timer.m_device->timer_expired(timer, timer.m_id, param, ptr); + m_scheduler->machine().logerror("%p: en=%d temp=%d exp=%15s start=%15s per=%15s param=%d", this, m_enabled, m_temporary, m_expire.as_string(PRECISION), m_start.as_string(PRECISION), m_period.as_string(PRECISION), m_param); + if (!m_callback.name()) + m_scheduler->machine().logerror(" cb=NULL\n"); + else + m_scheduler->machine().logerror(" cb=%s\n", m_callback.name()); } @@ -333,6 +284,7 @@ device_scheduler::device_scheduler(running_machine &machine) : m_execute_list(nullptr), m_basetime(attotime::zero), m_timer_list(nullptr), + m_inactive_timers(nullptr), m_callback_timer(nullptr), m_callback_timer_modified(false), m_callback_timer_expire_time(attotime::zero), @@ -340,8 +292,13 @@ device_scheduler::device_scheduler(running_machine &machine) : m_quantum_minimum(ATTOSECONDS_IN_NSEC(1) / 1000) { // append a single never-expiring timer so there is always one in the list - m_timer_list = &m_timer_allocator.alloc()->init(machine, timer_expired_delegate(), nullptr, true); - m_timer_list->adjust(attotime::never); + // need to subvert it because it would naturally be inserted in the inactive list + m_timer_list = &timer_list_remove(m_timer_allocator.alloc()->init(machine, timer_expired_delegate(), attotime::never, 0, true)); + + assert(m_timer_list); + assert(!m_timer_list->m_prev); + assert(!m_timer_list->m_next); + assert(!m_inactive_timers); // register global states machine.save().save_item(NAME(m_basetime)); @@ -357,8 +314,10 @@ device_scheduler::device_scheduler(running_machine &machine) : device_scheduler::~device_scheduler() { // remove all timers - while (m_timer_list != nullptr) - m_timer_allocator.reclaim(m_timer_list->release()); + while (m_inactive_timers) + m_timer_allocator.reclaim(timer_list_remove(*m_inactive_timers)); + while (m_timer_list) + m_timer_allocator.reclaim(timer_list_remove(*m_timer_list)); } @@ -386,13 +345,15 @@ attotime device_scheduler::time() const noexcept bool device_scheduler::can_save() const { // if any live temporary timers exit, fail - for (emu_timer *timer = m_timer_list; timer != nullptr; timer = timer->next()) + for (emu_timer *timer = m_timer_list; timer; timer = timer->m_next) + { if (timer->m_temporary && !timer->expire().is_never()) { machine().logerror("Failed save state attempt due to anonymous timers:\n"); dump_timers(); return false; } + } // otherwise, we're good return true; @@ -484,7 +445,7 @@ void device_scheduler::timeslice() // if we're not suspended, actually execute if (exec->m_suspend == 0) { - g_profiler.start(exec->m_profiler); + auto profile = g_profiler.start(exec->m_profiler); // note that this global variable cycles_stolen can be modified // via the call to cpu_execute @@ -505,7 +466,6 @@ void device_scheduler::timeslice() ran -= *exec->m_icountptr; assert(ran >= exec->m_cycles_stolen); ran -= exec->m_cycles_stolen; - g_profiler.stop(); } // account for these cycles @@ -550,7 +510,7 @@ void device_scheduler::timeslice() // current timeslice //------------------------------------------------- -void device_scheduler::abort_timeslice() +void device_scheduler::abort_timeslice() noexcept { if (m_executing_device != nullptr) m_executing_device->abort_timeslice(); @@ -567,74 +527,117 @@ void device_scheduler::trigger(int trigid, const attotime &after) if (m_execute_list == nullptr) rebuild_execute_list(); - // if we have a non-zero time, schedule a timer if (after != attotime::zero) + { + // if we have a non-zero time, schedule a timer timer_set(after, timer_expired_delegate(FUNC(device_scheduler::timed_trigger), this), trigid); - - // send the trigger to everyone who cares + } else - for (device_execute_interface *exec = m_execute_list; exec != nullptr; exec = exec->m_nextexec) + { + // send the trigger to everyone who cares + for (device_execute_interface *exec = m_execute_list; exec; exec = exec->m_nextexec) exec->trigger(trigid); + } } //------------------------------------------------- -// boost_interleave - temporarily boosts the -// interleave factor +// add_quantum - add a scheduling quantum; +// the smallest active one is the one that is in use //------------------------------------------------- -void device_scheduler::boost_interleave(const attotime ×lice_time, const attotime &boost_duration) +void device_scheduler::add_quantum(const attotime &quantum, const attotime &duration) { - // ignore timeslices > 1 second - if (timeslice_time.seconds() > 0) - return; - add_scheduling_quantum(timeslice_time, boost_duration); + assert(quantum.seconds() == 0); + + attotime curtime = time(); + attotime expire = curtime + duration; + const attoseconds_t quantum_attos = quantum.attoseconds(); + + // figure out where to insert ourselves, expiring any quanta that are out-of-date + quantum_slot *insert_after = nullptr; + quantum_slot *next; + for (quantum_slot *quant = m_quantum_list.first(); quant != nullptr; quant = next) + { + // if this quantum is expired, nuke it + next = quant->next(); + if (curtime >= quant->m_expire) + m_quantum_allocator.reclaim(m_quantum_list.detach(*quant)); + + // if this quantum is shorter than us, we need to be inserted afterwards + else if (quant->m_requested <= quantum_attos) + insert_after = quant; + } + + // if we found an exact match, just take the maximum expiry time + if (insert_after != nullptr && insert_after->m_requested == quantum_attos) + insert_after->m_expire = std::max(insert_after->m_expire, expire); + + // otherwise, allocate a new quantum and insert it after the one we picked + else + { + quantum_slot &quant = *m_quantum_allocator.alloc(); + quant.m_requested = quantum_attos; + quant.m_actual = std::max(quantum_attos, m_quantum_minimum); + quant.m_expire = expire; + m_quantum_list.insert_after(quant, insert_after); + } } //------------------------------------------------- -// timer_alloc - allocate a global non-device -// timer and return a pointer +// perfect_quantum - add a (temporary) minimum +// scheduling quantum to boost the interleave //------------------------------------------------- -emu_timer *device_scheduler::timer_alloc(timer_expired_delegate callback, void *ptr) +void device_scheduler::perfect_quantum(const attotime &duration) { - return &m_timer_allocator.alloc()->init(machine(), callback, ptr, false); + add_quantum(attotime::zero, duration); } //------------------------------------------------- -// timer_set - allocate an anonymous non-device -// timer and set it to go off after the given -// amount of time +// timer_alloc - allocate a global non-device +// timer and return a pointer //------------------------------------------------- -void device_scheduler::timer_set(const attotime &duration, timer_expired_delegate callback, int param, void *ptr) +emu_timer *device_scheduler::timer_alloc(timer_expired_delegate callback) { - m_timer_allocator.alloc()->init(machine(), callback, ptr, true).adjust(duration, param); + return &m_timer_allocator.alloc()->init(machine(), std::move(callback), attotime::never, 0, false); } //------------------------------------------------- -// timer_alloc - allocate a global device timer -// and return a pointer +// timer_set - allocate an anonymous non-device +// timer and set it to go off after the given +// amount of time //------------------------------------------------- -emu_timer *device_scheduler::timer_alloc(device_t &device, device_timer_id id, void *ptr) +void device_scheduler::timer_set(const attotime &duration, timer_expired_delegate callback, s32 param) { - return &m_timer_allocator.alloc()->init(device, id, ptr, false); + [[maybe_unused]] emu_timer &timer = m_timer_allocator.alloc()->init( + machine(), + std::move(callback), + duration, + param, + true); + assert(!timer.m_expire.is_never()); // this is not handled } //------------------------------------------------- -// timer_set - allocate an anonymous device timer -// and set it to go off after the given amount of -// time +// synchronize - allocate an anonymous non-device +// timer and set it to go off as soon as possible //------------------------------------------------- -void device_scheduler::timer_set(const attotime &duration, device_t &device, device_timer_id id, int param, void *ptr) +void device_scheduler::synchronize(timer_expired_delegate callback, s32 param) { - m_timer_allocator.alloc()->init(device, id, ptr, true).adjust(duration, param); + m_timer_allocator.alloc()->init( + machine(), + std::move(callback), + attotime::zero, + param, + true); } @@ -655,7 +658,7 @@ void device_scheduler::eat_all_cycles() // given amount of time //------------------------------------------------- -void device_scheduler::timed_trigger(void *ptr, s32 param) +void device_scheduler::timed_trigger(s32 param) { trigger(param); } @@ -682,24 +685,47 @@ void device_scheduler::presave() void device_scheduler::postload() { // remove all timers and make a private list of permanent ones - simple_list<emu_timer> private_list; - while (m_timer_list != nullptr) + emu_timer *private_list = nullptr; + while (m_inactive_timers) + { + emu_timer &timer = *m_inactive_timers; + assert(!timer.m_temporary); + + timer_list_remove(timer).m_next = private_list; + private_list = &timer; + } + while (m_timer_list->m_next) { emu_timer &timer = *m_timer_list; - // temporary timers go away entirely (except our special never-expiring one) - if (timer.m_temporary && !timer.expire().is_never()) - m_timer_allocator.reclaim(timer.release()); + if (timer.m_temporary) + { + assert(!timer.expire().is_never()); - // permanent ones get added to our private list + // temporary timers go away entirely (except our special never-expiring one) + timer.m_callback.reset(); + m_timer_allocator.reclaim(timer_list_remove(timer)); + } else - private_list.append(timer_list_remove(timer)); + { + // permanent ones get added to our private list + timer_list_remove(timer).m_next = private_list; + private_list = &timer; + } } + // special dummy timer + assert(!m_timer_list->m_enabled); + assert(m_timer_list->m_temporary); + assert(m_timer_list->m_expire.is_never()); + // now re-insert them; this effectively re-sorts them by time - emu_timer *timer; - while ((timer = private_list.detach_head()) != nullptr) - timer_list_insert(*timer); + while (private_list) + { + emu_timer &timer = *private_list; + private_list = timer.m_next; + timer_list_insert(timer); + } m_suspend_changes_pending = true; rebuild_execute_list(); @@ -775,7 +801,7 @@ void device_scheduler::rebuild_execute_list() min_quantum = (std::min)(attotime(0, exec->minimum_quantum()), min_quantum); // inform the timer system of our decision - add_scheduling_quantum(min_quantum, attotime::never); + add_quantum(min_quantum, attotime::never); } // start with an empty list @@ -815,38 +841,50 @@ void device_scheduler::rebuild_execute_list() inline emu_timer &device_scheduler::timer_list_insert(emu_timer &timer) { - // disabled timers sort to the end - const attotime expire = timer.m_enabled ? timer.m_expire : attotime::never; - - // loop over the timer list - emu_timer *prevtimer = nullptr; - for (emu_timer *curtimer = m_timer_list; curtimer != nullptr; prevtimer = curtimer, curtimer = curtimer->next()) + // disabled timers never expire + if (!timer.m_expire.is_never() && timer.m_enabled) { - // if the current list entry expires after us, we should be inserted before it - if (curtimer->m_expire > expire) + // loop over the timer list + emu_timer *prevtimer = nullptr; + for (emu_timer *curtimer = m_timer_list; curtimer; prevtimer = curtimer, curtimer = curtimer->m_next) { - // link the new guy in before the current list entry - timer.m_prev = prevtimer; - timer.m_next = curtimer; + // if the current list entry expires after us, we should be inserted before it + if (curtimer->m_expire > timer.m_expire) + { + // link the new guy in before the current list entry + timer.m_prev = prevtimer; + timer.m_next = curtimer; - if (prevtimer != nullptr) - prevtimer->m_next = &timer; - else - m_timer_list = &timer; + if (prevtimer) + prevtimer->m_next = &timer; + else + m_timer_list = &timer; - curtimer->m_prev = &timer; - return timer; + curtimer->m_prev = &timer; + return timer; + } } - } - // need to insert after the last one - if (prevtimer != nullptr) - prevtimer->m_next = &timer; + // need to insert after the last one + if (prevtimer) + prevtimer->m_next = &timer; + else + m_timer_list = &timer; + + timer.m_prev = prevtimer; + timer.m_next = nullptr; + } else - m_timer_list = &timer; + { + // keep inactive timers in a separate list + if (m_inactive_timers) + m_inactive_timers->m_prev = &timer; + + timer.m_next = m_inactive_timers; + timer.m_prev = nullptr; - timer.m_prev = prevtimer; - timer.m_next = nullptr; + m_inactive_timers = &timer; + } return timer; } @@ -859,12 +897,21 @@ inline emu_timer &device_scheduler::timer_list_insert(emu_timer &timer) inline emu_timer &device_scheduler::timer_list_remove(emu_timer &timer) { // remove it from the list - if (timer.m_prev != nullptr) + if (timer.m_prev) + { timer.m_prev->m_next = timer.m_next; - else + } + else if (&timer == m_timer_list) + { m_timer_list = timer.m_next; + } + else + { + assert(&timer == m_inactive_timers); + m_inactive_timers = timer.m_next; + } - if (timer.m_next != nullptr) + if (timer.m_next) timer.m_next->m_prev = timer.m_prev; return timer; @@ -896,30 +943,29 @@ inline void device_scheduler::execute_timers() // call the callback if (was_enabled) { - g_profiler.start(PROFILER_TIMER_CALLBACK); + auto profile = g_profiler.start(PROFILER_TIMER_CALLBACK); if (!timer.m_callback.isnull()) { - if (timer.m_device != nullptr) - LOG("execute_timers: timer device %s timer %d\n", timer.m_device->tag(), timer.m_id); - else - LOG("execute_timers: timer callback %s\n", timer.m_callback.name()); - timer.m_callback(timer.m_ptr, timer.m_param); + LOG("execute_timers: timer callback %s\n", timer.m_callback.name()); + timer.m_callback(timer.m_param); } - - g_profiler.stop(); } // reset or remove the timer, but only if it wasn't modified during the callback if (!m_callback_timer_modified) { - // if the timer is temporary, remove it now - if (timer.m_temporary) - m_timer_allocator.reclaim(timer.release()); - - // otherwise, reschedule it - else + if (!timer.m_temporary) + { + // if the timer is not temporary, reschedule it timer.schedule_next_period(); + } + else + { + // otherwise, remove it now + timer.m_callback.reset(); + m_timer_allocator.reclaim(timer_list_remove(timer)); + } } } @@ -929,51 +975,6 @@ inline void device_scheduler::execute_timers() //------------------------------------------------- -// add_scheduling_quantum - add a scheduling -// quantum; the smallest active one is the one -// that is in use -//------------------------------------------------- - -void device_scheduler::add_scheduling_quantum(const attotime &quantum, const attotime &duration) -{ - assert(quantum.seconds() == 0); - - attotime curtime = time(); - attotime expire = curtime + duration; - const attoseconds_t quantum_attos = quantum.attoseconds(); - - // figure out where to insert ourselves, expiring any quanta that are out-of-date - quantum_slot *insert_after = nullptr; - quantum_slot *next; - for (quantum_slot *quant = m_quantum_list.first(); quant != nullptr; quant = next) - { - // if this quantum is expired, nuke it - next = quant->next(); - if (curtime >= quant->m_expire) - m_quantum_allocator.reclaim(m_quantum_list.detach(*quant)); - - // if this quantum is shorter than us, we need to be inserted afterwards - else if (quant->m_requested <= quantum_attos) - insert_after = quant; - } - - // if we found an exact match, just take the maximum expiry time - if (insert_after != nullptr && insert_after->m_requested == quantum_attos) - insert_after->m_expire = std::max(insert_after->m_expire, expire); - - // otherwise, allocate a new quantum and insert it after the one we picked - else - { - quantum_slot &quant = *m_quantum_allocator.alloc(); - quant.m_requested = quantum_attos; - quant.m_actual = std::max(quantum_attos, m_quantum_minimum); - quant.m_expire = expire; - m_quantum_list.insert_after(quant, insert_after); - } -} - - -//------------------------------------------------- // dump_timers - dump the current timer state //------------------------------------------------- @@ -981,7 +982,9 @@ void device_scheduler::dump_timers() const { machine().logerror("=============================================\n"); machine().logerror("Timer Dump: Time = %15s\n", time().as_string(PRECISION)); - for (emu_timer *timer = first_timer(); timer != nullptr; timer = timer->next()) + for (emu_timer *timer = m_timer_list; timer; timer = timer->m_next) + timer->dump(); + for (emu_timer *timer = m_inactive_timers; timer; timer = timer->m_next) timer->dump(); machine().logerror("=============================================\n"); } diff --git a/src/emu/schedule.h b/src/emu/schedule.h index 9e90ed68ed5..e13fc18d573 100644 --- a/src/emu/schedule.h +++ b/src/emu/schedule.h @@ -22,7 +22,7 @@ // MACROS //************************************************************************** -#define TIMER_CALLBACK_MEMBER(name) void name(void *ptr, s32 param) +#define TIMER_CALLBACK_MEMBER(name) void name(s32 param) //************************************************************************** @@ -30,70 +30,65 @@ //************************************************************************** // timer callbacks look like this -typedef named_delegate<void (void *, s32)> timer_expired_delegate; +typedef named_delegate<void (s32)> timer_expired_delegate; // ======================> emu_timer class emu_timer { - friend class device_scheduler; - friend class simple_list<emu_timer>; - friend class fixed_allocator<emu_timer>; - - // construction/destruction - emu_timer(); - ~emu_timer(); - - // allocation and re-use - emu_timer &init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary); - emu_timer &init(device_t &device, device_timer_id id, void *ptr, bool temporary); - emu_timer &release(); - public: // getters - emu_timer *next() const { return m_next; } - running_machine &machine() const noexcept { assert(m_machine != nullptr); return *m_machine; } - bool enabled() const { return m_enabled; } - int param() const { return m_param; } - void *ptr() const { return m_ptr; } + bool enabled() const noexcept { return m_enabled; } + s32 param() const noexcept { return m_param; } // setters - bool enable(bool enable = true); - void set_param(int param) { m_param = param; } - void set_ptr(void *ptr) { m_ptr = ptr; } + bool enable(bool enable = true) noexcept; + void set_param(s32 param) noexcept { m_param = param; } // control - void reset(const attotime &duration = attotime::never) { adjust(duration, m_param, m_period); } - void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never); + void reset(const attotime &duration = attotime::never) noexcept { adjust(duration, m_param, m_period); } + void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never) noexcept; // timing queries attotime elapsed() const noexcept; attotime remaining() const noexcept; - attotime start() const { return m_start; } - attotime expire() const { return m_expire; } - attotime period() const { return m_period; } + attotime start() const noexcept { return m_start; } + attotime expire() const noexcept { return m_expire; } + attotime period() const noexcept { return m_period; } private: + // construction/destruction + emu_timer() noexcept; + ~emu_timer(); + + // allocation and re-use + emu_timer &init( + running_machine &machine, + timer_expired_delegate &&callback, + attotime start_delay, + s32 param, + bool temporary); + // internal helpers - void register_save(); - void schedule_next_period(); + void register_save(save_manager &manager) ATTR_COLD; + void schedule_next_period() noexcept; void dump() const; - static void device_timer_expired(emu_timer &timer, void *ptr, s32 param); // internal state - running_machine * m_machine; // reference to the owning machine + device_scheduler * m_scheduler; // reference to the owning machine emu_timer * m_next; // next timer in order in the list emu_timer * m_prev; // previous timer in order in the list timer_expired_delegate m_callback; // callback function s32 m_param; // integer parameter - void * m_ptr; // pointer parameter bool m_enabled; // is the timer enabled? bool m_temporary; // is the timer temporary? attotime m_period; // the repeat frequency of the timer attotime m_start; // time when the timer was started attotime m_expire; // time when the timer will expire - device_t * m_device; // for device timers, a pointer to the device - device_timer_id m_id; // for device timers, the ID of the timer + + friend class device_scheduler; + friend class fixed_allocator<emu_timer>; + friend class simple_list<emu_timer>; // FIXME: fixed_allocator requires this }; @@ -112,25 +107,23 @@ public: // getters running_machine &machine() const noexcept { return m_machine; } attotime time() const noexcept; - emu_timer *first_timer() const { return m_timer_list; } + emu_timer *first_timer() const noexcept { return m_timer_list; } device_execute_interface *currently_executing() const noexcept { return m_executing_device; } bool can_save() const; // execution void timeslice(); - void abort_timeslice(); + void abort_timeslice() noexcept; void trigger(int trigid, const attotime &after = attotime::zero); - void boost_interleave(const attotime ×lice_time, const attotime &boost_duration); + void add_quantum(const attotime &quantum, const attotime &duration); + void perfect_quantum(const attotime &duration); void suspend_resume_changed() { m_suspend_changes_pending = true; } // timers, specified by callback/name - emu_timer *timer_alloc(timer_expired_delegate callback, void *ptr = nullptr); - void timer_set(const attotime &duration, timer_expired_delegate callback, int param = 0, void *ptr = nullptr); - void synchronize(timer_expired_delegate callback = timer_expired_delegate(), int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, callback, param, ptr); } - - // timers, specified by device/id; generally devices should use the device_t methods instead - emu_timer *timer_alloc(device_t &device, device_timer_id id = 0, void *ptr = nullptr); - void timer_set(const attotime &duration, device_t &device, device_timer_id id = 0, int param = 0, void *ptr = nullptr); + emu_timer *timer_alloc(timer_expired_delegate callback); + [[deprecated("timer_set is deprecated; please avoid anonymous timers. Use an allocated emu_timer instead.")]] + void timer_set(const attotime &duration, timer_expired_delegate callback, s32 param = 0); + void synchronize(timer_expired_delegate callback = timer_expired_delegate(), s32 param = 0); // debugging void dump_timers() const; @@ -140,7 +133,7 @@ public: private: // callbacks - void timed_trigger(void *ptr, s32 param); + void timed_trigger(s32 param); void presave(); void postload(); @@ -148,7 +141,6 @@ private: void compute_perfect_interleave(); void rebuild_execute_list(); void apply_suspend_changes(); - void add_scheduling_quantum(const attotime &quantum, const attotime &duration); // timer helpers emu_timer &timer_list_insert(emu_timer &timer); @@ -163,6 +155,7 @@ private: // list of active timers emu_timer * m_timer_list; // head of the active list + emu_timer * m_inactive_timers; // head of the inactive timer list fixed_allocator<emu_timer> m_timer_allocator; // allocator for timers // other internal states diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index 5a9c055bbbb..cf311fb21eb 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -12,6 +12,8 @@ #include "screen.h" #include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "render.h" #include "rendutil.h" @@ -554,7 +556,7 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev , m_curtexture(0) , m_changed(true) , m_last_partial_scan(0) - , m_partial_scan_hpos(-1) + , m_partial_scan_hpos(0) , m_color(rgb_t(0xff, 0xff, 0xff, 0xff)) , m_brightness(0xff) , m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds()) @@ -683,9 +685,9 @@ void screen_device::device_validity_check(validity_checker &valid) const osd_printf_error("Non-raster display cannot have a variable width\n"); } - // check for zero frame rate - if (m_refresh == 0) - osd_printf_error("Invalid (zero) refresh rate\n"); + // check for invalid frame rate + if (m_refresh == 0 || m_refresh > ATTOSECONDS_PER_SECOND) + osd_printf_error("Invalid (under 1Hz) refresh rate\n"); texture_format texformat = !m_screen_update_ind16.isnull() ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32; if (m_palette.finder_tag() != finder_base::DUMMY_TAG) @@ -770,8 +772,6 @@ void screen_device::device_resolve_objects() // bind our handlers m_screen_update_ind16.resolve(); m_screen_update_rgb32.resolve(); - m_screen_vblank.resolve_safe(); - m_scanline_cb.resolve(); // assign our format to the palette before it starts if (m_palette) @@ -834,15 +834,15 @@ void screen_device::device_start() m_container->set_user_settings(settings); // allocate the VBLANK timers - m_vblank_begin_timer = timer_alloc(TID_VBLANK_START); - m_vblank_end_timer = timer_alloc(TID_VBLANK_END); + m_vblank_begin_timer = timer_alloc(FUNC(screen_device::vblank_begin), this); + m_vblank_end_timer = timer_alloc(FUNC(screen_device::vblank_end), this); // allocate a timer to reset partial updates - m_scanline0_timer = timer_alloc(TID_SCANLINE0); + m_scanline0_timer = timer_alloc(FUNC(screen_device::first_scanline_tick), this); // allocate a timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) - m_scanline_timer = timer_alloc(TID_SCANLINE); + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) + m_scanline_timer = timer_alloc(FUNC(screen_device::scanline_tick), this); // configure the screen with the default parameters configure(m_width, m_height, m_visarea, m_refresh); @@ -852,7 +852,7 @@ void screen_device::device_start() m_vblank_end_time = attotime(0, m_vblank_period); // start the timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) m_scanline_timer->adjust(time_until_pos(0)); // create burn-in bitmap @@ -887,7 +887,7 @@ void screen_device::device_start() save_item(NAME(m_vblank_end_time)); save_item(NAME(m_frame_number)); if (m_oldstyle_vblank_supplied) - logerror("%s: Deprecated legacy Old Style screen configured (MCFG_SCREEN_VBLANK_TIME), please use MCFG_SCREEN_RAW_PARAMS instead.\n",this->tag()); + logerror("%s: Deprecated legacy Old Style screen configured (set_vblank_time), please use set_raw instead.\n",this->tag()); m_is_primary_screen = (this == screen_device_enumerator(machine().root_device()).first()); } @@ -930,54 +930,39 @@ void screen_device::device_post_load() //------------------------------------------------- -// device_timer - called whenever a device timer -// fires +// timer events //------------------------------------------------- -void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(screen_device::first_scanline_tick) { - switch (id) + // first scanline + reset_partial_updates(); + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - // signal VBLANK start - case TID_VBLANK_START: - vblank_begin(); - break; - - // signal VBLANK end - case TID_VBLANK_END: - vblank_end(); - break; - - // first scanline - case TID_SCANLINE0: - reset_partial_updates(); - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) - { - pre_update_scanline(0); - } - break; + pre_update_scanline(0); + } +} - // subsequent scanlines when scanline updates are enabled - case TID_SCANLINE: - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) - { - pre_update_scanline(param); - } - if (m_video_attributes & VIDEO_UPDATE_SCANLINE) - { - // force a partial update to the current scanline - update_partial(param); - } - if (m_scanline_cb) - m_scanline_cb(param); - - // compute the next visible scanline - param++; - if (param > m_visarea.bottom()) - param = m_visarea.top(); - m_scanline_timer->adjust(time_until_pos(param), param); - break; +TIMER_CALLBACK_MEMBER(screen_device::scanline_tick) +{ + // subsequent scanlines when scanline updates are enabled + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + { + pre_update_scanline(param); + } + if (m_video_attributes & VIDEO_UPDATE_SCANLINE) + { + // force a partial update to the current scanline + update_partial(param); } + if (!m_scanline_cb.isunset()) + m_scanline_cb(param); + + // compute the next visible scanline + param++; + if (param > m_visarea.bottom()) + param = m_visarea.top(); + m_scanline_timer->adjust(time_until_pos(param), param); } @@ -1026,7 +1011,7 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a // call the VBLANK start timer now; otherwise, adjust it for the future attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds(); if (delta >= m_frame_period) - vblank_begin(); + vblank_begin(0); else m_vblank_begin_timer->adjust(time_until_vblank_start()); @@ -1064,7 +1049,7 @@ void screen_device::reset_origin(int beamy, int beamx) // if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start, // call the VBLANK start timer now; otherwise, adjust it for the future if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0) - vblank_begin(); + vblank_begin(0); else m_vblank_begin_timer->adjust(time_until_vblank_start()); } @@ -1196,55 +1181,56 @@ bool screen_device::update_partial(int scanline) // otherwise, render LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom())); - g_profiler.start(PROFILER_VIDEO); u32 flags = 0; - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - rectangle scan_clip(clip); - for (int y = clip.top(); y <= clip.bottom(); y++) + auto profile = g_profiler.start(PROFILER_VIDEO); + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - scan_clip.sety(y, y); - pre_update_scanline(y); - - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) + rectangle scan_clip(clip); + for (int y = clip.top(); y <= clip.bottom(); y++) { - default: - case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - } + scan_clip.sety(y, y); + pre_update_scanline(y); - m_partial_updates_this_frame++; - } - } - else - { - if (m_type != SCREEN_TYPE_SVG) - { - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; + case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; + } + + m_partial_updates_this_frame++; } } else { - flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + if (m_type != SCREEN_TYPE_SVG) + { + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } + } + else + { + flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + } + m_partial_updates_this_frame++; } - m_partial_updates_this_frame++; + // stop profiling } - g_profiler.stop(); - // if we modified the bitmap, we have to commit m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; // remember where we left off m_last_partial_scan = scanline + 1; - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; return true; } @@ -1298,10 +1284,10 @@ void screen_device::update_now() if (current_vpos > m_last_partial_scan) { // if the line before us was incomplete, we must do it in two pieces - if (m_partial_scan_hpos >= 0) + if (m_partial_scan_hpos > 0) { // now finish the previous partial scanline - clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), + clip.set((std::max)(clip.left(), m_partial_scan_hpos), clip.right(), (std::max)(clip.top(), m_last_partial_scan), (std::min)(clip.bottom(), m_last_partial_scan)); @@ -1309,7 +1295,7 @@ void screen_device::update_now() // if there's something to draw, do it if (!clip.empty()) { - g_profiler.start(PROFILER_VIDEO); + auto profile = g_profiler.start(PROFILER_VIDEO); u32 flags = 0; screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; @@ -1333,14 +1319,13 @@ void screen_device::update_now() } } - g_profiler.stop(); m_partial_updates_this_frame++; // if we modified the bitmap, we have to commit m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; } - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; m_last_partial_scan++; } if (current_vpos > m_last_partial_scan) @@ -1350,47 +1335,49 @@ void screen_device::update_now() } // now draw this partial scanline - clip = m_visarea; - - clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), - (std::min)(clip.right(), current_hpos), - (std::max)(clip.top(), current_vpos), - (std::min)(clip.bottom(), current_vpos)); - - // and if there's something to draw, do it - if (!clip.empty()) + if (current_hpos > 0) { - g_profiler.start(PROFILER_VIDEO); + clip = m_visarea; - LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right())); + clip.set((std::max)(clip.left(), m_partial_scan_hpos), + (std::min)(clip.right(), current_hpos - 1), + (std::max)(clip.top(), current_vpos), + (std::min)(clip.bottom(), current_vpos)); - u32 flags = 0; - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + // and if there's something to draw, do it + if (!clip.empty()) { - pre_update_scanline(current_vpos); - switch (curbitmap.format()) + auto profile = g_profiler.start(PROFILER_VIDEO); + + LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right())); + + u32 flags = 0; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + pre_update_scanline(current_vpos); + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + } } - } - else - { - switch (curbitmap.format()) + else { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } } - } - m_partial_updates_this_frame++; - g_profiler.stop(); + m_partial_updates_this_frame++; - // if we modified the bitmap, we have to commit - m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; + // if we modified the bitmap, we have to commit + m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; + } } // remember where we left off @@ -1407,7 +1394,7 @@ void screen_device::update_now() void screen_device::reset_partial_updates() { m_last_partial_scan = 0; - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; m_partial_updates_this_frame = 0; m_scanline0_timer->adjust(time_until_pos(0)); } @@ -1646,7 +1633,7 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap) // signal the VBLANK period has begun //------------------------------------------------- -void screen_device::vblank_begin() +TIMER_CALLBACK_MEMBER(screen_device::vblank_begin) { // reset the starting VBLANK time m_vblank_start_time = machine().time(); @@ -1666,7 +1653,7 @@ void screen_device::vblank_begin() // if no VBLANK period, call the VBLANK end callback immediately, otherwise reset the timer if (m_vblank_period == 0) - vblank_end(); + vblank_end(0); else m_vblank_end_timer->adjust(time_until_vblank_end()); } @@ -1677,7 +1664,7 @@ void screen_device::vblank_begin() // signal the VBLANK period has ended //------------------------------------------------- -void screen_device::vblank_end() +TIMER_CALLBACK_MEMBER(screen_device::vblank_end) { // call the screen specific callbacks for (auto &item : m_callback_list) diff --git a/src/emu/screen.h b/src/emu/screen.h index b909c25cecc..a2d9e7f7f2e 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -13,6 +13,8 @@ #pragma once +#include "rendertypes.h" + #include <type_traits> #include <utility> @@ -31,16 +33,6 @@ enum screen_type_enum SCREEN_TYPE_SVG }; -// texture formats -enum texture_format -{ - TEXFORMAT_UNDEFINED = 0, // require a format to be specified - TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha - TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB - TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB - TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence -}; - // screen_update callback flags constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed @@ -233,7 +225,7 @@ public: screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart) { assert(pixclock != 0); - m_clock = pixclock; + set_clock(pixclock); m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal; m_vblank = m_refresh / vtotal * (vtotal - (vbstart - vbend)); m_width = htotal; @@ -246,6 +238,10 @@ public: xtal.validate(std::string("Configuring screen ") + tag()); return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart); } + screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea) + { + return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1); + } void set_refresh(attoseconds_t rate) { m_refresh = rate; } /// \brief Set refresh rate in Hertz @@ -389,8 +385,8 @@ public: // beam positioning and state int vpos() const; int hpos() const; - DECLARE_READ_LINE_MEMBER(vblank) const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } - DECLARE_READ_LINE_MEMBER(hblank) const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } + int vblank() const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } + int hblank() const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } // timing attotime time_until_pos(int vpos, int hpos = 0) const; @@ -428,15 +424,6 @@ public: private: class svg_renderer; - // timer IDs - enum - { - TID_VBLANK_START, - TID_VBLANK_END, - TID_SCANLINE0, - TID_SCANLINE - }; - // device-level overrides virtual void device_validity_check(validity_checker &valid) const override; virtual void device_config_complete() override; @@ -445,13 +432,14 @@ private: virtual void device_reset() override; virtual void device_stop() override; virtual void device_post_load() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; // internal helpers void set_container(render_container &container) { m_container = &container; } void realloc_screen_bitmaps(); - void vblank_begin(); - void vblank_end(); + TIMER_CALLBACK_MEMBER(vblank_begin); + TIMER_CALLBACK_MEMBER(vblank_end); + TIMER_CALLBACK_MEMBER(first_scanline_tick); + TIMER_CALLBACK_MEMBER(scanline_tick); void finalize_burnin(); void load_effect_overlay(const char *filename); void update_scan_bitmap_size(int y); diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp index 4892a5ca5d8..c6bb7161be3 100644 --- a/src/emu/softlist.cpp +++ b/src/emu/softlist.cpp @@ -286,8 +286,7 @@ softlist_parser::softlist_parser( char buffer[1024]; for (bool done = false; !done; ) { - size_t length; - file.read(buffer, sizeof(buffer), length); // TODO: better error handling + auto const [err, length] = read(file, buffer, sizeof(buffer)); // TODO: better error handling if (!length) done = true; if (XML_Parse(m_parser, buffer, length, done) == XML_STATUS_ERROR) diff --git a/src/emu/softlist_dev.cpp b/src/emu/softlist_dev.cpp index 7d25dd17013..b65f5f28300 100644 --- a/src/emu/softlist_dev.cpp +++ b/src/emu/softlist_dev.cpp @@ -13,6 +13,7 @@ #include "diimage.h" #include "emuopts.h" +#include "fileio.h" #include "romload.h" #include "validity.h" @@ -49,9 +50,9 @@ image_software_list_loader image_software_list_loader::s_instance; // false_software_list_loader::load_software //------------------------------------------------- -bool false_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const +std::error_condition false_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const { - return false; + return image_error::UNSUPPORTED; } @@ -59,10 +60,10 @@ bool false_software_list_loader::load_software(device_image_interface &image, so // rom_software_list_loader::load_software //------------------------------------------------- -bool rom_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const +std::error_condition rom_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const { swlist.machine().rom_load().load_software_part_region(image.device(), swlist, swname, start_entry); - return true; + return std::error_condition(); } @@ -70,7 +71,7 @@ bool rom_software_list_loader::load_software(device_image_interface &image, soft // image_software_list_loader::load_software //------------------------------------------------- -bool image_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const +std::error_condition image_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const { return image.load_software(swlist, swname, start_entry); } @@ -249,7 +250,7 @@ void software_list_device::display_matches(const machine_config &config, const c // from an intermediate point //------------------------------------------------- -const software_info *software_list_device::find(const std::string &look_for) +const software_info *software_list_device::find(std::string_view look_for) { // empty search returns nothing if (look_for.empty()) @@ -264,9 +265,9 @@ const software_info *software_list_device::find(const std::string &look_for) info_list.end(), [&look_for, iswild] (const software_info &info) { - const char *shortname = info.shortname().c_str(); - return (iswild && core_strwildcmp(look_for.c_str(), shortname) == 0) - || core_stricmp(look_for.c_str(), shortname) == 0; + std::string_view shortname = info.shortname(); + return (iswild && core_strwildcmp(look_for, shortname) == 0) + || util::streqlower(look_for, shortname); }); return iter != info_list.end() ? &*iter : nullptr; @@ -453,6 +454,9 @@ void software_list_device::internal_validity_check(validity_checker &valid) if (m_shortname.length() > NAME_LEN_LIST) osd_printf_error("%s: %s software list name must be %d characters or less\n", m_filename, m_shortname, NAME_LEN_LIST); + + if (std::find_if_not(m_shortname.begin(), m_shortname.end(), valid_name_char) != m_shortname.end()) + osd_printf_error("%s: %s software list name contains invalid characters\n", m_filename, m_shortname); } // now check the software items @@ -572,6 +576,8 @@ void software_list_device::internal_validity_check(validity_checker &valid) current_length = ROMREGION_GETLENGTH(romp); if (!data_area_map.emplace(romp->name(), current_length).second) osd_printf_error("%s: %s part %s data area has duplicate name '%s'\n", m_filename, shortname, part.name(), romp->name()); + if (current_length == 0) + osd_printf_error("%s: %s part %s data area '%s' has zero length\n", m_filename, shortname, part.name(), romp->name()); } else if (ROMENTRY_ISFILE(romp)) // if this is a file, make sure it is properly formatted { diff --git a/src/emu/softlist_dev.h b/src/emu/softlist_dev.h index e0e912a67f1..772bb970c99 100644 --- a/src/emu/softlist_dev.h +++ b/src/emu/softlist_dev.h @@ -43,7 +43,7 @@ enum software_compatibility class software_list_loader { public: - virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const = 0; + virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const = 0; }; @@ -52,7 +52,7 @@ public: class false_software_list_loader : public software_list_loader { public: - virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; + virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; static const software_list_loader &instance() { return s_instance; } private: @@ -65,7 +65,7 @@ private: class rom_software_list_loader : public software_list_loader { public: - virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; + virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; static const software_list_loader &instance() { return s_instance; } private: @@ -78,7 +78,7 @@ private: class image_software_list_loader : public software_list_loader { public: - virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; + virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override; static const software_list_loader &instance() { return s_instance; } private: @@ -121,7 +121,7 @@ public: const std::list<software_info> &get_info() { if (!m_parsed) parse(); return m_infolist; } // operations - const software_info *find(const std::string &look_for); + const software_info *find(std::string_view look_for); void find_approx_matches(std::string_view name, int matches, const software_info **list, const char *interface); void release(); software_compatibility is_compatible(const software_part &part) const; diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp index 56b7d7ef071..c9626855197 100644 --- a/src/emu/sound.cpp +++ b/src/emu/sound.cpp @@ -9,32 +9,30 @@ ***************************************************************************/ #include "emu.h" -#include "speaker.h" -#include "emuopts.h" -#include "osdepend.h" + #include "config.h" +#include "emuopts.h" +#include "main.h" +#include "speaker.h" + #include "wavwrite.h" +#include "xmlfile.h" +#include "osdepend.h" //************************************************************************** // DEBUGGING //************************************************************************** -#define VERBOSE (0) +//#define VERBOSE 1 +#define LOG_OUTPUT_FUNC osd_printf_debug -#define VPRINTF(x) do { if (VERBOSE) osd_printf_debug x; } while (0) +#include "logmacro.h" #define LOG_OUTPUT_WAV (0) - -//************************************************************************** -// CONSTANTS -//************************************************************************** - - - //************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -42,7 +40,6 @@ const attotime sound_manager::STREAMS_UPDATE_ATTOTIME = attotime::from_hz(STREAMS_UPDATE_FREQUENCY); - //************************************************************************** // STREAM BUFFER //************************************************************************** @@ -560,6 +557,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output m_synchronous((flags & STREAM_SYNCHRONOUS) != 0), m_resampling_disabled((flags & STREAM_DISABLE_INPUT_RESAMPLING) != 0), m_sync_timer(nullptr), + m_last_update_end_time(attotime::zero), m_input(inputs), m_input_view(inputs), m_empty_buffer(100), @@ -578,8 +576,10 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output // create a unique tag for saving std::string state_tag = string_format("%d", m_device.machine().sound().unique_id()); auto &save = m_device.machine().save(); - save.save_item(&m_device, "stream.sample_rate", state_tag.c_str(), 0, NAME(m_sample_rate)); + save.save_item(&m_device, "stream.sound_stream", state_tag.c_str(), 0, NAME(m_sample_rate)); + save.save_item(&m_device, "stream.sound_stream", state_tag.c_str(), 0, NAME(m_last_update_end_time)); save.register_postload(save_prepost_delegate(FUNC(sound_stream::postload), this)); + save.register_presave(save_prepost_delegate(FUNC(sound_stream::presave), this)); // initialize all inputs for (unsigned int inputnum = 0; inputnum < m_input.size(); inputnum++) @@ -602,7 +602,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output // create an update timer for synchronous streams if (synchronous()) - m_sync_timer = m_device.machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sound_stream::sync_update), this)); + m_sync_timer = m_device.timer_alloc(FUNC(sound_stream::sync_update), this); // force an update to the sample rates sample_rate_changed(); @@ -648,8 +648,8 @@ void sound_stream::set_sample_rate(u32 new_rate) void sound_stream::set_input(int index, sound_stream *input_stream, int output_index, float gain) { - VPRINTF(("stream_set_input(%p, '%s', %d, %p, %d, %f)\n", (void *)this, m_device.tag(), - index, (void *)input_stream, output_index, (double) gain)); + LOG("stream_set_input(%p, '%s', %d, %p, %d, %f)\n", (void *)this, m_device.tag(), + index, (void *)input_stream, output_index, gain); // make sure it's a valid input if (index >= m_input.size()) @@ -704,7 +704,7 @@ read_stream_view sound_stream::update_view(attotime start, attotime end, u32 out if (start > end) start = end; - g_profiler.start(PROFILER_SOUND); + auto profile = g_profiler.start(PROFILER_SOUND); // reposition our start to coincide with the current buffer end attotime update_start = m_output[outputnum].end_time(); @@ -752,7 +752,6 @@ read_stream_view sound_stream::update_view(attotime start, attotime end, u32 out #endif } } - g_profiler.stop(); // return the requested view return read_stream_view(m_output_view[outputnum], start); @@ -857,14 +856,24 @@ void sound_stream::sample_rate_changed() void sound_stream::postload() { - // set the end time of all of our streams to now + // set the end time of all of our streams to the value saved in m_last_update_end_time for (auto &output : m_output) - output.set_end_time(m_device.machine().time()); + output.set_end_time(m_last_update_end_time); // recompute the sample rate information sample_rate_changed(); } +//------------------------------------------------- +// presave - save/restore callback +//------------------------------------------------- + +void sound_stream::presave() +{ + // save the stream end time + m_last_update_end_time = m_output[0].end_time(); +} + //------------------------------------------------- // reprime_sync_timer - set up the next sync @@ -885,7 +894,7 @@ void sound_stream::reprime_sync_timer() // synchronous stream //------------------------------------------------- -void sound_stream::sync_update(void *, s32) +void sound_stream::sync_update(s32) { update(); reprime_sync_timer(); @@ -1076,18 +1085,10 @@ sound_manager::sound_manager(running_machine &machine) : m_wavfile(), m_first_reset(true) { - // get filename for WAV file or AVI file if specified - const char *wavfile = machine.options().wav_write(); - const char *avifile = machine.options().avi_write(); - - // handle -nosound and lower sample rate if not recording WAV or AVI - if (m_nosound_mode && wavfile[0] == 0 && avifile[0] == 0) - machine.m_sample_rate = 11025; - // count the mixers #if VERBOSE mixer_interface_enumerator iter(machine.root_device()); - VPRINTF(("total mixers = %d\n", iter.count())); + LOG("total mixers = %d\n", iter.count()); #endif // register callbacks @@ -1366,16 +1367,44 @@ void sound_manager::config_load(config_type cfg_type, config_level cfg_level, ut if ((cfg_type != config_type::SYSTEM) || !parentnode) return; + // master volume attenuation + if (util::xml::data_node const *node = parentnode->get_child("attenuation")) + { + // treat source INI files or more specific as higher priority than CFG + // FIXME: leaky abstraction - this depends on a front-end implementation detail + if ((OPTION_PRIORITY_NORMAL + 5) > machine().options().get_entry(OPTION_VOLUME)->priority()) + set_attenuation(std::clamp(int(node->get_attribute_int("value", 0)), -32, 0)); + } + // iterate over channel nodes - for (util::xml::data_node const *channelnode = parentnode->get_child("channel"); channelnode != nullptr; channelnode = channelnode->get_next_sibling("channel")) + for (util::xml::data_node const *node = parentnode->get_child("channel"); node != nullptr; node = node->get_next_sibling("channel")) { mixer_input info; - if (indexed_mixer_input(channelnode->get_attribute_int("index", -1), info)) + if (indexed_mixer_input(node->get_attribute_int("index", -1), info)) + { + // note that this doesn't disallow out-of-range values + float value = node->get_attribute_float("value", std::nanf("")); + + if (!std::isnan(value)) + info.stream->input(info.inputnum).set_user_gain(value); + } + } + + // iterate over speaker panning nodes + for (util::xml::data_node const *node = parentnode->get_child("panning"); node != nullptr; node = node->get_next_sibling("panning")) + { + char const *const tag = node->get_attribute_string("tag", nullptr); + if (tag != nullptr) { - float defvol = channelnode->get_attribute_float("defvol", 1.0f); - float newvol = channelnode->get_attribute_float("newvol", -1000.0f); - if (newvol != -1000.0f) - info.stream->input(info.inputnum).set_user_gain(newvol / defvol); + for (speaker_device &speaker : speaker_device_enumerator(machine().root_device())) + { + if (!strcmp(tag, speaker.tag())) + { + float value = node->get_attribute_float("value", speaker.defpan()); + speaker.set_pan(value); + break; + } + } } } } @@ -1392,21 +1421,43 @@ void sound_manager::config_save(config_type cfg_type, util::xml::data_node *pare if (cfg_type != config_type::SYSTEM) return; - // iterate over mixer channels + // master volume attenuation + if (m_attenuation != machine().options().volume()) + { + if (util::xml::data_node *const node = parentnode->add_child("attenuation", nullptr)) + node->set_attribute_int("value", m_attenuation); + } + + // iterate over mixer channels for per-channel volume for (int mixernum = 0; ; mixernum++) { mixer_input info; if (!indexed_mixer_input(mixernum, info)) break; - float const newvol = info.stream->input(info.inputnum).user_gain(); - if (newvol != 1.0f) + float const value = info.stream->input(info.inputnum).user_gain(); + if (value != 1.0f) { - util::xml::data_node *const channelnode = parentnode->add_child("channel", nullptr); - if (channelnode) + util::xml::data_node *const node = parentnode->add_child("channel", nullptr); + if (node) { - channelnode->set_attribute_int("index", mixernum); - channelnode->set_attribute_float("newvol", newvol); + node->set_attribute_int("index", mixernum); + node->set_attribute_float("value", value); + } + } + } + + // iterate over speakers for panning + for (speaker_device &speaker : speaker_device_enumerator(machine().root_device())) + { + float const value = speaker.pan(); + if (value != speaker.defpan()) + { + util::xml::data_node *const node = parentnode->add_child("panning", nullptr); + if (node) + { + node->set_attribute("tag", speaker.tag()); + node->set_attribute_float("value", value); } } } @@ -1457,11 +1508,11 @@ stream_buffer::sample_t sound_manager::adjust_toward_compressor_scale(stream_buf // and send it to the OSD layer //------------------------------------------------- -void sound_manager::update(void *ptr, int param) +void sound_manager::update(s32 param) { - VPRINTF(("sound_update\n")); + LOG("sound_update\n"); - g_profiler.start(PROFILER_SOUND); + auto profile = g_profiler.start(PROFILER_SOUND); // determine the duration of this update attotime update_period = machine().time() - m_last_update; @@ -1597,6 +1648,4 @@ void sound_manager::update(void *ptr, int param) // notify that new samples have been generated emulator_info::sound_hook(); - - g_profiler.stop(); } diff --git a/src/emu/sound.h b/src/emu/sound.h index c1e66808ae6..15f6a5743a2 100644 --- a/src/emu/sound.h +++ b/src/emu/sound.h @@ -373,6 +373,7 @@ public: // safely write a sample to the buffer void put(s32 start, sample_t sample) { + sound_assert(u32(start) < samples()); m_buffer->put(index_to_buffer_index(start), sample); } @@ -399,6 +400,7 @@ public: // safely add a sample to the buffer void add(s32 start, sample_t sample) { + sound_assert(u32(start) < samples()); u32 index = index_to_buffer_index(start); m_buffer->put(index, m_buffer->get(index) + sample); } @@ -458,7 +460,6 @@ private: // given a stream starting offset, return the buffer index u32 index_to_buffer_index(s32 start) const { - sound_assert(u32(start) < samples()); u32 index = start + m_start; if (index >= m_buffer->size()) index -= m_buffer->size(); @@ -669,11 +670,14 @@ private: // handle updates after a save state load void postload(); + // handle updates before a save state load + void presave(); + // re-print the synchronization timer void reprime_sync_timer(); // timer callback for synchronous streams - void sync_update(void *, s32); + void sync_update(s32); // return a view of 0 data covering the given time period read_stream_view empty_view(attotime start, attotime end); @@ -692,6 +696,8 @@ private: bool m_resampling_disabled; // is resampling of input streams disabled? emu_timer *m_sync_timer; // update timer for synchronous streams + attotime m_last_update_end_time; // last end_time() in update + // input information std::vector<sound_stream_input> m_input; // list of streams we directly depend upon std::vector<read_stream_view> m_input_view; // array of output views for passing to the callback @@ -816,7 +822,7 @@ private: stream_buffer::sample_t adjust_toward_compressor_scale(stream_buffer::sample_t curscale, stream_buffer::sample_t prevsample, stream_buffer::sample_t rawsample); // periodic sound update, called STREAMS_UPDATE_FREQUENCY per second - void update(void *ptr = nullptr, s32 param = 0); + void update(s32 param = 0); // internal state running_machine &m_machine; // reference to the running machine diff --git a/src/emu/speaker.cpp b/src/emu/speaker.cpp index 3cbb14355a4..33b1e8d329a 100644 --- a/src/emu/speaker.cpp +++ b/src/emu/speaker.cpp @@ -37,6 +37,8 @@ speaker_device::speaker_device(const machine_config &mconfig, const char *tag, d , m_x(0.0) , m_y(0.0) , m_z(0.0) + , m_pan(0.0) + , m_defpan(0.0) , m_current_max(0) , m_samples_this_bucket(0) { @@ -53,6 +55,34 @@ speaker_device::~speaker_device() //------------------------------------------------- +// set_position - set speaker position +//------------------------------------------------- + +speaker_device &speaker_device::set_position(double x, double y, double z) +{ + // as mentioned in the header file, y and z params currently have no effect + m_x = x; + m_y = y; + m_z = z; + + // hard pan to left + if (m_x < 0.0) + set_pan(-1.0f); + + // hard pan to right + else if (m_x > 0.0) + set_pan(1.0f); + + // center (mono) + else + set_pan(0.0f); + + m_defpan = m_pan; + return *this; +} + + +//------------------------------------------------- // mix - mix in samples from the speaker's stream //------------------------------------------------- @@ -89,24 +119,29 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample // mix if sound is enabled if (!suppress) { - // if the speaker is centered, send to both left and right - if (m_x == 0) + // if the speaker is hard panned to the left, send only to the left + if (m_pan == -1.0f) for (int sample = 0; sample < expected_samples; sample++) - { - stream_buffer::sample_t cursample = view.get(sample); - leftmix[sample] += cursample; - rightmix[sample] += cursample; - } + leftmix[sample] += view.get(sample); - // if the speaker is to the left, send only to the left - else if (m_x < 0) + // if the speaker is hard panned to the right, send only to the right + else if (m_pan == 1.0f) for (int sample = 0; sample < expected_samples; sample++) - leftmix[sample] += view.get(sample); + rightmix[sample] += view.get(sample); - // if the speaker is to the right, send only to the right + // otherwise, send to both else + { + const float leftpan = (m_pan <= 0.0f) ? 1.0f : 1.0f - m_pan; + const float rightpan = (m_pan >= 0.0f) ? 1.0f : 1.0f + m_pan; + for (int sample = 0; sample < expected_samples; sample++) - rightmix[sample] += view.get(sample); + { + stream_buffer::sample_t cursample = view.get(sample); + leftmix[sample] += cursample * leftpan; + rightmix[sample] += cursample * rightpan; + } + } } } @@ -117,7 +152,6 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample void speaker_device::device_start() { - // dummy save to make device.c happy } @@ -187,4 +221,3 @@ void speaker_device::device_stop() } } } - diff --git a/src/emu/speaker.h b/src/emu/speaker.h index 54aa00603c9..3cb0794d998 100644 --- a/src/emu/speaker.h +++ b/src/emu/speaker.h @@ -53,8 +53,8 @@ public: speaker_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); virtual ~speaker_device(); - // inline configuration helpers - speaker_device &set_position(double x, double y, double z) { m_x = x; m_y = y; m_z = z; return *this; } + // configuration helpers + speaker_device &set_position(double x, double y, double z); speaker_device &front_center() { set_position( 0.0, 0.0, 1.0); return *this; } speaker_device &front_left() { set_position(-0.2, 0.0, 1.0); return *this; } speaker_device &front_floor() { set_position( 0.0, -0.5, 1.0); return *this; } @@ -71,15 +71,22 @@ public: // internally for use by the sound system void mix(stream_buffer::sample_t *leftmix, stream_buffer::sample_t *rightmix, attotime start, attotime end, int expected_samples, bool suppress); + // user panning configuration + void set_pan(float pan) { m_pan = std::clamp(pan, -1.0f, 1.0f); } + float pan() { return m_pan; } + float defpan() { return m_defpan; } + protected: // device-level overrides virtual void device_start() override ATTR_COLD; virtual void device_stop() override ATTR_COLD; - // inline configuration state + // configuration state double m_x; double m_y; double m_z; + float m_pan; + float m_defpan; // internal state static constexpr int BUCKETS_PER_SECOND = 10; diff --git a/src/emu/tilemap.cpp b/src/emu/tilemap.cpp index 5757f35341f..1aa18eef168 100644 --- a/src/emu/tilemap.cpp +++ b/src/emu/tilemap.cpp @@ -772,7 +772,7 @@ void tilemap_t::pixmap_update() if (m_all_tiles_clean) return; -g_profiler.start(PROFILER_TILEMAP_DRAW); + auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW); // flush the dirty state to all tiles as appropriate realize_all_dirty_tiles(); @@ -786,8 +786,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW); // mark it all clean m_all_tiles_clean = true; - -g_profiler.stop(); } @@ -797,7 +795,7 @@ g_profiler.stop(); void tilemap_t::tile_update(logical_index logindex, u32 col, u32 row) { -g_profiler.start(PROFILER_TILEMAP_UPDATE); + auto profile = g_profiler.start(PROFILER_TILEMAP_UPDATE); // call the get info callback for the associated memory index tilemap_memory_index memindex = m_logical_to_memory[logindex]; @@ -822,8 +820,6 @@ g_profiler.start(PROFILER_TILEMAP_UPDATE); m_gfx_used |= 1 << m_tileinfo.gfxnum; m_gfx_dirtyseq[m_tileinfo.gfxnum] = m_tileinfo.decoder->gfx(m_tileinfo.gfxnum)->dirtyseq(); } - -g_profiler.stop(); } @@ -997,7 +993,8 @@ void tilemap_t::draw_common(screen_device &screen, _BitmapClass &dest, const rec if (!m_enable) return; -g_profiler.start(PROFILER_TILEMAP_DRAW); + auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW); + // configure the blit parameters based on the input parameters blit_parameters blit; configure_blit_parameters(blit, screen.priority(), cliprect, flags, priority, priority_mask); @@ -1095,7 +1092,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW); } } } -g_profiler.stop(); } void tilemap_t::draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, u32 flags, u8 priority, u8 priority_mask) @@ -1134,7 +1130,8 @@ void tilemap_t::draw_roz_common(screen_device &screen, _BitmapClass &dest, const return; } -g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); + auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); + // configure the blit parameters blit_parameters blit; configure_blit_parameters(blit, screen.priority(), cliprect, flags, priority, priority_mask); @@ -1146,7 +1143,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); // then do the roz copy draw_roz_core(screen, dest, blit, startx, starty, incxx, incxy, incyx, incyy, wraparound); -g_profiler.stop(); } void tilemap_t::draw_roz(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, @@ -1182,7 +1178,16 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b // look up priority and destination base addresses for y1 bitmap_ind8 &priority_bitmap = *blit.priority; - u8 *priority_baseaddr = &priority_bitmap.pix(y1, xpos); + u8 *priority_baseaddr = nullptr; + int prio_rowpixels = 0; + if (priority_bitmap.valid()) + { + prio_rowpixels = priority_bitmap.rowpixels(); + priority_baseaddr = &priority_bitmap.pix(y1, xpos); + } + else + assert((blit.tilemap_priority_code & 0xffff) == 0xff00); + typename _BitmapClass::pixel_t *dest_baseaddr = nullptr; int dest_rowpixels = 0; if (dest.valid()) @@ -1260,7 +1265,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b { const u16 *source0 = source_baseaddr + x_start; typename _BitmapClass::pixel_t *dest0 = dest_baseaddr + x_start; - u8 *pmap0 = priority_baseaddr + x_start; + u8 *pmap0 = priority_baseaddr ? (priority_baseaddr + x_start) : nullptr; // if we were opaque, use the opaque renderer if (prev_trans == WHOLLY_OPAQUE) @@ -1278,7 +1283,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b dest0 += dest_rowpixels; source0 += m_pixmap.rowpixels(); - pmap0 += priority_bitmap.rowpixels(); + pmap0 += prio_rowpixels; } } @@ -1300,7 +1305,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b dest0 += dest_rowpixels; source0 += m_pixmap.rowpixels(); mask0 += m_flagsmap.rowpixels(); - pmap0 += priority_bitmap.rowpixels(); + pmap0 += prio_rowpixels; } } } @@ -1315,7 +1320,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b break; // advance to the next row on all our bitmaps - priority_baseaddr += priority_bitmap.rowpixels() * (nexty - y); + priority_baseaddr += prio_rowpixels * (nexty - y); source_baseaddr += m_pixmap.rowpixels() * (nexty - y); mask_baseaddr += m_flagsmap.rowpixels() * (nexty - y); dest_baseaddr += dest_rowpixels * (nexty - y); @@ -1559,10 +1564,14 @@ void tilemap_t::get_info_debug(u32 col, u32 row, u8 &gfxnum, u32 &code, u32 &col // get the GFX number and code gfxnum = m_tileinfo.gfxnum; code = m_tileinfo.code; + color = m_tileinfo.palette_base; - // work back from the palette base to get the color - const gfx_element &gfx = *m_tileinfo.decoder->gfx(gfxnum); - color = (m_tileinfo.palette_base - gfx.colorbase()) / gfx.granularity(); + if (gfxnum != 0xff) + { + // work back from the palette base to get the color + const gfx_element &gfx = *m_tileinfo.decoder->gfx(gfxnum); + color = (color - gfx.colorbase()) / gfx.granularity(); + } } @@ -1604,8 +1613,7 @@ tilemap_manager::~tilemap_manager() //------------------------------------------------- -// set_flip_all - set a global flip for all the -// tilemaps +// create - allocate a tilemap //------------------------------------------------- tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_mapper_delegate mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated) diff --git a/src/emu/ui/uimain.h b/src/emu/ui/uimain.h index bf10957d743..e45c71f9468 100644 --- a/src/emu/ui/uimain.h +++ b/src/emu/ui/uimain.h @@ -13,6 +13,8 @@ #pragma once +#include <functional> + /*************************************************************************** TYPE DEFINITIONS @@ -35,6 +37,8 @@ public: virtual void menu_reset() { } + virtual bool set_ui_event_handler(std::function<bool ()> &&handler) { return false; } + template <typename Format, typename... Params> void popup_time(int seconds, Format &&fmt, Params &&... args); protected: diff --git a/src/emu/uiinput.cpp b/src/emu/uiinput.cpp index d1398591687..12ba8a08bb0 100644 --- a/src/emu/uiinput.cpp +++ b/src/emu/uiinput.cpp @@ -36,19 +36,11 @@ enum ui_input_manager::ui_input_manager(running_machine &machine) : m_machine(machine) , m_presses_enabled(true) - , m_current_mouse_target(nullptr) - , m_current_mouse_x(-1) - , m_current_mouse_y(-1) - , m_current_mouse_down(false) - , m_current_mouse_field(nullptr) , m_events_start(0) , m_events_end(0) { std::fill(std::begin(m_next_repeat), std::end(m_next_repeat), 0); std::fill(std::begin(m_seqpressed), std::end(m_seqpressed), 0); - - // add a frame callback to poll inputs - machine.add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&ui_input_manager::frame_update, this)); } @@ -58,12 +50,12 @@ ui_input_manager::ui_input_manager(running_machine &machine) ***************************************************************************/ /*------------------------------------------------- - frame_update - looks through pressed - input as per events pushed our way and posts + check_ui_inputs - looks through pressed input + as per events pushed our way and posts corresponding IPT_UI_* events -------------------------------------------------*/ -void ui_input_manager::frame_update() +void ui_input_manager::check_ui_inputs() { // update the state of all the UI keys for (ioport_type code = ioport_type(IPT_UI_FIRST + 1); code < IPT_UI_LAST; ++code) @@ -80,22 +72,6 @@ void ui_input_manager::frame_update() m_seqpressed[code] = false; } } - - // perform mouse hit testing - ioport_field *mouse_field = m_current_mouse_down ? find_mouse_field() : nullptr; - if (m_current_mouse_field != mouse_field) - { - // clear the old field if there was one - if (m_current_mouse_field != nullptr) - m_current_mouse_field->set_value(0); - - // set the new field if it exists and isn't already being pressed - if (mouse_field != nullptr && !mouse_field->digital_value()) - mouse_field->set_value(1); - - // update internal state - m_current_mouse_field = mouse_field; - } } @@ -106,37 +82,6 @@ void ui_input_manager::frame_update() bool ui_input_manager::push_event(ui_event evt) { - // some pre-processing (this is an icky place to do this stuff!) - switch (evt.event_type) - { - case ui_event::type::MOUSE_MOVE: - m_current_mouse_target = evt.target; - m_current_mouse_x = evt.mouse_x; - m_current_mouse_y = evt.mouse_y; - break; - - case ui_event::type::MOUSE_LEAVE: - if (m_current_mouse_target == evt.target) - { - m_current_mouse_target = nullptr; - m_current_mouse_x = -1; - m_current_mouse_y = -1; - } - break; - - case ui_event::type::MOUSE_DOWN: - m_current_mouse_down = true; - break; - - case ui_event::type::MOUSE_UP: - m_current_mouse_down = false; - break; - - default: - /* do nothing */ - break; - } - // is the queue filled up? if ((m_events_end + 1) % std::size(m_events) == m_events_start) return false; @@ -186,64 +131,12 @@ void ui_input_manager::reset() } -/*------------------------------------------------- - find_mouse - retrieves the current - location of the mouse --------------------------------------------------*/ - -render_target *ui_input_manager::find_mouse(s32 *x, s32 *y, bool *button) const -{ - if (x != nullptr) - *x = m_current_mouse_x; - if (y != nullptr) - *y = m_current_mouse_y; - if (button != nullptr) - *button = m_current_mouse_down; - return m_current_mouse_target; -} - - -/*------------------------------------------------- - find_mouse_field - retrieves the input field - the mouse is currently pointing at --------------------------------------------------*/ - -ioport_field *ui_input_manager::find_mouse_field() const -{ - // map the point and determine what was hit - if (m_current_mouse_target != nullptr) - { - ioport_port *port = nullptr; - ioport_value mask; - float x, y; - if (m_current_mouse_target->map_point_input(m_current_mouse_x, m_current_mouse_y, port, mask, x, y)) - { - if (port != nullptr) - return port->field(mask); - } - } - return nullptr; -} - - /*************************************************************************** USER INTERFACE SEQUENCE READING ***************************************************************************/ /*------------------------------------------------- - pressed - return true if a key down - for the given user interface sequence is - detected --------------------------------------------------*/ - -bool ui_input_manager::pressed(int code) -{ - return pressed_repeat(code, 0); -} - - -/*------------------------------------------------- pressed_repeat - return true if a key down for the given user interface sequence is detected, or if autorepeat at the given speed @@ -254,10 +147,10 @@ bool ui_input_manager::pressed_repeat(int code, int speed) { bool pressed; -g_profiler.start(PROFILER_INPUT); + auto profile = g_profiler.start(PROFILER_INPUT); /* get the status of this key (assumed to be only in the defaults) */ - assert(code >= IPT_UI_CONFIGURE && code <= IPT_OSD_16); + assert(code > IPT_UI_FIRST && code < IPT_UI_LAST); pressed = (m_seqpressed[code] == SEQ_PRESSED_TRUE); /* if down, handle it specially */ @@ -272,7 +165,7 @@ g_profiler.start(PROFILER_INPUT); /* if this is an autorepeat case, set a 1x delay and leave pressed = 1 */ else if (speed > 0 && (osd_ticks() + tps - m_next_repeat[code]) >= tps) { - // In the autorepeatcase, we need to double check the key is still pressed + // In the autorepeat case, we need to double-check the key is still pressed // as there can be a delay between the key polling and our processing of the event m_seqpressed[code] = machine().ioport().type_pressed(ioport_type(code)); pressed = (m_seqpressed[code] == SEQ_PRESSED_TRUE); @@ -289,8 +182,6 @@ g_profiler.start(PROFILER_INPUT); else m_next_repeat[code] = 0; -g_profiler.stop(); - return pressed; } @@ -321,105 +212,84 @@ void ui_input_manager::push_window_defocus_event(render_target *target) } /*------------------------------------------------- - push_mouse_move_event - pushes a mouse - move event to the specified render_target --------------------------------------------------*/ - -void ui_input_manager::push_mouse_move_event(render_target *target, s32 x, s32 y) -{ - ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_MOVE; - event.target = target; - event.mouse_x = x; - event.mouse_y = y; - push_event(event); -} - -/*------------------------------------------------- - push_mouse_leave_event - pushes a - mouse leave event to the specified render_target --------------------------------------------------*/ - -void ui_input_manager::push_mouse_leave_event(render_target *target) -{ - ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_LEAVE; - event.target = target; - push_event(event); -} - -/*------------------------------------------------- - push_mouse_down_event - pushes a mouse - down event to the specified render_target --------------------------------------------------*/ - -void ui_input_manager::push_mouse_down_event(render_target *target, s32 x, s32 y) -{ - ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_DOWN; - event.target = target; - event.mouse_x = x; - event.mouse_y = y; - push_event(event); -} - -/*------------------------------------------------- - push_mouse_down_event - pushes a mouse - down event to the specified render_target --------------------------------------------------*/ - -void ui_input_manager::push_mouse_up_event(render_target *target, s32 x, s32 y) -{ - ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_UP; - event.target = target; - event.mouse_x = x; - event.mouse_y = y; - push_event(event); -} - -/*------------------------------------------------- -push_mouse_down_event - pushes a mouse -down event to the specified render_target + push_pointer_update - pushes a pointer update + event to the specified render_target -------------------------------------------------*/ -void ui_input_manager::push_mouse_rdown_event(render_target *target, s32 x, s32 y) +void ui_input_manager::push_pointer_update( + render_target *target, + pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 buttons, + u32 pressed, + u32 released, + s16 clicks) { ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_RDOWN; + event.event_type = ui_event::type::POINTER_UPDATE; event.target = target; - event.mouse_x = x; - event.mouse_y = y; + event.pointer_type = type; + event.pointer_id = ptrid; + event.pointer_device = device; + event.pointer_x = x; + event.pointer_y = y; + event.pointer_buttons = buttons; + event.pointer_pressed = pressed; + event.pointer_released = released; + event.pointer_clicks = clicks; push_event(event); } -/*------------------------------------------------- -push_mouse_down_event - pushes a mouse -down event to the specified render_target --------------------------------------------------*/ - -void ui_input_manager::push_mouse_rup_event(render_target *target, s32 x, s32 y) +void ui_input_manager::push_pointer_leave( + render_target *target, + pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 released, + s16 clicks) { ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_RUP; + event.event_type = ui_event::type::POINTER_LEAVE; event.target = target; - event.mouse_x = x; - event.mouse_y = y; + event.pointer_type = type; + event.pointer_id = ptrid; + event.pointer_device = device; + event.pointer_x = x; + event.pointer_y = y; + event.pointer_buttons = 0U; + event.pointer_pressed = 0U; + event.pointer_released = released; + event.pointer_clicks = clicks; push_event(event); } -/*------------------------------------------------- - push_mouse_double_click_event - pushes - a mouse double-click event to the specified - render_target --------------------------------------------------*/ -void ui_input_manager::push_mouse_double_click_event(render_target *target, s32 x, s32 y) +void ui_input_manager::push_pointer_abort( + render_target *target, + pointer type, + u16 ptrid, + u16 device, + s32 x, + s32 y, + u32 released, + s16 clicks) { ui_event event = { ui_event::type::NONE }; - event.event_type = ui_event::type::MOUSE_DOUBLE_CLICK; + event.event_type = ui_event::type::POINTER_ABORT; event.target = target; - event.mouse_x = x; - event.mouse_y = y; + event.pointer_type = type; + event.pointer_id = ptrid; + event.pointer_device = device; + event.pointer_x = x; + event.pointer_y = y; + event.pointer_buttons = 0U; + event.pointer_pressed = 0U; + event.pointer_released = released; + event.pointer_clicks = clicks; push_event(event); } @@ -441,7 +311,7 @@ void ui_input_manager::push_char_event(render_target *target, char32_t ch) wheel event to the specified render_target -------------------------------------------------*/ -void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int ucNumLines) +void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int lines) { ui_event event = { ui_event::type::NONE }; event.event_type = ui_event::type::MOUSE_WHEEL; @@ -449,7 +319,7 @@ void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 event.mouse_x = x; event.mouse_y = y; event.zdelta = delta; - event.num_lines = ucNumLines; + event.num_lines = lines; push_event(event); } diff --git a/src/emu/uiinput.h b/src/emu/uiinput.h index 3fc89d7a4ff..54170bad7ec 100644 --- a/src/emu/uiinput.h +++ b/src/emu/uiinput.h @@ -13,6 +13,8 @@ #pragma once +#include "interface/uievents.h" + /*************************************************************************** TYPE DEFINITIONS @@ -25,17 +27,15 @@ struct ui_event NONE, WINDOW_FOCUS, WINDOW_DEFOCUS, - MOUSE_MOVE, - MOUSE_LEAVE, - MOUSE_DOWN, - MOUSE_UP, - MOUSE_RDOWN, - MOUSE_RUP, - MOUSE_DOUBLE_CLICK, MOUSE_WHEEL, + POINTER_UPDATE, + POINTER_LEAVE, + POINTER_ABORT, IME_CHAR }; + using pointer = osd::ui_event_handler::pointer; + type event_type; render_target * target; s32 mouse_x; @@ -44,17 +44,27 @@ struct ui_event char32_t ch; short zdelta; int num_lines; + + pointer pointer_type; // type of input controlling this pointer + u16 pointer_id; // pointer ID - will be recycled aggressively + u16 pointer_device; // for grouping pointers for multi-touch gesture recognition + s32 pointer_x; // pointer X coordinate + s32 pointer_y; // pointer Y coordinate + u32 pointer_buttons; // currently depressed buttons + u32 pointer_pressed; // buttons pressed since last update (primary action in LSB) + u32 pointer_released; // buttons released since last update (primary action in LSB) + s16 pointer_clicks; // positive for multi-click, negative on release if turned into hold or drag }; // ======================> ui_input_manager -class ui_input_manager +class ui_input_manager final : public osd::ui_event_handler { public: // construction/destruction ui_input_manager(running_machine &machine); - void frame_update(); + void check_ui_inputs(); // pushes a single event onto the queue bool push_event(ui_event event); @@ -68,17 +78,13 @@ public: // clears all outstanding events void reset(); - // retrieves the current location of the mouse - render_target *find_mouse(s32 *x, s32 *y, bool *button) const; - ioport_field *find_mouse_field() const; - - // return true if a key down for the given user interface sequence is detected - bool pressed(int code); - // enable/disable UI key presses bool presses_enabled() const { return m_presses_enabled; } void set_presses_enabled(bool enabled) { m_presses_enabled = enabled; } + // return true if a key down for the given user interface sequence is detected + bool pressed(int code) { return pressed_repeat(code, 0); } + // return true if a key down for the given user interface sequence is detected, or if autorepeat at the given speed is triggered bool pressed_repeat(int code, int speed); @@ -86,44 +92,32 @@ public: running_machine &machine() const { return m_machine; } // queueing events - void push_window_focus_event(render_target *target); - void push_window_defocus_event(render_target *target); - void push_mouse_move_event(render_target *target, s32 x, s32 y); - void push_mouse_leave_event(render_target *target); - void push_mouse_down_event(render_target *target, s32 x, s32 y); - void push_mouse_up_event(render_target *target, s32 x, s32 y); - void push_mouse_rdown_event(render_target *target, s32 x, s32 y); - void push_mouse_rup_event(render_target *target, s32 x, s32 y); - void push_mouse_double_click_event(render_target *target, s32 x, s32 y); - void push_char_event(render_target *target, char32_t ch); - void push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int ucNumLines); + virtual void push_window_focus_event(render_target *target) override; + virtual void push_window_defocus_event(render_target *target) override; + virtual void push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int lines) override; + virtual void push_pointer_update(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 buttons, u32 pressed, u32 released, s16 clicks) override; + virtual void push_pointer_leave(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) override; + virtual void push_pointer_abort(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) override; + virtual void push_char_event(render_target *target, char32_t ch) override; void mark_all_as_pressed(); private: - // constants - static constexpr unsigned EVENT_QUEUE_SIZE = 128; + static constexpr unsigned EVENT_QUEUE_SIZE = 256; // internal state - running_machine & m_machine; // reference to our machine - - // pressed states; retrieved with ui_input_pressed() - bool m_presses_enabled; - osd_ticks_t m_next_repeat[IPT_COUNT]; - u8 m_seqpressed[IPT_COUNT]; - - // mouse position/info - render_target * m_current_mouse_target; - s32 m_current_mouse_x; - s32 m_current_mouse_y; - bool m_current_mouse_down; - ioport_field * m_current_mouse_field; - - // popped states; ring buffer of ui_events - ui_event m_events[EVENT_QUEUE_SIZE]; - int m_events_start; - int m_events_end; + running_machine & m_machine; + + // pressed states; retrieved with pressed() or pressed_repeat() + bool m_presses_enabled; + osd_ticks_t m_next_repeat[IPT_COUNT]; + u8 m_seqpressed[IPT_COUNT]; + + // ring buffer of ui_events + ui_event m_events[EVENT_QUEUE_SIZE]; + int m_events_start; + int m_events_end; }; #endif // MAME_EMU_UIINPUT_H diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp index 18ba2c6fc6b..4cb6202b4d9 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -11,10 +11,14 @@ #include "emu.h" #include "validity.h" -#include "corestr.h" #include "emuopts.h" +#include "main.h" #include "romload.h" +#include "speaker.h" #include "video/rgbutil.h" + +#include "corestr.h" +#include "path.h" #include "unicode.h" #include <cctype> @@ -47,12 +51,10 @@ using test_delegate = delegate<char (void const *&)>; // type //------------------------------------------------- -#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) test_delegate make_diamond_class_delegate(char (diamond_inheritance::*func)(void const *&), diamond_inheritance *obj) { return test_delegate(func, obj); } -#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) //------------------------------------------------- @@ -319,6 +321,34 @@ void validate_inlines() if (resultu8 != i) osd_printf_error("Error testing count_leading_ones_32 %08x=%02x (expected %02x)\n", t, resultu8, i); } + + u32 expected32 = testu32a << 1 | testu32a >> 31; + for (int i = -33; i <= 33; i++) + { + u32 resultu32r = rotr_32(testu32a, i); + u32 resultu32l = rotl_32(testu32a, -i); + + if (resultu32r != expected32) + osd_printf_error("Error testing rotr_32 %08x, %d=%08x (expected %08x)\n", u32(testu32a), i, resultu32r, expected32); + if (resultu32l != expected32) + osd_printf_error("Error testing rotl_32 %08x, %d=%08x (expected %08x)\n", u32(testu32a), -i, resultu32l, expected32); + + expected32 = expected32 >> 1 | expected32 << 31; + } + + u64 expected64 = testu64a << 1 | testu64a >> 63; + for (int i = -65; i <= 65; i++) + { + u64 resultu64r = rotr_64(testu64a, i); + u64 resultu64l = rotl_64(testu64a, -i); + + if (resultu64r != expected64) + osd_printf_error("Error testing rotr_64 %016x, %d=%016x (expected %016x)\n", u64(testu64a), i, resultu64r, expected64); + if (resultu64l != expected64) + osd_printf_error("Error testing rotl_64 %016x, %d=%016x (expected %016x)\n", u64(testu64a), -i, resultu64l, expected64); + + expected64 = expected64 >> 1 | expected64 << 63; + } } @@ -804,6 +834,15 @@ void validate_rgb() rgb.shl(rgbaint_t(19, 3, 21, 6)); check_expected("rgbaint_t::shl"); + // test shift left out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shl(rgbaint_t(-19, 32, -21, 38)); + check_expected("rgbaint_t::shl"); + // test shift left immediate expected_a = (actual_a = random_i32()) << 7; expected_r = (actual_r = random_i32()) << 7; @@ -813,6 +852,15 @@ void validate_rgb() rgb.shl_imm(7); check_expected("rgbaint_t::shl_imm"); + // test shift left immediate out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shl_imm(32); + check_expected("rgbaint_t::shl_imm"); + // test logical shift right expected_a = s32(u32(actual_a = random_i32()) >> 8); expected_r = s32(u32(actual_r = random_i32()) >> 18); @@ -831,6 +879,15 @@ void validate_rgb() rgb.shr(rgbaint_t(21, 13, 11, 17)); check_expected("rgbaint_t::shr"); + // test logical shift right out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shr(rgbaint_t(40, -18, -26, 32)); + check_expected("rgbaint_t::shr"); + // test logical shift right immediate expected_a = s32(u32(actual_a = random_i32()) >> 5); expected_r = s32(u32(actual_r = random_i32()) >> 5); @@ -849,6 +906,15 @@ void validate_rgb() rgb.shr_imm(15); check_expected("rgbaint_t::shr_imm"); + // test logical shift right immediate out of range + expected_a = (actual_a = random_i32()) & 0; + expected_r = (actual_r = random_i32()) & 0; + expected_g = (actual_g = random_i32()) & 0; + expected_b = (actual_b = random_i32()) & 0; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.shr_imm(35); + check_expected("rgbaint_t::shr_imm"); + // test arithmetic shift right expected_a = (actual_a = random_i32()) >> 16; expected_r = (actual_r = random_i32()) >> 20; @@ -867,6 +933,15 @@ void validate_rgb() rgb.sra(rgbaint_t(1, 29, 10, 22)); check_expected("rgbaint_t::sra"); + // test arithmetic shift right out of range + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.sra(rgbaint_t(-16, -20, 46, 32)); + check_expected("rgbaint_t::sra"); + // test arithmetic shift right immediate (method) expected_a = (actual_a = random_i32()) >> 12; expected_r = (actual_r = random_i32()) >> 12; @@ -885,6 +960,15 @@ void validate_rgb() rgb.sra_imm(9); check_expected("rgbaint_t::sra_imm"); + // test arithmetic shift right immediate out of range (method) + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb.sra_imm(38); + check_expected("rgbaint_t::sra_imm"); + // test arithmetic shift right immediate (operator) expected_a = (actual_a = random_i32()) >> 7; expected_r = (actual_r = random_i32()) >> 7; @@ -903,6 +987,15 @@ void validate_rgb() rgb >>= 11; check_expected("rgbaint_t::operator>>="); + // test arithmetic shift right immediate out of range (operator) + expected_a = (actual_a = random_i32()) >> 31; + expected_r = (actual_r = random_i32()) >> 31; + expected_g = (actual_g = random_i32()) >> 31; + expected_b = (actual_b = random_i32()) >> 31; + rgb.set(actual_a, actual_r, actual_g, actual_b); + rgb >>= 41; + check_expected("rgbaint_t::operator>>="); + // test RGB equality comparison actual_a = random_i32_nolimit(); actual_r = random_i32_nolimit(); @@ -1393,7 +1486,6 @@ void validate_delegates_mfp() if (&o != addr) osd_printf_error("Error testing delegate this pointer adjustment for virtual member function through base class pointer %p -> %p (expected %p)\n", static_cast<void const *>(static_cast<base_b *>(&o)), addr, static_cast<void const *>(&o)); -#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) // test creating delegates for a forward-declared class cb1 = make_diamond_class_delegate(&diamond_inheritance::get_derived_a, &d); cb2 = make_diamond_class_delegate(&diamond_inheritance::get_derived_b, &d); @@ -1423,7 +1515,6 @@ void validate_delegates_mfp() if (static_cast<virtual_base *>(&d) != addr) osd_printf_error("Error testing delegate this pointer adjustment for incomplete class %p -> %p (expected %p)\n", static_cast<void const *>(&d), addr, static_cast<void const *>(static_cast<virtual_base *>(&d))); #endif // defined(_MSC_VER) && !defined(__clang__) -#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) } @@ -1868,6 +1959,7 @@ void validity_checker::validate_begin() m_defstr_map.clear(); m_region_map.clear(); m_ioport_set.clear(); + m_slotcard_set.clear(); // reset internal state m_errors = 0; @@ -2044,7 +2136,7 @@ void validity_checker::validate_driver(device_t &root) device_t::feature_type const imperfect(m_current_driver->type.imperfect_features()); if (!(m_current_driver->flags & (machine_flags::IS_BIOS_ROOT | machine_flags::NO_SOUND_HW)) && !(unemulated & device_t::feature::SOUND)) { - sound_interface_enumerator iter(root); + speaker_device_enumerator iter(root); if (!iter.first()) osd_printf_error("Driver is missing MACHINE_NO_SOUND or MACHINE_NO_SOUND_HW flag\n"); } @@ -2079,7 +2171,6 @@ void validity_checker::validate_roms(device_t &root) u32 current_length = 0; int items_since_region = 1; int last_bios = 0, max_bios = 0; - int total_files = 0; std::unordered_map<std::string, int> bios_names; std::unordered_map<std::string, std::string> bios_descs; char const *defbios = nullptr; @@ -2113,34 +2204,46 @@ void validity_checker::validate_roms(device_t &root) current_length = ROMREGION_GETLENGTH(romp); if (!m_region_map.emplace(fulltag, current_length).second) osd_printf_error("Multiple ROM_REGIONs with the same tag '%s' defined\n", fulltag); + if (current_length == 0) + osd_printf_error("ROM region '%s' has zero length\n", fulltag); } else if (ROMENTRY_ISSYSTEM_BIOS(romp)) // If this is a system bios, make sure it is using the next available bios number { int const bios_flags = ROM_GETBIOSFLAGS(romp); char const *const biosname = romp->name; if (bios_flags != last_bios + 1) - osd_printf_error("Non-sequential BIOS %s (specified as %d, expected to be %d)\n", biosname, bios_flags - 1, last_bios); + osd_printf_error("Non-sequential BIOS %s (specified as %d, expected to be %d)\n", biosname ? biosname : "UNNAMED", bios_flags - 1, last_bios); last_bios = bios_flags; // validate the name - if (strlen(biosname) > 16) - osd_printf_error("BIOS name %s exceeds maximum 16 characters\n", biosname); - for (char const *s = biosname; *s; ++s) + if (!biosname || biosname[0] == 0) + osd_printf_error("BIOS %d is missing a name\n", bios_flags - 1); + else { - if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '.') && (*s != '_') && (*s != '-')) + if (strlen(biosname) > 16) + osd_printf_error("BIOS name %s exceeds maximum 16 characters\n", biosname); + for (char const *s = biosname; *s; ++s) { - osd_printf_error("BIOS name %s contains invalid characters\n", biosname); - break; + if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '.') && (*s != '_') && (*s != '-')) + { + osd_printf_error("BIOS name %s contains invalid characters\n", biosname); + break; + } } - } - // check for duplicate names/descriptions - auto const nameins = bios_names.emplace(biosname, bios_flags); - if (!nameins.second) - osd_printf_error("Duplicate BIOS name %s specified (%d and %d)\n", biosname, nameins.first->second, bios_flags - 1); - auto const descins = bios_descs.emplace(romp->hashdata, biosname); - if (!descins.second) - osd_printf_error("BIOS %s has duplicate description '%s' (was %s)\n", biosname, romp->hashdata, descins.first->second); + // check for duplicate names/descriptions + auto const nameins = bios_names.emplace(biosname, bios_flags); + if (!nameins.second) + osd_printf_error("Duplicate BIOS name %s specified (%d and %d)\n", biosname, nameins.first->second, bios_flags - 1); + if (!romp->hashdata || romp->hashdata[0] == 0) + osd_printf_error("BIOS %s has empty description\n", biosname); + else + { + auto const descins = bios_descs.emplace(romp->hashdata, biosname); + if (!descins.second) + osd_printf_error("BIOS %s has duplicate description '%s' (was %s)\n", biosname, romp->hashdata, descins.first->second); + } + } } else if (ROMENTRY_ISDEFAULT_BIOS(romp)) // if this is a default BIOS setting, remember it so it to check at the end { @@ -2150,7 +2253,6 @@ void validity_checker::validate_roms(device_t &root) { // track the last filename we found last_name = romp->name; - total_files++; max_bios = std::max<int>(max_bios, ROM_GETBIOSFLAGS(romp)); // validate the name @@ -2292,8 +2394,9 @@ void validity_checker::validate_analog_input_field(const ioport_field &field) void validity_checker::validate_dip_settings(const ioport_field &field) { - const char *demo_sounds = ioport_string_from_index(INPUT_STRING_Demo_Sounds); - const char *flipscreen = ioport_string_from_index(INPUT_STRING_Flip_Screen); + char const *const demo_sounds = ioport_string_from_index(INPUT_STRING_Demo_Sounds); + char const *const flipscreen = ioport_string_from_index(INPUT_STRING_Flip_Screen); + char const *const name = field.specific_name() ? field.specific_name() : "UNNAMED"; u8 coin_list[__input_string_coinage_end + 1 - __input_string_coinage_start] = { 0 }; bool coin_error = false; @@ -2306,15 +2409,15 @@ void validity_checker::validate_dip_settings(const ioport_field &field) coin_list[strindex - __input_string_coinage_start] = 1; // make sure demo sounds default to on - if (field.name() == demo_sounds && strindex == INPUT_STRING_On && field.defvalue() != setting->value()) + if (name == demo_sounds && strindex == INPUT_STRING_On && field.defvalue() != setting->value()) osd_printf_error("Demo Sounds must default to On\n"); // check for bad demo sounds options - if (field.name() == demo_sounds && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No)) + if (name == demo_sounds && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No)) osd_printf_error("Demo Sounds option must be Off/On, not %s\n", setting->name()); // check for bad flip screen options - if (field.name() == flipscreen && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No)) + if (name == flipscreen && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No)) osd_printf_error("Flip Screen option must be Off/On, not %s\n", setting->name()); // if we have a neighbor, compare ourselves to him @@ -2324,21 +2427,21 @@ void validity_checker::validate_dip_settings(const ioport_field &field) // check for inverted off/on DIP switch order int next_strindex = get_defstr_index(nextsetting->name(), true); if (strindex == INPUT_STRING_On && next_strindex == INPUT_STRING_Off) - osd_printf_error("%s option must have Off/On options in the order: Off, On\n", field.name()); + osd_printf_error("%s option must have Off/On options in the order: Off, On\n", name); // check for inverted yes/no DIP switch order else if (strindex == INPUT_STRING_Yes && next_strindex == INPUT_STRING_No) - osd_printf_error("%s option must have Yes/No options in the order: No, Yes\n", field.name()); + osd_printf_error("%s option must have Yes/No options in the order: No, Yes\n", name); // check for inverted upright/cocktail DIP switch order else if (strindex == INPUT_STRING_Cocktail && next_strindex == INPUT_STRING_Upright) - osd_printf_error("%s option must have Upright/Cocktail options in the order: Upright, Cocktail\n", field.name()); + osd_printf_error("%s option must have Upright/Cocktail options in the order: Upright, Cocktail\n", name); // check for proper coin ordering else if (strindex >= __input_string_coinage_start && strindex <= __input_string_coinage_end && next_strindex >= __input_string_coinage_start && next_strindex <= __input_string_coinage_end && strindex >= next_strindex && setting->condition() == nextsetting->condition()) { - osd_printf_error("%s option has unsorted coinage %s > %s\n", field.name(), setting->name(), nextsetting->name()); + osd_printf_error("%s option has unsorted coinage %s > %s\n", name, setting->name(), nextsetting->name()); coin_error = true; } } @@ -2362,6 +2465,12 @@ void validity_checker::validate_dip_settings(const ioport_field &field) void validity_checker::validate_condition(const ioport_condition &condition, device_t &device) { + if (condition.tag() == nullptr) + { + osd_printf_error("Condition referencing null ioport tag\n"); + return; + } + // resolve the tag, then find a matching port if (m_ioport_set.find(device.subtag(condition.tag())) == m_ioport_set.end()) osd_printf_error("Condition referencing non-existent ioport tag '%s'\n", condition.tag()); @@ -2426,34 +2535,43 @@ void validity_checker::validate_inputs(device_t &root) if (field.is_analog()) validate_analog_input_field(field); - // look for invalid (0) types which should be mapped to IPT_OTHER - if (field.type() == IPT_INVALID) + // checks based on field type + if ((field.type() > IPT_UI_FIRST) && (field.type() < IPT_UI_LAST)) + { + osd_printf_error("Field has invalid UI control type\n"); + } + else if (field.type() == IPT_INVALID) + { osd_printf_error("Field has an invalid type (0); use IPT_OTHER instead\n"); - - if (field.type() == IPT_SPECIAL) + } + else if (field.type() == IPT_SPECIAL) + { osd_printf_error("Field has an invalid type IPT_SPECIAL\n"); - - // verify dip switches - if (field.type() == IPT_DIPSWITCH) + } + else if (field.type() == IPT_DIPSWITCH) { - // dip switch fields must have a specific name + // DIP switch fields must have a specific name if (field.specific_name() == nullptr) osd_printf_error("DIP switch has no specific name\n"); // verify the settings list validate_dip_settings(field); } - - // verify config settings - if (field.type() == IPT_CONFIG) + else if (field.type() == IPT_CONFIG) { // config fields must have a specific name if (field.specific_name() == nullptr) osd_printf_error("Config switch has no specific name\n"); } + else if (field.type() == IPT_ADJUSTER) + { + // adjuster fields must have a specific name + if (field.specific_name() == nullptr) + osd_printf_error("Adjuster has no specific name\n"); + } // verify names - const char *name = field.specific_name(); + char const *const name = field.specific_name(); if (name != nullptr) { // check for empty string @@ -2467,9 +2585,6 @@ void validity_checker::validate_inputs(device_t &root) // check for invalid UTF-8 if (!utf8_is_valid_string(name)) osd_printf_error("Field '%s' has invalid characters\n", name); - - // look up the string and print an error if default strings are not used - /*strindex =get_defstr_index(defstr_map, name, driver, &error);*/ } // verify conditions on the field @@ -2549,6 +2664,10 @@ void validity_checker::validate_devices(machine_config &config) if (slot->default_option() != nullptr && option.first == slot->default_option()) continue; + // if we need to save time, instantiate and validate each slot card type at most once + if (m_quick && !m_slotcard_set.insert(option.second->devtype().shortname()).second) + continue; + m_checking_card = true; device_t *card; { @@ -2774,7 +2893,7 @@ void validity_checker::build_output_prefix(std::ostream &str) const // error_output - error message output override //------------------------------------------------- -void validity_checker::output_callback(osd_output_channel channel, const util::format_argument_pack<std::ostream> &args) +void validity_checker::output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) { std::ostringstream output; switch (channel) diff --git a/src/emu/validity.h b/src/emu/validity.h index 3e6ff8e5a00..fbf5f239323 100644 --- a/src/emu/validity.h +++ b/src/emu/validity.h @@ -51,7 +51,7 @@ public: protected: // osd_output interface - virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<std::ostream> &args) override; + virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override; private: // internal map types @@ -109,6 +109,7 @@ private: int_map m_region_map; string_set m_ioport_set; string_set m_already_checked; + string_set m_slotcard_set; bool m_checking_card; bool const m_quick; }; diff --git a/src/emu/video.cpp b/src/emu/video.cpp index 652272f680b..06a16b76cda 100644 --- a/src/emu/video.cpp +++ b/src/emu/video.cpp @@ -9,19 +9,26 @@ ***************************************************************************/ #include "emu.h" -#include "emuopts.h" -#include "debugger.h" -#include "ui/uimain.h" + #include "crsshair.h" -#include "rendersw.hxx" +#include "debugger.h" +#include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "output.h" +#include "screen.h" + +#include "ui/uimain.h" #include "corestr.h" +#include "path.h" #include "png.h" #include "xmlfile.h" #include "osdepend.h" +#include "rendersw.hxx" + //************************************************************************** // DEBUGGING @@ -211,8 +218,9 @@ void video_manager::frame_update(bool from_debugger) bool const update_screens = (phase == machine_phase::RUNNING) && (!machine().paused() || machine().options().update_in_pause()); bool anything_changed = update_screens && finish_screen_updates(); - // draw the user interface - emulator_info::draw_user_interface(machine()); + // update inputs and draw the user interface + machine().osd().input_update(true); + anything_changed = emulator_info::draw_user_interface(machine()) || anything_changed; // let plugins draw over the UI anything_changed = emulator_info::frame_hook() || anything_changed; @@ -227,21 +235,20 @@ void video_manager::frame_update(bool from_debugger) // if we're throttling, synchronize before rendering attotime current_time = machine().time(); - if (!from_debugger && !skipped_it && phase > machine_phase::INIT && !m_low_latency && effective_throttle()) + if (!from_debugger && phase > machine_phase::INIT && !m_low_latency && effective_throttle()) update_throttle(current_time); // ask the OSD to update - g_profiler.start(PROFILER_BLIT); - machine().osd().update(!from_debugger && skipped_it); - g_profiler.stop(); + { + auto profile = g_profiler.start(PROFILER_BLIT); + machine().osd().update(!from_debugger && skipped_it); + } // we synchronize after rendering instead of before, if low latency mode is enabled - if (!from_debugger && !skipped_it && phase > machine_phase::INIT && m_low_latency && effective_throttle()) + if (!from_debugger && phase > machine_phase::INIT && m_low_latency && effective_throttle()) update_throttle(current_time); - // get most recent input now - machine().osd().input_update(); - + machine().osd().input_update(false); emulator_info::periodic_check(); if (!from_debugger) @@ -299,7 +306,7 @@ std::string video_manager::speed_text() // append the speed for all cases except paused if (!paused) - util::stream_format(str, "%4d%%", (int)(100 * m_speed_percent + 0.5)); + util::stream_format(str, " %3d%%", int(100 * m_speed_percent + 0.5)); // display the number of partial updates as well int partials = 0; @@ -317,7 +324,7 @@ std::string video_manager::speed_text() // file handle //------------------------------------------------- -void video_manager::save_snapshot(screen_device *screen, emu_file &file) +void video_manager::save_snapshot(screen_device *screen, util::core_file &file) { // validate assert(!m_snap_native || screen != nullptr); @@ -378,18 +385,15 @@ void video_manager::save_active_screen_snapshots() void video_manager::begin_recording_screen(const std::string &filename, uint32_t index, screen_device *screen, movie_recording::format format) { - // determine the file extension - const char *extension = movie_recording::format_file_extension(format); - // create the emu_file - bool is_absolute_path = !filename.empty() && osd_is_absolute_path(filename); + bool const is_absolute_path = !filename.empty() && osd_is_absolute_path(filename); std::unique_ptr<emu_file> movie_file = std::make_unique<emu_file>( is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); // and open the actual file std::error_condition filerr = filename.empty() - ? open_next(*movie_file, extension) + ? open_next(*movie_file, movie_recording::format_file_extension(format)) : movie_file->open(filename); if (filerr) { @@ -427,26 +431,48 @@ void video_manager::begin_recording(const char *name, movie_recording::format fo // clear out existing recordings m_movie_recordings.clear(); + // check if the supplied name already has the desired extension + std::string_view basename; + std::string extension; + if (name) + { + std::string_view const desired_ext = movie_recording::format_file_extension(format); + basename = name; + extension.reserve(1 + desired_ext.length()); + extension.assign(1, '.').append(desired_ext); + if (core_filename_ends_with(basename, extension)) + { + extension = basename.substr(basename.length() - extension.length()); + basename.remove_suffix(extension.length()); + } + } + if (m_snap_native) { + std::string tempname; for (uint32_t index = 0; index < count; index++, iter++) { - create_snapshot_bitmap(iter.current()); + create_snapshot_bitmap(iter.current()); // TODO: only do this when starting on-the-fly, and make name match AVI file name - std::string tempname; if (name) - tempname = index > 0 ? name : util::string_format("%s%d", name, index); + { + if (1 < count) + tempname = util::string_format("%s%d%s", basename, index, extension); + else + tempname.assign(name).append(extension); + } + begin_recording_screen( - tempname, - index, - iter.current(), - format); + tempname, + index, + iter.current(), + format); } } else { create_snapshot_bitmap(nullptr); - begin_recording_screen(name ? name : "", 0, iter.current(), format); + begin_recording_screen(std::string(basename) + extension, 0, iter.current(), format); } } @@ -492,7 +518,7 @@ void video_manager::exit() // when there are no screens to drive it //------------------------------------------------- -void video_manager::screenless_update_callback(void *ptr, int param) +void video_manager::screenless_update_callback(s32 param) { // force an update frame_update(false); @@ -506,8 +532,13 @@ void video_manager::screenless_update_callback(void *ptr, int param) void video_manager::postload() { + attotime const emutime = machine().time(); for (const auto &x : m_movie_recordings) - x->set_next_frame_time(machine().time()); + x->set_next_frame_time(emutime); + + // reset speed measurements + m_speed_last_realtime = osd_ticks(); + m_speed_last_emutime = emutime; } @@ -590,7 +621,7 @@ bool video_manager::finish_screen_updates() bool has_live_screen = false; for (screen_device &screen : iter) { - if (screen.partial_scan_hpos() >= 0) // previous update ended mid-scanline + if (screen.partial_scan_hpos() > 0) // previous update ended mid-scanline screen.update_now(); screen.update_partial(screen.visible_area().max_y); @@ -776,7 +807,7 @@ osd_ticks_t video_manager::throttle_until_ticks(osd_ticks_t target_ticks) bool const allowed_to_sleep = (machine().options().sleep() && (!effective_autoframeskip() || effective_frameskip() == 0)) || machine().paused(); // loop until we reach our target - g_profiler.start(PROFILER_IDLE); + auto profile = g_profiler.start(PROFILER_IDLE); osd_ticks_t current_ticks = osd_ticks(); while (current_ticks < target_ticks) { @@ -812,7 +843,6 @@ osd_ticks_t video_manager::throttle_until_ticks(osd_ticks_t target_ticks) } current_ticks = new_ticks; } - g_profiler.stop(); return current_ticks; } @@ -960,10 +990,23 @@ void video_manager::recompute_speed(const attotime &emutime) if (m_seconds_to_run != 0 && emutime.seconds() >= m_seconds_to_run) { // create a final screenshot - emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - std::error_condition const filerr = open_next(file, "png"); - if (!filerr) - save_snapshot(nullptr, file); + if (m_snap_native) + { + for (screen_device &screen : screen_device_enumerator(machine().root_device())) + { + emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + std::error_condition const filerr = open_next(file, "png"); + if (!filerr) + save_snapshot(&screen, file); + } + } + else + { + emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + std::error_condition const filerr = open_next(file, "png"); + if (!filerr) + save_snapshot(nullptr, file); + } //printf("Scheduled exit at %f\n", emutime.as_double()); // schedule our demise @@ -1057,14 +1100,19 @@ std::error_condition video_manager::open_next(emu_file &file, const char *extens // handle defaults const char *snapname = machine().options().snap_name(); - if (snapname == nullptr || snapname[0] == 0) + if (!snapname || !snapname[0]) snapname = "%g/%i"; std::string snapstr(snapname); - // strip any extension in the provided name - int index = snapstr.find_last_of('.'); - if (index != -1) - snapstr = snapstr.substr(0, index); + // strip desired extension if already present + std::string extstr; + extstr.reserve(1 + std::strlen(extension)); + extstr.assign(1, '.').append(extension); + if (core_filename_ends_with(snapstr, extstr)) + { + extstr = snapstr.substr(snapstr.length() - extstr.length()); + snapstr.resize(snapstr.length() - extstr.length()); + } // handle %d in the template (for image devices) std::string snapdev("%d_"); @@ -1129,27 +1177,30 @@ std::error_condition video_manager::open_next(emu_file &file, const char *extens if (pos_time != -1) { - char t_str[15]; + char t_str[16]; const std::time_t cur_time = std::time(nullptr); strftime(t_str, sizeof(t_str), "%Y%m%d_%H%M%S", std::localtime(&cur_time)); strreplace(snapstr, "%t", t_str); } - // add our own extension - snapstr.append(".").append(extension); + // append extension + snapstr.append(extstr); // substitute path and gamename up front strreplace(snapstr, "/", PATH_SEPARATOR); strreplace(snapstr, "%g", machine().basename()); - // determine if the template has an index; if not, we always use the same name + // determine if the template has an index std::string fname; if (snapstr.find("%i") == -1) + { + // if not, we always use the same name fname.assign(snapstr); - - // otherwise, we scan for the next available filename + } else { + // otherwise, we scan for the next available filename + // try until we succeed file.set_openflags(OPEN_FLAG_WRITE); for (int seq = 0; ; seq++) @@ -1182,7 +1233,7 @@ void video_manager::record_frame() return; // start the profiler and get the current time - g_profiler.start(PROFILER_MOVIE_REC); + auto profile = g_profiler.start(PROFILER_MOVIE_REC); attotime curtime = machine().time(); bool error = false; @@ -1201,7 +1252,6 @@ void video_manager::record_frame() if (error) end_recording(); - g_profiler.stop(); } diff --git a/src/emu/video.h b/src/emu/video.h index c6d69194ba1..efc819ae793 100644 --- a/src/emu/video.h +++ b/src/emu/video.h @@ -78,7 +78,7 @@ public: // snapshots bool snap_native() const { return m_snap_native; } render_target &snapshot_target() { return *m_snap_target; } - void save_snapshot(screen_device *screen, emu_file &file); + void save_snapshot(screen_device *screen, util::core_file &file); void save_active_screen_snapshots(); // movies @@ -90,7 +90,7 @@ public: private: // internal helpers void exit(); - void screenless_update_callback(void *ptr, int param); + void screenless_update_callback(s32 param); void postload(); // effective value helpers diff --git a/src/emu/video/resnet.h b/src/emu/video/resnet.h index 638f9909255..53ef41ee5dd 100644 --- a/src/emu/video/resnet.h +++ b/src/emu/video/resnet.h @@ -106,7 +106,7 @@ struct res_net_channel_info { // - Least significant bit first double R[8]; // Minimum output voltage - // - Applicable if output is routed through a complimentary + // - Applicable if output is routed through a complementary // - darlington circuit // - typical value ~ 0.9V double minout; diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h index e460208d9fd..b20d79c94d8 100644 --- a/src/emu/video/rgbgen.h +++ b/src/emu/video/rgbgen.h @@ -151,16 +151,21 @@ public: inline void shl(const rgbaint_t& shift) { - m_a <<= shift.m_a; - m_r <<= shift.m_r; - m_g <<= shift.m_g; - m_b <<= shift.m_b; + m_a = (u32(shift.m_a) > 31) ? 0 : (m_a << shift.m_a); + m_r = (u32(shift.m_r) > 31) ? 0 : (m_r << shift.m_r); + m_g = (u32(shift.m_g) > 31) ? 0 : (m_g << shift.m_g); + m_b = (u32(shift.m_b) > 31) ? 0 : (m_b << shift.m_b); } inline void shl_imm(const u8 shift) { if (shift == 0) return; + if (shift > 31) + { + zero(); + return; + } m_a <<= shift; m_r <<= shift; @@ -170,16 +175,21 @@ public: inline void shr(const rgbaint_t& shift) { - m_a = s32(u32(m_a) >> shift.m_a); - m_r = s32(u32(m_r) >> shift.m_r); - m_g = s32(u32(m_g) >> shift.m_g); - m_b = s32(u32(m_b) >> shift.m_b); + m_a = (u32(shift.m_a) > 31) ? 0 : s32(u32(m_a) >> shift.m_a); + m_r = (u32(shift.m_r) > 31) ? 0 : s32(u32(m_r) >> shift.m_r); + m_g = (u32(shift.m_g) > 31) ? 0 : s32(u32(m_g) >> shift.m_g); + m_b = (u32(shift.m_b) > 31) ? 0 : s32(u32(m_b) >> shift.m_b); } inline void shr_imm(const u8 shift) { if (shift == 0) return; + if (shift > 31) + { + zero(); + return; + } m_a = s32(u32(m_a) >> shift); m_r = s32(u32(m_r) >> shift); @@ -189,43 +199,19 @@ public: inline void sra(const rgbaint_t& shift) { - m_a >>= shift.m_a; - if (m_a & (1 << (31 - shift.m_a))) - m_a |= ~0 << (32 - shift.m_a); - - m_r >>= shift.m_r; - if (m_r & (1 << (31 - shift.m_r))) - m_r |= ~0 << (32 - shift.m_r); - - m_g >>= shift.m_g; - if (m_g & (1 << (31 - shift.m_g))) - m_g |= ~0 << (32 - shift.m_g); - - m_b >>= shift.m_b; - if (m_b & (1 << (31 - shift.m_b))) - m_b |= ~0 << (32 - shift.m_b); + m_a >>= (u32(shift.m_a) > 31) ? 31 : shift.m_a; + m_r >>= (u32(shift.m_r) > 31) ? 31 : shift.m_r; + m_g >>= (u32(shift.m_g) > 31) ? 31 : shift.m_g; + m_b >>= (u32(shift.m_b) > 31) ? 31 : shift.m_b; } inline void sra_imm(const u8 shift) { - const u32 high_bit = 1 << (31 - shift); - const u32 high_mask = ~0 << (32 - shift); - - m_a >>= shift; - if (m_a & high_bit) - m_a |= high_mask; - - m_r >>= shift; - if (m_r & high_bit) - m_r |= high_mask; - - m_g >>= shift; - if (m_g & high_bit) - m_g |= high_mask; - - m_b >>= shift; - if (m_b & high_bit) - m_b |= high_mask; + const u8 s = std::min<u8>(shift, 31); + m_a >>= s; + m_r >>= s; + m_g >>= s; + m_b >>= s; } void or_reg(const rgbaint_t& color) { or_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); } diff --git a/src/emu/video/rgbvmx.cpp b/src/emu/video/rgbvmx.cpp index 608f7024565..62bd25b3578 100644 --- a/src/emu/video/rgbvmx.cpp +++ b/src/emu/video/rgbvmx.cpp @@ -190,7 +190,7 @@ void rgbaint_t::scale_and_clamp(const rgbaint_t& scale) clamp_to_uint8(); } -void rgbaint_t::scale_imm_and_clamp(const s32 scale) +void rgbaint_t::scale_imm_and_clamp(s32 scale) { mul_imm(scale); sra_imm(8); diff --git a/src/emu/video/rgbvmx.h b/src/emu/video/rgbvmx.h index 05d26cd9e21..dd1946bfa28 100644 --- a/src/emu/video/rgbvmx.h +++ b/src/emu/video/rgbvmx.h @@ -76,7 +76,7 @@ public: } // This function sets all elements to the same val - void set_all(const s32& val) { set(val, val, val, val); } + void set_all(const s32 &val) { set(val, val, val, val); } // This function zeros all elements void zero() { set_all(0); } // This function zeros only the alpha element @@ -100,31 +100,31 @@ public: return result; } - void set_a16(const s32 value) + void set_a16(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_perm(m_value, temp, alpha_perm); } - void set_a(const s32 value) + void set_a(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_perm(m_value, temp, alpha_perm); } - void set_r(const s32 value) + void set_r(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_perm(m_value, temp, red_perm); } - void set_g(const s32 value) + void set_g(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_perm(m_value, temp, green_perm); } - void set_b(const s32 value) + void set_b(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_perm(m_value, temp, blue_perm); @@ -229,13 +229,13 @@ public: m_value = vec_add(m_value, color2.m_value); } - inline void add_imm(const s32 imm) + inline void add_imm(s32 imm) { const VECS32 temp = { imm, imm, imm, imm }; m_value = vec_add(m_value, temp); } - inline void add_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void add_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -250,13 +250,13 @@ public: m_value = vec_sub(m_value, color2.m_value); } - inline void sub_imm(const s32 imm) + inline void sub_imm(s32 imm) { const VECS32 temp = { imm, imm, imm, imm }; m_value = vec_sub(m_value, temp); } - inline void sub_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void sub_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -271,13 +271,13 @@ public: m_value = vec_sub(color2.m_value, m_value); } - inline void subr_imm(const s32 imm) + inline void subr_imm(s32 imm) { const VECS32 temp = { imm, imm, imm, imm }; m_value = vec_sub(temp, m_value); } - inline void subr_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void subr_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -298,7 +298,7 @@ public: #endif } - inline void mul_imm(const s32 imm) + inline void mul_imm(s32 imm) { const VECU32 value = { u32(imm), u32(imm), u32(imm), u32(imm) }; const VECU32 shift = vec_splat_u32(-16); @@ -310,7 +310,7 @@ public: #endif } - inline void mul_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void mul_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECU32 value = { u32(b), u32(g), u32(r), u32(a) }; @@ -332,10 +332,17 @@ public: m_value = vec_and(vec_sl(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value))); } - inline void shl_imm(const u8 shift) + inline void shl_imm(u8 shift) { - const VECU32 temp = { shift, shift, shift, shift }; - m_value = vec_sl(m_value, temp); + if (32 > shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sl(m_value, temp); + } + else + { + m_value = vec_splat_s32(0); + } } inline void shr(const rgbaint_t& shift) @@ -344,10 +351,17 @@ public: m_value = vec_and(vec_sr(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value))); } - inline void shr_imm(const u8 shift) + inline void shr_imm(u8 shift) { - const VECU32 temp = { shift, shift, shift, shift }; - m_value = vec_sr(m_value, temp); + if (32 > shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sr(m_value, temp); + } + else + { + m_value = vec_splat_s32(0); + } } inline void sra(const rgbaint_t& shift) @@ -356,8 +370,9 @@ public: m_value = vec_sra(m_value, vec_min(VECU32(shift.m_value), limit)); } - inline void sra_imm(const u8 shift) + inline void sra_imm(u8 shift) { + shift = std::min<u8>(shift, 31); const VECU32 temp = { shift, shift, shift, shift }; m_value = vec_sra(m_value, temp); } @@ -367,13 +382,13 @@ public: m_value = vec_or(m_value, color2.m_value); } - inline void or_imm(const s32 value) + inline void or_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_or(m_value, temp); } - inline void or_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void or_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -393,13 +408,13 @@ public: m_value = vec_andc(m_value, color.m_value); } - inline void and_imm(const s32 value) + inline void and_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_and(m_value, temp); } - inline void and_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void and_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -414,13 +429,13 @@ public: m_value = vec_xor(m_value, color2.m_value); } - inline void xor_imm(const s32 value) + inline void xor_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_xor(m_value, temp); } - inline void xor_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void xor_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -430,7 +445,7 @@ public: m_value = vec_xor(m_value, temp); } - inline void clamp_and_clear(const u32 sign) + inline void clamp_and_clear(u32 sign) { const VECS32 vzero = { 0, 0, 0, 0 }; VECS32 vsign = { s32(sign), s32(sign), s32(sign), s32(sign) }; @@ -454,7 +469,7 @@ public: #endif } - inline void sign_extend(const u32 compare, const u32 sign) + inline void sign_extend(u32 compare, u32 sign) { const VECS32 compare_vec = { s32(compare), s32(compare), s32(compare), s32(compare) }; const VECS32 compare_mask = VECS32(vec_cmpeq(vec_and(m_value, compare_vec), compare_vec)); @@ -462,13 +477,13 @@ public: m_value = vec_or(m_value, vec_and(sign_vec, compare_mask)); } - inline void min(const s32 value) + inline void min(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_min(m_value, temp); } - inline void max(const s32 value) + inline void max(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = vec_max(m_value, temp); @@ -477,7 +492,7 @@ public: void blend(const rgbaint_t& other, u8 factor); void scale_and_clamp(const rgbaint_t& scale); - void scale_imm_and_clamp(const s32 scale); + void scale_imm_and_clamp(s32 scale); void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) { @@ -503,13 +518,13 @@ public: m_value = VECS32(vec_cmpeq(m_value, value.m_value)); } - inline void cmpeq_imm(const s32 value) + inline void cmpeq_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = VECS32(vec_cmpeq(m_value, temp)); } - inline void cmpeq_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void cmpeq_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -524,13 +539,13 @@ public: m_value = VECS32(vec_cmpgt(m_value, value.m_value)); } - inline void cmpgt_imm(const s32 value) + inline void cmpgt_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = VECS32(vec_cmpgt(m_value, temp)); } - inline void cmpgt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void cmpgt_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -545,13 +560,13 @@ public: m_value = VECS32(vec_cmplt(m_value, value.m_value)); } - inline void cmplt_imm(const s32 value) + inline void cmplt_imm(s32 value) { const VECS32 temp = { value, value, value, value }; m_value = VECS32(vec_cmplt(m_value, temp)); } - inline void cmplt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b) + inline void cmplt_imm_rgba(s32 a, s32 r, s32 g, s32 b) { #ifdef __LITTLE_ENDIAN__ const VECS32 temp = { b, g, r, a }; @@ -567,7 +582,7 @@ public: return *this; } - inline rgbaint_t& operator+=(const s32 other) + inline rgbaint_t& operator+=(s32 other) { const VECS32 temp = { other, other, other, other }; m_value = vec_add(m_value, temp); @@ -592,7 +607,7 @@ public: return *this; } - inline rgbaint_t& operator*=(const s32 other) + inline rgbaint_t& operator*=(s32 other) { const VECS32 value = { other, other, other, other }; const VECU32 shift = vec_splat_u32(-16); @@ -605,19 +620,20 @@ public: return *this; } - inline rgbaint_t& operator>>=(const s32 shift) + inline rgbaint_t& operator>>=(s32 shift) { + shift = s32(std::min<u32>(shift, 31)); const VECU32 temp = { u32(shift), u32(shift), u32(shift), u32(shift) }; m_value = vec_sra(m_value, temp); return *this; } - inline void merge_alpha16(const rgbaint_t& alpha) + inline void merge_alpha16(const rgbaint_t &alpha) { m_value = vec_perm(m_value, alpha.m_value, alpha_perm); } - inline void merge_alpha(const rgbaint_t& alpha) + inline void merge_alpha(const rgbaint_t &alpha) { m_value = vec_perm(m_value, alpha.m_value, alpha_perm); } diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp index 16178a2bfc7..ab4f13f11cf 100644 --- a/src/emu/xtal.cpp +++ b/src/emu/xtal.cpp @@ -80,10 +80,12 @@ const double XTAL::known_xtals[] = { 2'000'000, /* 2_MHz_XTAL - */ 2'012'160, /* 2.01216_MHz_XTAL Cidelsa Draco sound board */ 2'097'152, /* 2.097152_MHz_XTAL Icatel 1995 - Brazilian public payphone */ + 2'250'000, /* 2.25_MHz_XTAL Resonator - YM2154 on Yamaha PSR-60 & PSR-70 */ 2'376'000, /* 2.376_MHz_XTAL CIT-101 keyboard */ 2'457'600, /* 2.4576_MHz_XTAL Atari ST MFP */ 2'500'000, /* 2.5_MHz_XTAL Janken Man units */ 2'600'000, /* 2.6_MHz_XTAL Sharp PC-1500 */ + 2'700'000, /* 2.7_MHz_XTAL Resonator - YM2154 on Yamaha RX15 */ 2'950'000, /* 2.95_MHz_XTAL Playmatic MPU-C, MPU-III & Sound-3 */ 3'000'000, /* 3_MHz_XTAL Probably only used to drive 68705 or similar MCUs on 80's Taito PCBs */ 3'072'000, /* 3.072_MHz_XTAL INS 8520 input clock rate */ @@ -100,6 +102,7 @@ const double XTAL::known_xtals[] = { 3'579'000, /* 3.579_MHz_XTAL BeebOPL */ 3'579'545, /* 3.579545_MHz_XTAL NTSC color subcarrier, extremely common, used on 100's of PCBs (Keytronic custom part #48-300-010 is equivalent) */ 3'579'575, /* 3.579575_MHz_XTAL Atari 2600 NTSC */ + 3'680'000, /* 3.68_MHz_XTAL Resonator - Baud rate clock for the 6551 in the MTU-130 */ 3'686'400, /* 3.6864_MHz_XTAL Baud rate clock for MC68681 and similar UARTs */ 3'840'000, /* 3.84_MHz_XTAL Fairlight CMI Alphanumeric Keyboard */ 3'900'000, /* 3.9_MHz_XTAL Resonator - Used on some Fidelity boards */ @@ -115,13 +118,16 @@ const double XTAL::known_xtals[] = { 4'433'619, /* 4.433619_MHz_XTAL PAL color subcarrier (technically 4.43361875mhz)*/ 4'608'000, /* 4.608_MHz_XTAL Luxor ABC-77 keyboard (Keytronic custom part #48-300-107 is equivalent) */ 4'915'200, /* 4.9152_MHz_XTAL - */ + 4'952'000, /* 4.952_MHz_XTAL IGS M036 based mahjong games, for TT5665 sound chip */ 5'000'000, /* 5_MHz_XTAL Mutant Night */ 5'068'800, /* 5.0688_MHz_XTAL Usually used as MC2661 or COM8116 baud rate clock */ 5'185'000, /* 5.185_MHz_XTAL Intel INTELLEC® 4 */ 5'370'000, /* 5.37_MHz_XTAL HP 95LX */ 5'460'000, /* 5.46_MHz_XTAL ec1840 and ec1841 keyboard */ + 5'500'000, /* 5.5_MHz_XTAL Yamaha PSS-480 */ 5'529'600, /* 5.5296_MHz_XTAL Kontron PSI98 keyboard */ 5'626'000, /* 5.626_MHz_XTAL RCA CDP1869 PAL dot clock */ + 5'659'200, /* 5.6592_MHz_XTAL Digilog 320 dot clock */ 5'670'000, /* 5.67_MHz_XTAL RCA CDP1869 NTSC dot clock */ 5'714'300, /* 5.7143_MHz_XTAL Cidelsa Destroyer, TeleVideo serial keyboards */ 5'856'000, /* 5.856_MHz_XTAL HP 3478A Multimeter */ @@ -137,8 +143,9 @@ const double XTAL::known_xtals[] = { 7'000'000, /* 7_MHz_XTAL Jaleco Mega System PCBs */ 7'056'000, /* 7.056_MHz_XTAL Alesis QS FXCHIP (LCM of 44.1 kHz and 48 kHz) */ 7'159'090, /* 7.15909_MHz_XTAL Blood Bros (2x NTSC subcarrier) */ - 7'200'000, /* 7.2_MHz_XTAL Image Fight bootleg I80C031 MCU */ + 7'200'000, /* 7.2_MHz_XTAL Novag Constellation (later models, with /2 divider), Kawai K1 keyscan IC */ 7'372'800, /* 7.3728_MHz_XTAL - */ + 7'680'000, /* 7.68_MHz_XTAL Psion Series 3 */ 7'864'300, /* 7.8643_MHz_XTAL Used on InterFlip games as video clock */ 7'987'000, /* 7.987_MHz_XTAL PC9801-86 YM2608 clock */ 7'995'500, /* 7.9955_MHz_XTAL Used on Electronic Devices Italy Galaxy Gunners sound board */ @@ -158,6 +165,7 @@ const double XTAL::known_xtals[] = { 9'000'000, /* 9_MHz_XTAL Homedata PCBs */ 9'216'000, /* 9.216_MHz_XTAL Univac UTS 20 */ 9'400'000, /* 9.4_MHz_XTAL Yamaha MU-5 and TG-100 */ + 9'426'500, /* 9.4265_MHz_XTAL Yamaha DX7, and DX9 */ 9'600'000, /* 9.6_MHz_XTAL WD37C65 second clock (for 300 KB/sec rate) */ 9'732'000, /* 9.732_MHz_XTAL CTA Invader */ 9'828'000, /* 9.828_MHz_XTAL Universal PCBs */ @@ -172,6 +180,7 @@ const double XTAL::known_xtals[] = { 10'480'000, /* 10.48_MHz_XTAL System-80 (50 Hz) */ 10'500'000, /* 10.5_MHz_XTAL Agat-7 */ 10'595'000, /* 10.595_MHz_XTAL Mad Alien */ + 10'644'000, /* 10.644_MHz_XTAL Northwest Digitial Systems GP-19 */ 10'644'500, /* 10.6445_MHz_XTAL TRS-80 Model I */ 10'687'500, /* 10.6875_MHz_XTAL BBC Bridge Companion */ 10'694'250, /* 10.69425_MHz_XTAL Xerox 820 */ @@ -191,14 +200,16 @@ const double XTAL::known_xtals[] = { 11'289'600, /* 11.2896_MHz_XTAL Frantic Fred */ 11'400'000, /* 11.4_MHz_XTAL HP 9845 */ 11'668'800, /* 11.6688_MHz_XTAL Gameplan pixel clock */ + 11'730'000, /* 11.73_MHz_XTAL Irem M-11 */ 11'800'000, /* 11.8_MHz_XTAL IBM PC Music Feature Card */ 11'980'800, /* 11.9808_MHz_XTAL Luxor ABC 80 */ 12'000'000, /* 12_MHz_XTAL Extremely common, used on 100's of PCBs */ 12'057'600, /* 12.0576_MHz_XTAL Poly 1 (38400 * 314) */ 12'096'000, /* 12.096_MHz_XTAL Some early 80's Atari games */ 12'288'000, /* 12.288_MHz_XTAL Sega Model 3 digital audio board */ + 12'292'000, /* 12.292_MHz_XTAL Northwest Digitial Systems GP-19 */ 12'324'000, /* 12.324_MHz_XTAL Otrona Attache */ - 12'432'000, /* 12.432_MHz_XTAL Kaneko Fly Boy/Fast Freddie Hardware */ + 12'335'600, /* 12.3356_MHz_XTAL RasterOps ColorBoard 264 (~784x NTSC line rate) */ 12'472'500, /* 12.4725_MHz_XTAL Bonanza's Mini Boy 7 */ 12'480'000, /* 12.48_MHz_XTAL TRS-80 Model II */ 12'500'000, /* 12.5_MHz_XTAL Red Alert audio board */ @@ -217,22 +228,27 @@ const double XTAL::known_xtals[] = { 13'495'200, /* 13.4952_MHz_XTAL Used on Shadow Force pcb and maybe other Technos pcbs? */ 13'500'000, /* 13.5_MHz_XTAL Microbee */ 13'516'800, /* 13.5168_MHz_XTAL Kontron KDT6 */ + 13'560'000, /* 13.560_MHz_XTAL Tong Zi Maque */ 13'608'000, /* 13.608_MHz_XTAL TeleVideo 910 & 925 */ 13'824'000, /* 13.824_MHz_XTAL Robotron PC-1715 display circuit */ + 13'977'600, /* 13.9776_MHz_XTAL Kaypro II dot clock */ 14'000'000, /* 14_MHz_XTAL - */ 14'112'000, /* 14.112_MHz_XTAL Timex/Sinclair TS2068 */ 14'192'640, /* 14.19264_MHz_XTAL Central Data 2650 */ 14'218'000, /* 14.218_MHz_XTAL Dragon */ + 14'250'450, /* 14.25045_MHz_XTAL Apple II Europlus */ 14'300'000, /* 14.3_MHz_XTAL Agat-7 */ 14'314'000, /* 14.314_MHz_XTAL Taito TTL Board */ 14'318'181, /* 14.318181_MHz_XTAL Extremely common, used on 100's of PCBs (4x NTSC subcarrier) */ 14'349'600, /* 14.3496_MHz_XTAL Roland S-50 VDP */ + 14'469'000, /* 14.469_MHz_XTAL Esprit Systems Executive 10/102 */ 14'580'000, /* 14.58_MHz_XTAL Fortune 32:16 Video Controller */ 14'705'882, /* 14.705882_MHz_XTAL Aleck64 */ 14'728'000, /* 14.728_MHz_XTAL ADM 36 */ 14'742'800, /* 14.7428_MHz_XTAL ADM 23 */ 14'745'000, /* 14.745_MHz_XTAL Synertek KTM-3 */ 14'745'600, /* 14.7456_MHz_XTAL Namco System 12 & System Super 22/23 for JVS */ + 14'746'000, /* 14.746_MHz_XTAL Namco System 10 MGEXIO */ 14'784'000, /* 14.784_MHz_XTAL Zenith Z-29 */ 14'916'000, /* 14.916_MHz_XTAL ADDS Viewpoint 122 */ 14'976'000, /* 14.976_MHz_XTAL CIT-101 80-column display clock */ @@ -245,6 +261,7 @@ const double XTAL::known_xtals[] = { 15'400'000, /* 15.4_MHz_XTAL DVK KSM */ 15'468'480, /* 15.46848_MHz_XTAL Bank Panic h/w, Sega G80 */ 15'582'000, /* 15.582_MHz_XTAL Zentec Zephyr */ + 15'625'000, /* 15.625_MHz_XTAL Zaccaria The Invaders */ 15'667'200, /* 15.6672_MHz_XTAL Apple Macintosh */ 15'700'000, /* 15.7_MHz_XTAL Motogonki */ 15'741'000, /* 15.741_MHz_XTAL DECmate II 80-column display clock */ @@ -261,16 +278,20 @@ const double XTAL::known_xtals[] = { 16'364'000, /* 16.364_MHz_XTAL Corvus Concept */ 16'384'000, /* 16.384_MHz_XTAL - */ 16'400'000, /* 16.4_MHz_XTAL MS 6102 */ + 16'537'000, /* 16.537_MHz_XTAL Falco terminals 80-column clock */ 16'572'000, /* 16.572_MHz_XTAL Micro-Term ACT-5A */ 16'588'800, /* 16.5888_MHz_XTAL SM 7238 */ 16'666'600, /* 16.6666_MHz_XTAL Firebeat GCU */ + 16'667'000, /* 16.667_MHz_XTAL Visual XDS-19P */ 16'669'800, /* 16.6698_MHz_XTAL Qume QVT-102 */ 16'670'000, /* 16.67_MHz_XTAL - */ 16'777'216, /* 16.777216_MHz_XTAL Nintendo Game Boy Advance */ 16'934'400, /* 16.9344_MHz_XTAL Usually used to drive 90's Yamaha OPL/FM chips (44100 * 384) */ + 16'960'000, /* 16.960_MHz_XTAL Esprit Systems Executive 10/102 */ 17'010'000, /* 17.01_MHz_XTAL Epic 14E */ 17'064'000, /* 17.064_MHz_XTAL Memorex 1377 */ 17'074'800, /* 17.0748_MHz_XTAL SWTPC 8212 */ + 17'320'000, /* 17.320_MHz_XTAL Visual 50 */ 17'350'000, /* 17.35_MHz_XTAL ITT Courier 1700 */ 17'360'000, /* 17.36_MHz_XTAL OMTI Series 10 SCSI controller */ 17'430'000, /* 17.43_MHz_XTAL Videx Videoterm */ @@ -304,6 +325,7 @@ const double XTAL::known_xtals[] = { 20'000'000, /* 20_MHz_XTAL - */ 20'160'000, /* 20.16_MHz_XTAL Nintendo 8080 */ 20'275'200, /* 20.2752_MHz_XTAL TRS-80 Model III */ + 20'282'000, /* 20.282_MHz_XTAL Northwest Digitial Systems GP-19 */ 20'375'040, /* 20.37504_MHz_XTAL Apple Lisa dot clock (197-0019A) */ 20'625'000, /* 20.625_MHz_XTAL SM 7238 */ 20'790'000, /* 20.79_MHz_XTAL Blockade-hardware Gremlin games */ @@ -326,13 +348,16 @@ const double XTAL::known_xtals[] = { 22'321'000, /* 22.321_MHz_XTAL Apple LaserWriter II NT */ 22'464'000, /* 22.464_MHz_XTAL CIT-101 132-column display clock */ 22'579'000, /* 22.579_MHz_XTAL Sega System H1 SCSP clock */ + 22'579'200, /* 22.5792_MHz_XTAL Enhanced Apple Digital Sound Chip clock (44100 * 512) */ 22'656'000, /* 22.656_MHz_XTAL Super Pinball Action (~1440x NTSC line rate) */ + 22'680'000, /* 22.680_MHz_XTAL HDS200 80-columns display clock */ 22'896'000, /* 22.896_MHz_XTAL DEC VT220 132-column display clock */ 23'200'000, /* 23.2_MHz_XTAL Roland JV-80 & JV-880 PCM clock */ 23'814'000, /* 23.814_MHz_XTAL TeleVideo TVI-912, 920 & 950 */ 23'961'600, /* 23.9616_MHz_XTAL Osborne 4 (Vixen) */ 24'000'000, /* 24_MHz_XTAL Mario, 80's Data East games, 80's Konami games */ 24'073'400, /* 24.0734_MHz_XTAL DEC Rainbow 100 */ + 24'167'829, /* 24.167829_MHz_XTAL Neo Geo AES rev. 3-3 and later (~1536x NTSC line rate) */ 24'270'000, /* 24.27_MHz_XTAL CIT-101XL */ 24'300'000, /* 24.3_MHz_XTAL ADM 36 132-column display clock */ 24'576'000, /* 24.576_MHz_XTAL Pole Position h/w, Model 3 CPU board */ @@ -355,7 +380,9 @@ const double XTAL::known_xtals[] = { 26'601'712, /* 26.601712_MHz_XTAL Astro Corp.'s Show Hand, PAL Vtech/Yeno Socrates (6x PAL subcarrier) */ 26'666'000, /* 26.666_MHz_XTAL Imagetek I4220/I4300 */ 26'666'666, /* 26.666666_MHz_XTAL Irem M92 but most use 27MHz */ + 26'670'000, /* 26.670_MHz_XTAL Namco EVA */ 26'686'000, /* 26.686_MHz_XTAL Typically used on 90's Taito PCBs to drive the custom chips */ + 26'824'000, /* 26.824_MHz_XTAL Astro Corp.'s Zoo */ 26'880'000, /* 26.88_MHz_XTAL Roland RF5C36/SA-16 clock (30000 * 896) */ 26'989'200, /* 26.9892_MHz_XTAL TeleVideo 965 */ 27'000'000, /* 27_MHz_XTAL Some Banpresto games macrossp, Irem M92 and 90's Toaplan games */ @@ -371,7 +398,7 @@ const double XTAL::known_xtals[] = { 28'475'000, /* 28.475_MHz_XTAL CoCo 3 PAL */ 28'480'000, /* 28.48_MHz_XTAL Chromatics CGC-7900 */ 28'636'000, /* 28.636_MHz_XTAL Super Kaneko Nova System */ - 28'636'363, /* 28.636363_MHz_XTAL Later Leland games and Atari GT, Amiga NTSC, Raiden2 h/w (8x NTSC subcarrier)*/ + 28'636'363, /* 28.636363_MHz_XTAL Later Leland games and Atari GT, Amiga NTSC, Raiden2 h/w (8x NTSC subcarrier), NEC PC-88xx */ 28'640'000, /* 28.64_MHz_XTAL Fuuki FG-1c AI AM-2 PCB */ 28'700'000, /* 28.7_MHz_XTAL - */ 29'376'000, /* 29.376_MHz_XTAL Qume QVT-103 */ @@ -391,6 +418,7 @@ const double XTAL::known_xtals[] = { 32'256'000, /* 32.256_MHz_XTAL Hitachi MB-6890 */ 32'317'400, /* 32.3174_MHz_XTAL DEC VT330, VT340 */ 32'530'470, /* 32.53047_MHz_XTAL Seta 2 */ + 32'640'000, /* 32.64_MHz_XTAL Vector 4 */ 32'768'000, /* 32.768_MHz_XTAL Roland D-50 audio clock */ 33'000'000, /* 33_MHz_XTAL Sega Model 3 video board */ 33'264'000, /* 33.264_MHz_XTAL Hazeltine 1500 terminal */ @@ -402,6 +430,8 @@ const double XTAL::known_xtals[] = { 34'000'000, /* 34_MHz_XTAL Gaelco PCBs */ 34'291'712, /* 34.291712_MHz_XTAL Fairlight CMI master card */ 34'846'000, /* 34.846_MHz_XTAL Visual 550 */ + 35'469'000, /* 35.469_MHz_XTAL ZX Spectrum +2/+3 (~8x PAL subcarrier) */ + 35'640'000, /* 35.640_MHz_XTAL HDS200 132-column display clock */ 35'834'400, /* 35.8344_MHz_XTAL Tab Products E-22 132-column display clock */ 35'840'000, /* 35.84_MHz_XTAL Akai MPC 60 voice PCB */ 35'904'000, /* 35.904_MHz_XTAL Used on HP98543 graphics board */ @@ -450,6 +480,7 @@ const double XTAL::known_xtals[] = { 57'272'727, /* 57.272727_MHz_XTAL Psikyo SH2 with /2 divider (16x NTSC subcarrier)*/ 57'283'200, /* 57.2832_MHz_XTAL Macintosh IIci RBV, 15-inch portrait display */ 58'000'000, /* 58_MHz_XTAL Magic Reel (Play System) */ + 58'982'400, /* 58.9824_MHz_XTAL Wyse WY-65 */ 59'292'000, /* 59.292_MHz_XTAL Data General D461 */ 60'000'000, /* 60_MHz_XTAL ARM610 */ 61'440'000, /* 61.44_MHz_XTAL Donkey Kong */ @@ -463,6 +494,7 @@ const double XTAL::known_xtals[] = { 72'000'000, /* 72_MHz_XTAL Aristocrat MKV */ 72'576'000, /* 72.576_MHz_XTAL Centipede, Millipede, Missile Command, Let's Go Bowling "Multipede" */ 73'728'000, /* 73.728_MHz_XTAL Ms. Pac-Man/Galaga 20th Anniversary */ + 75'000'000, /* 75_MHz_XTAL Sony NEWS NWS-5000X */ 77'414'400, /* 77.4144_MHz_XTAL NCD17c */ 80'000'000, /* 80_MHz_XTAL ARM710 */ 87'183'360, /* 87.18336_MHz_XTAL AT&T 630 MTG */ @@ -473,6 +505,7 @@ const double XTAL::known_xtals[] = { 101'491'200, /* 101.4912_MHz_XTAL PSX-based Namco System 10 */ 105'561'000, /* 105.561_MHz_XTAL Sun cgsix */ 108'108'000, /* 108.108_MHz_XTAL HP 98550 high-res color card */ + 120'000'000, /* 120_MHz_XTAL Astro Corp.'s Stone Age */ 200'000'000 /* 200_MHz_XTAL Base SH4 CPU (Naomi, Hikaru etc.) */ }; |