summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2019-11-01 00:47:41 +1100
committer Vas Crabb <vas@vastheman.com>2019-11-01 00:47:41 +1100
commit6f4c1f6e5b2525ac8b700b3a0754f5e99c4223e1 (patch)
tree4b0e0ac5cf1c3a7fd518a7d8f4d12f39291b2629 /src/emu
parent0be348c7fbc8c0478f724ba098dabeb9eb3aab8c (diff)
Spring cleaning:
* Changed emu_fatalerror to use util::string_format semantics * Fixed some incorrectly marked up stuff in build scripts * Make internal layout compression type a scoped enum (only zlib is supported still, but at least the values aren't magic numbers now) * Fixed memory leaks in Xbox USB * There can only be one "perfect quantum" device - enforce that only the root machine can set it, as allowing subdevices to will cause weird issues with slot cards overiding it * Allow multiple devices to set maximum quantum and use the most restrictive one (it's maximum quantum, it would be minimum interleave) * Got rid of device_slot_card_interface as it wasn't providing value * Added a helper template to reduce certain kinds of boilerplate in slots/buses * Cleaned up some particularly bad slot code (plenty more of that to do), and made some slots more idiomatic
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/dislot.cpp59
-rw-r--r--src/emu/dislot.h142
-rw-r--r--src/emu/emucore.cpp74
-rw-r--r--src/emu/emucore.h46
-rw-r--r--src/emu/emufwd.h2
-rw-r--r--src/emu/image.cpp16
-rw-r--r--src/emu/machine.cpp2
-rw-r--r--src/emu/main.h24
-rw-r--r--src/emu/mconfig.cpp134
-rw-r--r--src/emu/mconfig.h96
-rw-r--r--src/emu/render.cpp9
-rw-r--r--src/emu/romload.cpp28
-rw-r--r--src/emu/schedule.cpp26
-rw-r--r--src/emu/validity.cpp4
14 files changed, 407 insertions, 255 deletions
diff --git a/src/emu/dislot.cpp b/src/emu/dislot.cpp
index e5bb4cff0d3..9e8a5128996 100644
--- a/src/emu/dislot.cpp
+++ b/src/emu/dislot.cpp
@@ -11,10 +11,6 @@
#include "zippath.h"
-// -------------------------------------------------
-// ctor
-// -------------------------------------------------
-
device_slot_interface::device_slot_interface(const machine_config &mconfig, device_t &device) :
device_interface(device, "slot"),
m_default_clock(DERIVED_CLOCK(1, 1)),
@@ -24,20 +20,11 @@ device_slot_interface::device_slot_interface(const machine_config &mconfig, devi
{
}
-
-// -------------------------------------------------
-// dtor
-// -------------------------------------------------
-
device_slot_interface::~device_slot_interface()
{
}
-// -------------------------------------------------
-// device_slot_option ctor
-// -------------------------------------------------
-
device_slot_interface::slot_option::slot_option(const char *name, const device_type &devtype, bool selectable) :
m_name(name),
m_devtype(devtype),
@@ -50,44 +37,39 @@ device_slot_interface::slot_option::slot_option(const char *name, const device_t
}
-// -------------------------------------------------
-// option_add
-// -------------------------------------------------
+void device_slot_interface::interface_validity_check(validity_checker &valid) const
+{
+ if (m_default_option && (m_options.find(m_default_option) == m_options.end()))
+ osd_printf_error("Default option '%s' does not correspond to any configured option\n", m_default_option);
+}
+
device_slot_interface::slot_option &device_slot_interface::option_add(const char *name, const device_type &devtype)
{
+ if (!name || !*name)
+ throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag());
+
const slot_option *const existing = option(name);
if (existing)
throw emu_fatalerror("slot '%s' duplicate option '%s'\n", device().tag(), name);
- if (m_options.count(name))
- throw tag_add_exception(name);
-
return m_options.emplace(name, std::make_unique<slot_option>(name, devtype, true)).first->second->clock(m_default_clock);
}
-// -------------------------------------------------
-// option_add_internal
-// -------------------------------------------------
-
device_slot_interface::slot_option &device_slot_interface::option_add_internal(const char *name, const device_type &devtype)
{
+ if (!name || !*name)
+ throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag());
+
const slot_option *const existing = option(name);
if (existing)
throw emu_fatalerror("slot '%s' duplicate option '%s'\n", device().tag(), name);
- if (m_options.count(name))
- throw tag_add_exception(name);
-
return m_options.emplace(name, std::make_unique<slot_option>(name, devtype, false)).first->second->clock(m_default_clock);
}
-// -------------------------------------------------
-// option
-// -------------------------------------------------
-
device_slot_interface::slot_option *device_slot_interface::config_option(const char *name)
{
auto const search = m_options.find(name);
@@ -98,10 +80,6 @@ device_slot_interface::slot_option *device_slot_interface::config_option(const c
}
-// -------------------------------------------------
-// has_selectable_options
-// -------------------------------------------------
-
bool device_slot_interface::has_selectable_options() const
{
if (!fixed())
@@ -114,10 +92,6 @@ bool device_slot_interface::has_selectable_options() const
}
-// -------------------------------------------------
-// option
-// -------------------------------------------------
-
const device_slot_interface::slot_option *device_slot_interface::option(const char *name) const
{
if (name)
@@ -130,15 +104,6 @@ const device_slot_interface::slot_option *device_slot_interface::option(const ch
}
-device_slot_card_interface::device_slot_card_interface(const machine_config &mconfig, device_t &device)
- : device_interface(device, "slot")
-{
-}
-
-device_slot_card_interface::~device_slot_card_interface()
-{
-}
-
get_default_card_software_hook::get_default_card_software_hook(const std::string &path, std::function<bool(util::core_file &, std::string&)> &&get_hashfile_extrainfo)
: m_get_hashfile_extrainfo(std::move(get_hashfile_extrainfo))
, m_called_get_hashfile_extrainfo(false)
diff --git a/src/emu/dislot.h b/src/emu/dislot.h
index da6a1b0aa3d..a88102f84e5 100644
--- a/src/emu/dislot.h
+++ b/src/emu/dislot.h
@@ -9,13 +9,10 @@
#ifndef MAME_EMU_DISLOT_H
#define MAME_EMU_DISLOT_H
-
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// ======================> get_default_card_software_hook
-
class get_default_card_software_hook
{
// goofy "hook" to pass to device_slot_interface::get_default_card_software
@@ -42,8 +39,7 @@ private:
};
-// ======================> device_slot_interface
-
+/// \brief Base class for configurable slot devices
class device_slot_interface : public device_interface
{
public:
@@ -77,20 +73,88 @@ public:
u32 m_clock;
};
- // construction/destruction
- device_slot_interface(const machine_config &mconfig, device_t &device);
virtual ~device_slot_interface();
+ /// \brief Set whether slot is fixed
+ ///
+ /// Allows a slot to be configured as fixed. Fixed slots can only
+ /// be configured programmatically. Options for fixed slots are not
+ /// user-selectable. By default, slots are not fixed.
+ /// \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; }
+
+ /// \brief Set the default option
+ ///
+ /// Set the default option the slot. The corresponding card device
+ /// will be loaded if no other option is selected by the user or
+ /// programmatically.
+ /// \param [in] option The name of the default option. This must be
+ /// correspond to an option added using #option_add or
+ /// #option_add_internal, or be nullptr to not load any card
+ /// device by default. The string is not copied and must remain
+ /// 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; }
+
+ /// \brief Clear options
+ ///
+ /// This removes all previously added options.
void option_reset() { m_options.clear(); }
- slot_option &option_add(const char *option, const device_type &devtype);
+
+ /// \brief Add a user-selectable option
+ ///
+ /// Adds an option that may be selected by the user via the command
+ /// line or other configureation methods.
+ /// \param [in] option The name used to select the option. This
+ /// will also be used as the tag when instantiating the card. It
+ /// must be a valid device tag, and should be terse but
+ /// descriptive. The string is copied when the option is added.
+ /// \param [in] devtype Device type of the option. The device type
+ /// 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);
+
+ /// \brief Add an internal option
+ ///
+ /// Adds an option that may only be selected programmatically. This
+ /// is most often used for options used for loading software.
+ /// \param [in] option The name used to select the option. This
+ /// will also be used as the tag when instantiating the card. It
+ /// must be a valid device tag. The string is copied when the
+ /// option is added.
+ /// \param [in] devtype Device type of the option. The device type
+ /// 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);
+
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)); }
void set_option_device_input_defaults(const char *option, const input_device_default *default_input) { config_option(option)->input_device_defaults(default_input); }
+
+ /// \brief Returns whether the slot is fixed
+ ///
+ /// Fixed slots can only be configured programmatically. Slots are
+ /// not fixed by default.
+ /// \return True if the slot is fixed, or false if it is
+ /// user-configurable.
+ /// \sa set_fixed
bool fixed() const { return m_fixed; }
+
+ /// \brief Returns true if the slot has user-selectable options
+ ///
+ /// Returns true if the slot is not marked as fixed and has at least
+ /// one user-selectable option (added using #option_add rather than
+ /// #option_add_internal). Returns false if the slot is marked as
+ /// fixed, all options are internal, or there are no options.
+ /// \return True if the slot has user-selectable options, or false
+ /// otherwise.
bool has_selectable_options() const;
+
const char *default_option() const { return m_default_option; }
const std::unordered_map<std::string, std::unique_ptr<slot_option>> &option_list() const { return m_options; }
const slot_option *option(const char *name) const;
@@ -101,30 +165,68 @@ public:
slot_option &option_set(const char *tag, const 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);
+ virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD;
void set_default_clock(u32 clock) { m_default_clock = clock; }
private:
// internal state
- std::unordered_map<std::string,std::unique_ptr<slot_option>> m_options;
+ std::unordered_map<std::string, std::unique_ptr<slot_option>> m_options;
u32 m_default_clock;
- const char *m_default_option;
+ char const *m_default_option;
bool m_fixed;
device_t *m_card_device;
- slot_option *config_option(const char *option);
+ slot_option *config_option(char const *option);
};
-// iterator
-typedef device_interface_iterator<device_slot_interface> slot_interface_iterator;
-
-// ======================> device_slot_card_interface
-class device_slot_card_interface : public device_interface
+/// \brief Base class for slots that accept a single card interface
+///
+/// Performs basic validity checks to ensure the configured card (if
+/// any) implements the required interface.
+template <typename Card>
+class device_single_card_slot_interface : public device_slot_interface
{
public:
- // construction/destruction
- device_slot_card_interface(const machine_config &mconfig, device_t &device);
- virtual ~device_slot_card_interface();
+ Card *get_card_device() const { return dynamic_cast<Card *>(device_slot_interface::get_card_device()); }
+
+protected:
+ device_single_card_slot_interface(machine_config const &mconfig, device_t &device) :
+ device_slot_interface(mconfig, device)
+ {
+ }
+
+ virtual void interface_validity_check(validity_checker &valid) const override ATTR_COLD
+ {
+ device_slot_interface::interface_validity_check(valid);
+ device_t *const card(device_slot_interface::get_card_device());
+ if (card && !dynamic_cast<Card *>(card))
+ {
+ osd_printf_error(
+ "Card device %s (%s) does not implement %s\n",
+ card->tag(),
+ card->name(),
+ typeid(Card).name());
+ }
+ }
+
+ virtual void interface_pre_start() override ATTR_COLD
+ {
+ device_slot_interface::interface_pre_start();
+ device_t *const card(device_slot_interface::get_card_device());
+ if (card && !dynamic_cast<Card *>(card))
+ {
+ throw emu_fatalerror(
+ "slot '%s' card device %s (%s) does not implement %s\n",
+ device().tag(),
+ card->tag(),
+ card->name(),
+ typeid(Card).name());
+ }
+ }
};
-#endif /* MAME_EMU_DISLOT_H */
+typedef device_interface_iterator<device_slot_interface> slot_interface_iterator;
+
+#endif // MAME_EMU_DISLOT_H
diff --git a/src/emu/emucore.cpp b/src/emu/emucore.cpp
index 35256b4f364..689d5fa1c37 100644
--- a/src/emu/emucore.cpp
+++ b/src/emu/emucore.cpp
@@ -14,60 +14,16 @@
const char *const endianness_names[2] = { "little", "big" };
-emu_fatalerror::emu_fatalerror(const char *format, ...) : code(0)
+emu_fatalerror::emu_fatalerror(util::format_argument_pack<std::ostream> const &args)
+ : emu_fatalerror(0, args)
{
- if (format == nullptr)
- {
- text[0] = '\0';
- }
- else
- {
- va_list ap;
- va_start(ap, format);
- vsnprintf(text, sizeof(text), format, ap);
- va_end(ap);
- }
- osd_break_into_debugger(text);
+ osd_break_into_debugger(m_text.c_str());
}
-emu_fatalerror::emu_fatalerror(const char *format, va_list ap) : code(0)
+emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args)
+ : m_text(util::string_format(args))
+ , m_code(_exitcode)
{
- if (format == nullptr)
- {
- text[0] = '\0';
- }
- else
- {
- vsnprintf(text, sizeof(text), format, ap);
- }
- osd_break_into_debugger(text);
-}
-
-emu_fatalerror::emu_fatalerror(int _exitcode, const char *format, ...) : code(_exitcode)
-{
- if (format == nullptr)
- {
- text[0] = '\0';
- }
- else
- {
- va_list ap;
- va_start(ap, format);
- vsnprintf(text, sizeof(text), format, ap);
- va_end(ap);
- }
-}
-
-emu_fatalerror::emu_fatalerror(int _exitcode, const char *format, va_list ap) : code(_exitcode)
-{
- if (format == nullptr)
- {
- text[0] = '\0';
- }
- else
- {
- vsnprintf(text, sizeof(text), format, ap);
- }
}
@@ -82,21 +38,3 @@ void report_bad_device_cast(const device_t *dev, const std::type_info &src_type,
throw emu_fatalerror("Error: bad downcast<> or device<>. Tried to convert the device %s (%s) of type %s to a %s, which are incompatible.\n",
dev->tag(), dev->name(), src_type.name(), dst_type.name());
}
-
-void fatalerror(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- emu_fatalerror error(format, ap);
- va_end(ap);
- throw error;
-}
-
-void fatalerror_exitcode(running_machine &machine, int exitcode, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- emu_fatalerror error(exitcode, format, ap);
- va_end(ap);
- throw error;
-}
diff --git a/src/emu/emucore.h b/src/emu/emucore.h
index 92135e7ae84..ef6713c8d8f 100644
--- a/src/emu/emucore.h
+++ b/src/emu/emucore.h
@@ -29,6 +29,7 @@
// standard C++ includes
#include <cassert>
#include <exception>
+#include <string>
#include <type_traits>
#include <typeinfo>
@@ -37,6 +38,7 @@
#include "emualloc.h"
#include "corestr.h"
#include "bitmap.h"
+#include "strformat.h"
#include "emufwd.h"
@@ -247,17 +249,26 @@ class emu_exception : public std::exception { };
class emu_fatalerror : public emu_exception
{
public:
- emu_fatalerror(const char *format, ...) ATTR_PRINTF(2,3);
- emu_fatalerror(const char *format, va_list ap);
- emu_fatalerror(int _exitcode, const char *format, ...) ATTR_PRINTF(3,4);
- emu_fatalerror(int _exitcode, const char *format, va_list ap);
-
- const char *string() const { return text; }
- int exitcode() const { return code; }
+ emu_fatalerror(util::format_argument_pack<std::ostream> const &args);
+ emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> 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)...)))
+ {
+ }
+ 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)...)))
+ {
+ }
+
+ virtual char const *what() const noexcept override { return m_text.c_str(); }
+ int exitcode() const noexcept { return m_code; }
private:
- char text[1024];
- int code;
+ std::string m_text;
+ int m_code;
};
class tag_add_exception
@@ -269,12 +280,13 @@ private:
std::string m_tag;
};
+
//**************************************************************************
// CASTING TEMPLATES
//**************************************************************************
-void report_bad_cast(const std::type_info &src_type, const std::type_info &dst_type);
-void report_bad_device_cast(const device_t *dev, const std::type_info &src_type, const std::type_info &dst_type);
+[[noreturn]] void report_bad_cast(const std::type_info &src_type, const std::type_info &dst_type);
+[[noreturn]] void report_bad_device_cast(const device_t *dev, const std::type_info &src_type, const std::type_info &dst_type);
template <typename Dest, typename Source>
inline std::enable_if_t<std::is_base_of<device_t, Source>::value> report_bad_cast(Source *const src)
@@ -316,15 +328,15 @@ inline Dest downcast(Source &src)
//**************************************************************************
-// FUNCTION PROTOTYPES
+// INLINE FUNCTIONS
//**************************************************************************
-[[noreturn]] void fatalerror(const char *format, ...) ATTR_PRINTF(1,2);
-[[noreturn]] void fatalerror_exitcode(running_machine &machine, int exitcode, const char *format, ...) ATTR_PRINTF(3,4);
+template <typename... T>
+[[noreturn]] inline void fatalerror(T &&... args)
+{
+ throw emu_fatalerror(std::forward<T>(args)...);
+}
-//**************************************************************************
-// INLINE FUNCTIONS
-//**************************************************************************
// convert a series of 32 bits into a float
inline float u2f(u32 v)
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index cb0af700c64..97955067865 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -178,7 +178,7 @@ struct ioport_port_live;
class running_machine;
// declared in mconfig.h
-namespace emu { namespace detail { struct machine_config_replace; } }
+namespace emu { namespace detail { class machine_config_replace; } }
class machine_config;
// declared in natkeyboard.h
diff --git a/src/emu/image.cpp b/src/emu/image.cpp
index 3013d03f668..e2cf6d91c83 100644
--- a/src/emu/image.cpp
+++ b/src/emu/image.cpp
@@ -73,11 +73,11 @@ image_manager::image_manager(running_machine &machine)
if (machine.options().write_config())
write_config(machine.options(), nullptr, &machine.system());
- fatalerror_exitcode(machine, EMU_ERR_DEVICE, "Device %s load (-%s %s) failed: %s",
- image.device().name(),
- image.instance_name().c_str(),
- startup_image_name.c_str(),
- image_err.c_str());
+ throw emu_fatalerror(EMU_ERR_DEVICE, "Device %s load (-%s %s) failed: %s",
+ image.device().name(),
+ image.instance_name(),
+ startup_image_name,
+ image_err);
}
}
}
@@ -244,9 +244,9 @@ void image_manager::postdevice_init()
/* unload all images */
unload_all();
- fatalerror_exitcode(machine(), EMU_ERR_DEVICE, "Device %s load failed: %s",
- image.device().name(),
- image_err.c_str());
+ throw emu_fatalerror(EMU_ERR_DEVICE, "Device %s load failed: %s",
+ image.device().name(),
+ image_err);
}
}
/* add a callback for when we shut down */
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index 1b00ddfcfd9..331d5a7905a 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -388,7 +388,7 @@ int running_machine::run(bool quiet)
}
catch (emu_fatalerror &fatal)
{
- osd_printf_error("Fatal error: %s\n", fatal.string());
+ osd_printf_error("Fatal error: %s\n", fatal.what());
error = EMU_ERR_FATALERROR;
if (fatal.exitcode() != 0)
error = fatal.exitcode();
diff --git a/src/emu/main.h b/src/emu/main.h
index a62457a1c75..2a088a3995d 100644
--- a/src/emu/main.h
+++ b/src/emu/main.h
@@ -23,19 +23,17 @@
// CONSTANTS
//**************************************************************************
-enum
-{
- EMU_ERR_NONE = 0, /* no error */
- EMU_ERR_FAILED_VALIDITY = 1, /* failed validity checks */
- EMU_ERR_MISSING_FILES = 2, /* missing files */
- EMU_ERR_FATALERROR = 3, /* some other fatal error */
- EMU_ERR_DEVICE = 4, /* device initialization error (MESS-specific) */
- EMU_ERR_NO_SUCH_GAME = 5, /* game was specified but doesn't exist */
- EMU_ERR_INVALID_CONFIG = 6, /* some sort of error in configuration */
- EMU_ERR_IDENT_NONROMS = 7, /* identified all non-ROM files */
- EMU_ERR_IDENT_PARTIAL = 8, /* identified some files but not all */
- EMU_ERR_IDENT_NONE = 9 /* identified no files */
-};
+constexpr int EMU_ERR_NONE = 0; // no error
+constexpr int EMU_ERR_FAILED_VALIDITY = 1; // failed validity checks
+constexpr int EMU_ERR_MISSING_FILES = 2; // missing files
+constexpr int EMU_ERR_FATALERROR = 3; // some other fatal error
+constexpr int EMU_ERR_DEVICE = 4; // device initialization error
+constexpr int EMU_ERR_NO_SUCH_SYSTEM = 5; // system was specified but doesn't exist
+constexpr int EMU_ERR_INVALID_CONFIG = 6; // some sort of error in configuration
+constexpr int EMU_ERR_IDENT_NONROMS = 7; // identified all non-ROM files
+constexpr int EMU_ERR_IDENT_PARTIAL = 8; // identified some files but not all
+constexpr int EMU_ERR_IDENT_NONE = 9; // identified no files
+
//**************************************************************************
// TYPE DEFINITIONS
diff --git a/src/emu/mconfig.cpp b/src/emu/mconfig.cpp
index e9533aff7d8..d6385c6d628 100644
--- a/src/emu/mconfig.cpp
+++ b/src/emu/mconfig.cpp
@@ -13,7 +13,9 @@
#include "screen.h"
#include <ctype.h>
+
#include <cstring>
+#include <numeric>
//**************************************************************************
@@ -37,12 +39,13 @@ private:
//-------------------------------------------------
machine_config::machine_config(const game_driver &gamedrv, emu_options &options)
- : m_minimum_quantum(attotime::zero)
- , m_gamedrv(gamedrv)
+ : m_gamedrv(gamedrv)
, m_options(options)
, m_root_device()
, m_default_layouts([] (char const *a, char const *b) { return 0 > std::strcmp(a, b); })
, m_current_device(nullptr)
+ , m_maximum_quantums([] (char const *a, char const *b) { return 0 > std::strcmp(a, b); })
+ , m_perfect_quantum_device(nullptr, "")
{
// add the root device
device_add("root", gamedrv.type, 0);
@@ -117,6 +120,51 @@ machine_config::~machine_config()
//-------------------------------------------------
+// maximum_quantum - get smallest configured
+// maximum quantum
+//-------------------------------------------------
+
+attotime machine_config::maximum_quantum(attotime const &default_quantum) const
+{
+ return std::accumulate(
+ m_maximum_quantums.begin(),
+ m_maximum_quantums.end(),
+ default_quantum,
+ [] (attotime const &lhs, maximum_quantum_map::value_type const &rhs) { return (std::min)(lhs, rhs.second); });
+}
+
+//-------------------------------------------------
+// perfect_quantum_device - get device configured
+// for perfect quantum if any
+//-------------------------------------------------
+
+device_execute_interface *machine_config::perfect_quantum_device() const
+{
+ if (!m_perfect_quantum_device.first)
+ return nullptr;
+
+ device_t *const found(m_perfect_quantum_device.first->subdevice(m_perfect_quantum_device.second.c_str()));
+ if (!found)
+ {
+ throw emu_fatalerror(
+ "Device %s relative to %s specified for perfect interleave is not present!\n",
+ m_perfect_quantum_device.second,
+ m_perfect_quantum_device.first->tag());
+ }
+
+ device_execute_interface *result;
+ if (!found->interface(result))
+ {
+ throw emu_fatalerror("Device %s (%s) specified for perfect interleave does not implement device_execute_interface!\n",
+ found->tag(),
+ found->shortname());
+ }
+
+ return result;
+}
+
+
+//-------------------------------------------------
// set_default_layout - set layout for current
// device
//-------------------------------------------------
@@ -130,6 +178,19 @@ void machine_config::set_default_layout(internal_layout const &layout)
//-------------------------------------------------
+// set_maximum_quantum - set maximum scheduling
+// quantum for current device device
+//-------------------------------------------------
+
+void machine_config::set_maximum_quantum(attotime const &quantum)
+{
+ std::pair<maximum_quantum_map::iterator, bool> const ins(m_maximum_quantums.emplace(current_device().tag(), quantum));
+ if (!ins.second)
+ ins.first->second = quantum;
+}
+
+
+//-------------------------------------------------
// device_add - configuration helper to add a
// new device
//-------------------------------------------------
@@ -288,43 +349,70 @@ device_t &machine_config::replace_device(std::unique_ptr<device_t> &&device, dev
//-------------------------------------------------
-// device_find - configuration helper to
-// locate a device
-//-------------------------------------------------
-
-device_t *machine_config::device_find(device_t *owner, const char *tag)
-{
- // find the original device by relative tag (must exist)
- assert(owner != nullptr);
- device_t *device = owner->subdevice(tag);
- if (device == nullptr)
- throw emu_fatalerror("Unable to find device '%s'\n", tag);
-
- // return the device
- return device;
-}
-
-
-//-------------------------------------------------
// remove_references - globally remove references
// to a device about to be removed from the tree
//-------------------------------------------------
void machine_config::remove_references(device_t &device)
{
- // remove default layouts for subdevices
+ // sanity check
+ if (m_perfect_quantum_device.first == &device)
+ {
+ throw emu_fatalerror(
+ "Removing %s device %s would make the perfect quantum device target invalid\n",
+ device.shortname(),
+ device.tag());
+ }
+
+ // remove default layouts and maximum quantum settings for subdevices
char const *const tag(device.tag());
std::size_t const taglen(std::strlen(tag));
- default_layout_map::iterator it(m_default_layouts.lower_bound(tag));
- while ((m_default_layouts.end() != it) && !std::strncmp(tag, it->first, taglen))
+ for (auto it = m_default_layouts.lower_bound(tag); (m_default_layouts.end() != it) && !std::strncmp(tag, it->first, taglen); )
{
if (!it->first[taglen] || (':' == it->first[taglen]))
it = m_default_layouts.erase(it);
else
++it;
}
+ for (auto it = m_maximum_quantums.lower_bound(tag); (m_maximum_quantums.end() != it) && !std::strncmp(tag, it->first, taglen); )
+ {
+ if (!it->first[taglen] || (':' == it->first[taglen]))
+ it = m_maximum_quantums.erase(it);
+ else
+ ++it;
+ }
// iterate over all devices and remove any references
for (device_t &scan : device_iterator(root_device()))
scan.subdevices().m_tagmap.clear();
}
+
+
+//-------------------------------------------------
+// set_perfect_quantum - set device to base
+// scheduling interval on
+//-------------------------------------------------
+
+void machine_config::set_perfect_quantum(device_t &device, std::string tag)
+{
+ if (!m_current_device)
+ {
+ throw emu_fatalerror(
+ "Perfect quantum device can only be set during configuration (set to %s relative to %s)\n",
+ tag,
+ device.tag());
+ }
+
+ if (m_current_device != m_root_device.get())
+ {
+ throw emu_fatalerror(
+ "Perfect quantum device can only be set by the root device (set to %s relative to %s while configuring %s device %s)\n",
+ tag,
+ device.tag(),
+ m_current_device->shortname(),
+ m_current_device->tag());
+ }
+
+ m_perfect_quantum_device.first = &device;
+ m_perfect_quantum_device.second = std::move(tag);
+}
diff --git a/src/emu/mconfig.h b/src/emu/mconfig.h
index 84d42d94996..af332e7db9c 100644
--- a/src/emu/mconfig.h
+++ b/src/emu/mconfig.h
@@ -33,17 +33,32 @@
namespace emu { namespace detail {
-struct machine_config_replace { machine_config &config; };
+class machine_config_replace
+{
+public:
+ machine_config_replace(machine_config_replace const &) = default;
+ machine_config &config;
+private:
+ machine_config_replace(machine_config &c) : config(c) { }
+ friend class ::machine_config;
+};
} } // namesapce emu::detail
+/// \brief Internal layout description
+///
+/// Holds the compressed and decompressed data size, compression method,
+/// and a reference to the compressed layout data. Note that copying
+/// the structure will not copy the referenced data.
struct internal_layout
{
+ enum class compression { NONE, ZLIB };
+
size_t decompressed_size;
size_t compressed_size;
- u8 compression_type;
- const u8* data;
+ compression compression_type;
+ u8 const *data;
};
@@ -96,19 +111,68 @@ public:
emu_options &options() const { return m_options; }
device_t *device(const char *tag) const { return root_device().subdevice(tag); }
template <class DeviceClass> DeviceClass *device(const char *tag) const { return downcast<DeviceClass *>(device(tag)); }
+ attotime maximum_quantum(attotime const &default_quantum) const;
+ device_execute_interface *perfect_quantum_device() const;
+
+ /// \brief Apply visitor to internal layouts
+ ///
+ /// Calls the supplied visitor for each device with an internal
+ /// layout. The order of devices is implementation-dependent.
+ /// \param [in] op The visitor. It must provide a function call
+ // operator that can be invoked with two arguments: a reference
+ // to a #device_t and a const reference to an #internal_layout.
template <typename T> void apply_default_layouts(T &&op) const
{
for (std::pair<char const *, internal_layout const *> const &lay : m_default_layouts)
op(*device(lay.first), *lay.second);
}
- // public state
- attotime m_minimum_quantum; // minimum scheduling quantum
- std::string m_perfect_cpu_quantum; // tag of CPU to use for "perfect" scheduling
-
- // configuration methods
+ /// \brief Get a device replacement helper
+ ///
+ /// Pass the result in place of the machine configuration itself to
+ /// 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); };
+
+ /// \brief Set internal layout for current device
+ ///
+ /// Set internal layout for current device. Each device in the
+ /// system can have its own internal layout. Tags in the layout
+ /// will be resolved relative to the device. Replaces previously
+ /// set layout if any.
+ /// \param [in] layout Reference to the internal layout description
+ /// structure. Neither the description structure nor the
+ /// compressed data is copied. It is the caller's responsibility
+ /// to ensure both remain valid until layouts and views are
+ /// instantiated.
void set_default_layout(internal_layout const &layout);
+ /// \brief Set maximum scheduling quantum
+ ///
+ /// Set the maximum scheduling quantum required for the current
+ /// device. The smallest maximum quantum requested by a device in
+ /// the system will be used.
+ /// \param [in] quantum Maximum scheduling quantum in attoseconds.
+ void set_maximum_quantum(attotime const &quantum);
+
+ template <typename T>
+ void set_perfect_quantum(T &&tag)
+ {
+ set_perfect_quantum(current_device(), std::forward<T>(tag));
+ }
+ template <class DeviceClass, bool Required>
+ void set_perfect_quantum(device_finder<DeviceClass, Required> const &finder)
+ {
+ std::pair<device_t &, char const *> const target(finder.finder_target());
+ set_perfect_quantum(target.first, target.second);
+ }
+ template <class DeviceClass, bool Required>
+ void set_perfect_quantum(device_finder<DeviceClass, Required> &finder)
+ {
+ set_perfect_quantum(const_cast<device_finder<DeviceClass, Required> const &>(finder));
+ }
+
// helpers during configuration; not for general use
token begin_configuration(device_t &device)
{
@@ -116,7 +180,6 @@ public:
m_current_device = &device;
return token(*this, device);
}
- emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace{ *this }; };
device_t *device_add(const char *tag, device_type type, u32 clock);
template <typename Creator>
device_t *device_add(const char *tag, Creator &&type, u32 clock)
@@ -162,11 +225,11 @@ public:
return device_replace(tag, std::forward<Creator>(type), clock.value(), std::forward<Params>(args)...);
}
device_t *device_remove(const char *tag);
- device_t *device_find(device_t *owner, const char *tag);
private:
class current_device_stack;
typedef std::map<char const *, internal_layout const *, bool (*)(char const *, char const *)> default_layout_map;
+ typedef std::map<char const *, attotime, bool (*)(char const *, char const *)> maximum_quantum_map;
// internal helpers
std::pair<const char *, device_t *> resolve_owner(const char *tag) const;
@@ -174,13 +237,16 @@ private:
device_t &add_device(std::unique_ptr<device_t> &&device, device_t *owner);
device_t &replace_device(std::unique_ptr<device_t> &&device, device_t &owner, device_t *existing);
void remove_references(device_t &device);
+ void set_perfect_quantum(device_t &device, std::string tag);
// internal state
- game_driver const & m_gamedrv;
- emu_options & m_options;
- std::unique_ptr<device_t> m_root_device;
- default_layout_map m_default_layouts;
- device_t * m_current_device;
+ game_driver const & m_gamedrv;
+ emu_options & m_options;
+ std::unique_ptr<device_t> m_root_device;
+ default_layout_map m_default_layouts;
+ device_t * m_current_device;
+ maximum_quantum_map m_maximum_quantums;
+ std::pair<device_t *, std::string> m_perfect_quantum_device;
};
#endif // MAME_EMU_MCONFIG_H
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 0c598345ea1..55340803345 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1995,12 +1995,11 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
z_stream stream;
int zerr;
- /* initialize the stream */
+ // initialize the stream
memset(&stream, 0, sizeof(stream));
stream.next_out = tempout.get();
stream.avail_out = layout_data.decompressed_size;
-
zerr = inflateInit(&stream);
if (zerr != Z_OK)
{
@@ -2008,12 +2007,12 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
return false;
}
- /* decompress this chunk */
+ // decompress this chunk
stream.next_in = (unsigned char *)layout_data.data;
stream.avail_in = layout_data.compressed_size;
zerr = inflate(&stream, Z_NO_FLUSH);
- /* stop at the end of the stream */
+ // stop at the end of the stream
if (zerr == Z_STREAM_END)
{
// OK
@@ -2024,7 +2023,7 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
return false;
}
- /* clean up */
+ // clean up
zerr = inflateEnd(&stream);
if (zerr != Z_OK)
{
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index d04d0e308a3..a6610ec6c0c 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -471,7 +471,7 @@ void rom_load_manager::display_rom_load_results(bool from_list)
{
/* create the error message and exit fatally */
osd_printf_error("%s", m_errorstring);
- fatalerror_exitcode(machine(), EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
+ throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
}
/* if we had warnings, output them, but continue */
@@ -595,7 +595,7 @@ int rom_load_manager::open_rom_file(const char *regiontag, const rom_entry *romp
}
if (tag5.find_first_of('%') != -1)
- fatalerror("We do not support clones of clones!\n");
+ throw emu_fatalerror("We do not support clones of clones!\n");
// try to load from the available location(s):
// - if we are not using lists, we have regiontag only;
@@ -688,11 +688,11 @@ int rom_load_manager::read_rom_data(const rom_entry *parent_region, const rom_en
/* make sure we only fill within the region space */
if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes())
- fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
+ throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
/* make sure the length was valid */
if (numbytes == 0)
- fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
+ throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
/* special case for simple loads */
if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
@@ -790,11 +790,11 @@ void rom_load_manager::fill_rom_data(const rom_entry *romp)
// make sure we fill within the region space
if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
- fatalerror("Error in RomModule definition: FILL out of memory region space\n");
+ throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n");
// make sure the length was valid
if (numbytes == 0)
- fatalerror("Error in RomModule definition: FILL has an invalid length\n");
+ throw emu_fatalerror("Error in RomModule definition: FILL has an invalid length\n");
// for fill bytes, the byte that gets filled is the first byte of the hashdata string
u8 fill_byte = u8(strtol(ROM_GETHASHDATA(romp), nullptr, 0));
@@ -823,20 +823,20 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
/* make sure we copy within the region space */
if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
- fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
+ throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
/* make sure the length was valid */
if (numbytes == 0)
- fatalerror("Error in RomModule definition: COPY has an invalid length\n");
+ 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)
- fatalerror("Error in RomModule definition: COPY from an invalid region\n");
+ 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())
- fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
+ throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
/* fill the data */
memcpy(base, region->base() + srcoffs, numbytes);
@@ -856,13 +856,13 @@ void rom_load_manager::process_rom_entries(const char *regiontag, const rom_entr
while (!ROMENTRY_ISREGIONEND(romp))
{
if (ROMENTRY_ISCONTINUE(romp))
- fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
if (ROMENTRY_ISIGNORE(romp))
- fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
if (ROMENTRY_ISRELOAD(romp))
- fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
if (ROMENTRY_ISFILL(romp))
{
@@ -1005,7 +1005,7 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_
}
if (tag5.find_first_of('%') != -1)
- fatalerror("We do not support clones of clones!\n");
+ throw emu_fatalerror("We do not support clones of clones!\n");
// try to load from the available location(s):
// - if we are not using lists, we have locationtag only;
diff --git a/src/emu/schedule.cpp b/src/emu/schedule.cpp
index e2b1497995f..fbe9f667255 100644
--- a/src/emu/schedule.cpp
+++ b/src/emu/schedule.cpp
@@ -756,29 +756,13 @@ void device_scheduler::rebuild_execute_list()
// if we haven't yet set a scheduling quantum, do it now
if (m_quantum_list.empty())
{
- // set the core scheduling quantum
- attotime min_quantum = machine().config().m_minimum_quantum;
-
- // if none specified default to 60Hz
- if (min_quantum.is_zero())
- min_quantum = attotime::from_hz(60);
+ // set the core scheduling quantum, ensuring it's no longer than 60Hz
+ attotime min_quantum = machine().config().maximum_quantum(attotime::from_hz(60));
// if the configuration specifies a device to make perfect, pick that as the minimum
- if (!machine().config().m_perfect_cpu_quantum.empty())
- {
- device_t *device = machine().root_device().subdevice(machine().config().m_perfect_cpu_quantum.c_str());
- if (device == nullptr)
- fatalerror("Device '%s' specified for perfect interleave is not present!\n", machine().config().m_perfect_cpu_quantum.c_str());
-
- device_execute_interface *exec;
- if (!device->interface(exec))
- fatalerror("Device '%s' specified for perfect interleave is not an executing device!\n", machine().config().m_perfect_cpu_quantum.c_str());
-
- min_quantum = std::min(attotime(0, exec->minimum_quantum()), min_quantum);
- }
-
- // make sure it's no higher than 60Hz
- min_quantum = std::min(min_quantum, attotime::from_hz(60));
+ device_execute_interface *const exec(machine().config().perfect_quantum_device());
+ if (exec)
+ 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);
diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp
index 882da29c1ff..a46639d882e 100644
--- a/src/emu/validity.cpp
+++ b/src/emu/validity.cpp
@@ -238,7 +238,7 @@ bool validity_checker::check_all_matching(const char *string)
// if we failed to match anything, it
if (string && !validated_any)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", string);
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_SYSTEM, "No matching systems found for '%s'", string);
return !(m_errors > 0 || m_warnings > 0);
}
@@ -318,7 +318,7 @@ void validity_checker::validate_one(const game_driver &driver)
}
catch (emu_fatalerror &err)
{
- osd_printf_error("Fatal error %s", err.string());
+ osd_printf_error("Fatal error %s", err.what());
}
// if we had warnings or errors, output