// license:BSD-3-Clause // copyright-holders:Aaron Giles /***************************************************************************/ #pragma once #ifndef __EMU_H__ #error Dont include this file directly; include emu.h instead. #endif #ifndef MAME_EMU_MCONFIG_H #define MAME_EMU_MCONFIG_H #include #include #include #include #include #include #include //************************************************************************** // CONSTANTS //************************************************************************** // by convention, tags should all be lowercase #define MIN_TAG_LENGTH 1 //************************************************************************** // TYPE DEFINITIONS //************************************************************************** namespace emu::detail { 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; }; } // namespace 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; compression compression_type; u8 const *data; }; // ======================> machine_config // machine configuration definition class machine_config { DISABLE_COPYING(machine_config); friend class running_machine; public: class token { public: token(machine_config &host, device_t &device) : m_host(host), m_device(&device) { assert(m_device == m_host.m_current_device); } token(token &&that) : m_host(that.m_host), m_device(that.m_device) { that.m_device = nullptr; assert(!m_device || (m_device == m_host.m_current_device)); } token(token const &) = delete; token &operator=(token &&) = delete; token &operator=(token const &) = delete; ~token() { if (m_device) { assert(m_device == m_host.m_current_device); m_host.m_current_device = nullptr; } } private: machine_config &m_host; device_t *m_device; }; // construction/destruction machine_config(const game_driver &gamedrv, emu_options &options); ~machine_config(); // getters const game_driver &gamedrv() const { return m_gamedrv; } device_t &root_device() const { assert(m_root_device); return *m_root_device; } device_t ¤t_device() const { assert(m_current_device); return *m_current_device; } emu_options &options() const { return m_options; } device_t *device(const char *tag) const { return root_device().subdevice(tag); } template DeviceClass *device(const char *tag) const { return downcast(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 void apply_default_layouts(T &&op) const { for (std::pair const &lay : m_default_layouts) op(*device(lay.first), *lay.second); } /// \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 void set_perfect_quantum(T &&tag) { set_perfect_quantum(current_device(), std::forward(tag)); } template void set_perfect_quantum(device_finder const &finder) { std::pair const target(finder.finder_target()); set_perfect_quantum(target.first, target.second); } template void set_perfect_quantum(device_finder &finder) { set_perfect_quantum(const_cast const &>(finder)); } // helpers during configuration; not for general use token begin_configuration(device_t &device) { assert(!m_current_device); m_current_device = &device; return token(*this, device); } device_t *device_add(const char *tag, device_type type, u32 clock); template device_t *device_add(const char *tag, Creator &&type, u32 clock) { return device_add(tag, device_type(type), clock); } template auto device_add(const char *tag, Creator &&type, Params &&... args) { std::pair const owner(resolve_owner(tag)); auto device(type.create(*this, owner.first, owner.second, std::forward(args)...)); auto &result(*device); assert(type.type() == typeid(result)); add_device(std::move(device), owner.second); return &result; } template auto device_add(const char *tag, Creator &&type, XTAL clock, Params &&... args) { clock.validate(std::string("Instantiating device ") + tag); return device_add(tag, std::forward(type), clock.value(), std::forward(args)...); } device_t *device_replace(const char *tag, device_type type, u32 clock); template device_t *device_replace(const char *tag, Creator &&type, u32 clock) { return device_replace(tag, device_type(type), clock); } template auto device_replace(const char *tag, Creator &&type, Params &&... args) { std::tuple const existing(prepare_replace(tag)); auto device(type.create(*this, std::get<0>(existing), std::get<1>(existing), std::forward(args)...)); auto &result(*device); assert(type.type() == typeid(result)); replace_device(std::move(device), *std::get<1>(existing), std::get<2>(existing)); return &result; } template auto device_replace(const char *tag, Creator &&type, XTAL clock, Params &&... args) { clock.validate(std::string("Replacing device ") + tag); return device_replace(tag, std::forward(type), clock.value(), std::forward(args)...); } device_t *device_remove(const char *tag); private: class current_device_stack; typedef std::map default_layout_map; typedef std::map maximum_quantum_map; // internal helpers std::pair resolve_owner(const char *tag) const; std::tuple prepare_replace(const char *tag); device_t &add_device(std::unique_ptr &&device, device_t *owner); device_t &replace_device(std::unique_ptr &&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 m_root_device; default_layout_map m_default_layouts; device_t * m_current_device; maximum_quantum_map m_maximum_quantums; std::pair m_perfect_quantum_device; }; #endif // MAME_EMU_MCONFIG_H