diff options
author | 2020-11-06 03:00:57 +1100 | |
---|---|---|
committer | 2020-11-06 03:00:57 +1100 | |
commit | ae8c70b7e648c169e597a34ea1256e629ed97c7d (patch) | |
tree | af4fb65d907843c57fe5cc5406d2d043d8fa383a | |
parent | 453aed194b9f13e363ee26fc69874c1b8142b891 (diff) |
-emu/devfind.h: Made read_safe avaiable for optional I/O ports only.
-docs: Added the next couple of sections explaining object finders.
-rw-r--r-- | docs/source/techspecs/object_finders.rst | 239 | ||||
-rw-r--r-- | src/devices/bus/coco/coco_dwsock.cpp | 10 | ||||
-rw-r--r-- | src/devices/bus/megadrive/jcart.cpp | 16 | ||||
-rw-r--r-- | src/devices/bus/mtx/sdx.cpp | 2 | ||||
-rw-r--r-- | src/devices/bus/sbus/sbus.cpp | 2 | ||||
-rw-r--r-- | src/devices/bus/sbus/sbus.h | 14 | ||||
-rw-r--r-- | src/emu/devfind.h | 48 | ||||
-rw-r--r-- | src/mame/drivers/maxaflex.cpp | 4 | ||||
-rw-r--r-- | src/mame/drivers/meyc8088.cpp | 8 | ||||
-rw-r--r-- | src/mame/drivers/sun4.cpp | 2 | ||||
-rw-r--r-- | src/mame/drivers/topspeed.cpp | 10 | ||||
-rw-r--r-- | src/mame/video/dooyong.h | 2 |
12 files changed, 308 insertions, 49 deletions
diff --git a/docs/source/techspecs/object_finders.rst b/docs/source/techspecs/object_finders.rst index 75f6b07460f..0a47ff7835d 100644 --- a/docs/source/techspecs/object_finders.rst +++ b/docs/source/techspecs/object_finders.rst @@ -43,8 +43,8 @@ memory_bank_creator optional version, because the target object will always be found or created. required_ioport, optional_ioport - Finds and I/O port from a device’s input port definitions. The target is - the ``ioport_port`` object. + Finds an I/O port from a device’s input port definitions. The target is the + ``ioport_port`` object. required_address_space, optional_address_space Finds a device’s address space. The target is the ``address_space`` object. required_region_ptr<PointerType>, optional_region_ptr<PointerType> @@ -200,5 +200,238 @@ much the same way as pointers:: return m_prom[offset]; } -For convenience, object finders that target the base addresses of memory regions +For convenience, object finders that target the base pointer of memory regions and shares can be indexed like arrays. + + +Connections between devices +--------------------------- + +Devices need to be connected together within a system. For example the Sun SBus +device needs access to the host CPU and address space. Here’s how we declare +the object finders in the device class (with all distractions removed):: + + DECLARE_DEVICE_TYPE(SBUS, sbus_device) + + class sbus_device : public device_t, public device_memory_interface + { + template <typename T, typename U> + sbus_device( + machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, + T &&cpu_tag, + U &&space_tag, int space_num) : + sbus_device(mconfig, tag, owner, clock) + { + set_cpu(std::forward<T>(cpu_tag)); + set_type1space(std::forward<U>(space_tag), space_num); + } + + sbus_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : + device_t(mconfig, type, tag, owner, clock), + device_memory_interface(mconfig, *this), + m_maincpu(*this, finder_base::DUMMY_TAG), + m_type1space(*this, finder_base::DUMMY_TAG, -1) + { + } + + template <typename T> void set_cpu(T &&tag) { m_maincpu.set_tag(std::forward<T>(tag)); } + template <typename T> void set_type1space(T &&tag, int num) { m_type1space.set_tag(std::forward<T>(tag), num); } + + protected: + required_device<sparc_base_device> m_maincpu; + required_address_space m_type1space; + }; + +There are several things to take note of here: + +* Object finder members are declared for the things the device needs to access. +* The device doesn’t know how it will fit into a larger system, the object + finders are constructed with dummy arguments. +* Configuration member functions are provided to set the tag for the host CPU, + and the tag and index for the type 1 address space. +* In addition to the standard device constructor, a constructor with additional + parameters for setting the CPU and type 1 address space is provided. + +The constant ``finder_base::DUMMY_TAG`` is guaranteed to be invalid and will not +resolve to an object. This makes it easy to detect incomplete configuration and +report an error. Address spaces are numbered from zero, so a negative address +space number is invalid. + +The member functions for configuring object finders take a universal reference +to a tag-like object (templated type with ``&&`` qualifier), as well as any +other parameters needed by the specific type of object finder. An address space +finder needs an address space number in addition to a tag-like object. + +So what’s a tag-like object? Three things are supported: + +* A C string pointer (``char const *``) representing a tag relative to the + device being configured. Note that the object finder will not copy the + string. The caller must ensure it remains valid until resolution and/or + validation is complete. +* Another object finder. The object finder will take on its current target. +* For device finders, a reference to an instance of the target device type, + setting the target to that device. Note that this will not work if the device + is subsequently replaced in the machine configuration. It’s most often used + with ``*this``. + +The additional constructor that sets initial configuration delegates to the +standard constructor and then calls the configuration member functions. It’s +purely for convenience. + +When we want to instantiate this device and hook it up, we do this:: + + SPARCV7(config, m_maincpu, 20'000'000); + + ADDRESS_MAP_BANK(config, m_type1space); + + SBUS(config, m_sbus, 20'000'000); + m_sbus->set_cpu(m_maincpu); + m_sbus->set_type1space(m_type1space, 0); + +We supply the same object finders to instantiate the CPU and address space +devices, and to configure the SBus device. + +Note that we could also use literal C strings to configure the SBus device, at +the cost of needing to update the tags in multiple places if they change:: + + SBUS(config, m_sbus, 20'000'000); + m_sbus->set_cpu("maincpu"); + m_sbus->set_type1space("type1", 0); + +If we want to use the convenience constructor, we just supply additional +arguments when instantiating the device:: + + SBUS(config, m_sbus, 20'000'000, m_maincpu, m_type1space, 0); + + +Object finder arrays +-------------------- + +Many systems have multiple similar devices, I/O ports or other resources that +can be logically organised as an array. To simplify these use cases, object +finder array types are provided. The object finder array type names have +``_array`` added to them: + ++------------------------+------------------------------+ +| required_device | required_device_array | ++------------------------+------------------------------+ +| optional_device | optional_device_array | ++------------------------+------------------------------+ +| required_memory_region | required_memory_region_array | ++------------------------+------------------------------+ +| optional_memory_region | optional_memory_region_array | ++------------------------+------------------------------+ +| required_memory_bank | required_memory_bank_array | ++------------------------+------------------------------+ +| optional_memory_bank | optional_memory_bank_array | ++------------------------+------------------------------+ +| memory_bank_creator | memory_bank_array_creator | ++------------------------+------------------------------+ +| required_ioport | required_ioport_array | ++------------------------+------------------------------+ +| optional_ioport | optional_ioport_array | ++------------------------+------------------------------+ +| required_address_space | required_address_space_array | ++------------------------+------------------------------+ +| optional_address_space | optional_address_space_array | ++------------------------+------------------------------+ +| required_region_ptr | required_region_ptr_array | ++------------------------+------------------------------+ +| optional_region_ptr | optional_region_ptr_array | ++------------------------+------------------------------+ +| required_shared_ptr | required_shared_ptr_array | ++------------------------+------------------------------+ +| optional_shared_ptr | optional_shared_ptr_array | ++------------------------+------------------------------+ + +A common case for an object array finder is a key matrix:: + + class keyboard_base : public device_t, public device_mac_keyboard_interface + { + protected: + keyboard_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) : + device_t(mconfig, type, tag, owner, clock), + device_mac_keyboard_interface(mconfig, *this), + m_rows(*this, "ROW%u", 0U) + { + } + + u8 bus_r() + { + u8 result(0xffU); + for (unsigned i = 0U; m_rows.size() > i; ++i) + { + if (!BIT(m_row_drive, i)) + result &= m_rows[i]->read(); + } + return result; + } + + required_ioport_array<10> m_rows; + }; + +Constructing an object finder array is similar to constructing an object finder, +except that rather than just a tag you supply a tag format string and index +offset. In this case, the tags of the I/O ports in the array will be ``ROW0``, +``ROW1``, ``ROW2``, … ``ROW9``. Note that the object finder array allocates +dynamic storage for the tags, which remain valid until destruction. + +The object finder array is used in much the same way as a ``std::array`` of the +underlying object finder type. It supports indexing, iterators, and range-based +``for`` loops. + +Because an index offset is specified, the tags don’t need to use zero-based +indices. It’s common to use one-based indexing like this:: + + class dooyong_state : public driver_device + { + protected: + dooyong_state(machine_config const &mconfig, device_type type, char const *tag) : + driver_device(mconfig, type, tag), + m_bg(*this, "bg%u", 1U), + m_fg(*this, "fg%u", 1U) + { + } + + optional_device_array<dooyong_rom_tilemap_device, 2> m_bg; + optional_device_array<dooyong_rom_tilemap_device, 2> m_fg; + }; + +This causes ``m_bg`` to find devices with tags ``bg1`` and ``bg2``, while +``m_fg`` finds devices with tags ``fg1`` and ``fg2``. Note that the indexes +into the object finder arrays are still zero-based like any other C array. + +It’s also possible to other format conversions, like hexadecimal (``%x`` and +``%X``) or character (``%c``):: + + class eurit_state : public driver_device + { + public: + eurit_state(machine_config const &mconfig, device_type type, char const *tag) : + driver_device(mconfig, type, tag), + m_keys(*this, "KEY%c", 'A') + { + } + + private: + required_ioport_array<5> m_keys; + }; + +In this case, the key matrix ports use tags ``KEYA``, ``KEYB``, ``KEYC``, +``KEYD`` and ``KEYE``. + +When the tags don’t follow a simple ascending sequence, you can supply a +brace-enclosed initialiser list of tags:: + + class seabattl_state : public driver_device + { + public: + seabattl_state(machine_config const &mconfig, device_type type, char const *tag) : + driver_device(mconfig, type, tag), + m_digits(*this, { "sc_thousand", "sc_hundred", "sc_half", "sc_unity", "tm_half", "tm_unity" }) + { + } + + private: + required_device_array<dm9368_device, 6> m_digits; + }; diff --git a/src/devices/bus/coco/coco_dwsock.cpp b/src/devices/bus/coco/coco_dwsock.cpp index 96cfd234f8c..b970458c91c 100644 --- a/src/devices/bus/coco/coco_dwsock.cpp +++ b/src/devices/bus/coco/coco_dwsock.cpp @@ -80,7 +80,7 @@ beckerport_device::~beckerport_device() device_start -------------------------------------------------*/ -void beckerport_device::device_start(void) +void beckerport_device::device_start() { char chAddress[64]; @@ -104,7 +104,7 @@ void beckerport_device::device_start(void) device_stop -------------------------------------------------*/ -void beckerport_device::device_stop(void) +void beckerport_device::device_stop() { if (m_pSocket) { @@ -117,7 +117,7 @@ void beckerport_device::device_stop(void) device_config_complete -------------------------------------------------*/ -void beckerport_device::device_config_complete(void) +void beckerport_device::device_config_complete() { m_hostname = "127.0.0.1"; m_dwtcpport = 65504; @@ -198,9 +198,9 @@ void beckerport_device::write(offs_t offset, u8 data) update_port -------------------------------------------------*/ -void beckerport_device::update_port(void) +void beckerport_device::update_port() { device_stop(); - m_dwtcpport = m_dwconfigport.read_safe(65504); + m_dwtcpport = m_dwconfigport->read(); device_start(); } diff --git a/src/devices/bus/megadrive/jcart.cpp b/src/devices/bus/megadrive/jcart.cpp index 26c99b2ef5f..4bda9522e9d 100644 --- a/src/devices/bus/megadrive/jcart.cpp +++ b/src/devices/bus/megadrive/jcart.cpp @@ -165,14 +165,14 @@ uint16_t md_jcart_device::read(offs_t offset) if (m_jcart_io_data[0] & 0x40) { - joy[0] = m_jcart3.read_safe(0); - joy[1] = m_jcart4.read_safe(0); + joy[0] = m_jcart3->read(); + joy[1] = m_jcart4->read(); return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); } else { - joy[0] = ((m_jcart3.read_safe(0) & 0xc0) >> 2) | (m_jcart3.read_safe(0) & 0x03); - joy[1] = ((m_jcart4.read_safe(0) & 0xc0) >> 2) | (m_jcart4.read_safe(0) & 0x03); + joy[0] = ((m_jcart3->read() & 0xc0) >> 2) | (m_jcart3->read() & 0x03); + joy[1] = ((m_jcart4->read() & 0xc0) >> 2) | (m_jcart4->read() & 0x03); return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); } } @@ -208,14 +208,14 @@ uint16_t md_seprom_codemast_device::read(offs_t offset) if (m_jcart_io_data[0] & 0x40) { - joy[0] = m_jcart3.read_safe(0); - joy[1] = m_jcart4.read_safe(0); + joy[0] = m_jcart3->read(); + joy[1] = m_jcart4->read(); return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); } else { - joy[0] = ((m_jcart3.read_safe(0) & 0xc0) >> 2) | (m_jcart3.read_safe(0) & 0x03); - joy[1] = ((m_jcart4.read_safe(0) & 0xc0) >> 2) | (m_jcart4.read_safe(0) & 0x03); + joy[0] = ((m_jcart3->read() & 0xc0) >> 2) | (m_jcart3->read() & 0x03); + joy[1] = ((m_jcart4->read() & 0xc0) >> 2) | (m_jcart4->read() & 0x03); return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); } } diff --git a/src/devices/bus/mtx/sdx.cpp b/src/devices/bus/mtx/sdx.cpp index 09e7199ac53..150ff7b6d1a 100644 --- a/src/devices/bus/mtx/sdx.cpp +++ b/src/devices/bus/mtx/sdx.cpp @@ -281,7 +281,7 @@ uint8_t mtx_sdx_device::sdx_status_r() uint8_t data = 0x00; - data |= m_dsw[BIT(m_control, 0)].read_safe(0x0f) & 0x0f; + data |= m_dsw[BIT(m_control, 0)]->read() & 0x0f; data |= (m_floppy0->get_device() && m_floppy1->get_device()) ? 0x10 : 0x00; diff --git a/src/devices/bus/sbus/sbus.cpp b/src/devices/bus/sbus/sbus.cpp index 4dff2c5db9b..01f753f12f5 100644 --- a/src/devices/bus/sbus/sbus.cpp +++ b/src/devices/bus/sbus/sbus.cpp @@ -85,7 +85,7 @@ sbus_device::sbus_device(const machine_config &mconfig, device_type type, const , device_memory_interface(mconfig, *this) , m_space_config("SBus Space", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor()) , m_maincpu(*this, finder_base::DUMMY_TAG) - , m_type1space(*this, finder_base::DUMMY_TAG) + , m_type1space(*this, finder_base::DUMMY_TAG, -1) , m_irq_cb(*this) , m_buserr(*this) { diff --git a/src/devices/bus/sbus/sbus.h b/src/devices/bus/sbus/sbus.h index c6ad513f4ca..2c66318c8aa 100644 --- a/src/devices/bus/sbus/sbus.h +++ b/src/devices/bus/sbus/sbus.h @@ -58,20 +58,18 @@ class sbus_device : public device_t, public: // construction/destruction template <typename T, typename U> - sbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&space_tag) + sbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&space_tag, int space_num) : sbus_device(mconfig, tag, owner, clock) { - set_cpu_tag(std::forward<T>(cpu_tag)); - set_space_tag(std::forward<U>(space_tag)); + set_cpu(std::forward<T>(cpu_tag)); + set_type1space(std::forward<U>(space_tag), space_num); } sbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); // inline configuration - template <typename T> void set_cpu_tag(T &&tag) { m_maincpu.set_tag(std::forward<T>(tag)); } - template <typename T> void set_space_tag(T &&tag) { m_type1space.set_tag(std::forward<T>(tag)); } - - // devcb3 + template <typename T> void set_cpu(T &&tag) { m_maincpu.set_tag(std::forward<T>(tag)); } + template <typename T> void set_type1space(T &&tag, int num) { m_type1space.set_tag(std::forward<T>(tag), num); } template <unsigned Line> auto irq() { return m_irq_cb[Line].bind(); } auto buserr() { return m_buserr.bind(); } @@ -101,7 +99,7 @@ protected: // internal state required_device<sparc_base_device> m_maincpu; - required_device<address_map_bank_device> m_type1space; + required_address_space m_type1space; address_space *m_space; devcb_write_line::array<7> m_irq_cb; diff --git a/src/emu/devfind.h b/src/emu/devfind.h index 36628b2721d..88d47f25aed 100644 --- a/src/emu/devfind.h +++ b/src/emu/devfind.h @@ -836,6 +836,44 @@ protected: template <unsigned Count> using memory_bank_array_creator = object_array_finder<memory_bank_creator, Count>; +/// \brief Base class for optional I/O port finders +/// +/// Adds helpers for to test whether the I/O port was found, and to read +/// the port value or return a default if the I/O port was not found. +template <> +class object_finder_base<ioport_port, false> : public object_finder_common_base<ioport_port, false> +{ +public: + /// \brief Read I/O port if found or return default value + /// + /// If the I/O port was found, this reads a value from the I/O port + /// and returns it. If the I/O port was not found, the default + /// value (supplied as a parameter) is returned. + /// \param [in] defval Value to return if I/O port was not found. + /// \return Value read from I/O port if found, or supplied default + /// value otherwise. + ioport_value read_safe(ioport_value defval) { return this->m_target ? this->m_target->read() : defval; } + + /// \brief Return whether target has been found + /// + /// Works on the assumption that the target object pointer will + /// be non-null if the target has been found, and null + /// otherwise. + /// \return True if object has been found, or false otherwise. + bool found() const { return this->m_target != nullptr; } + + /// \brief Cast-to-Boolean operator + /// + /// Allows truth tests to test whether it's safe to dereference + /// the object, similar to pointers and various C++ standard + /// library objects. + /// \return True if safe to dereference, or false otherwise. + explicit operator bool() const { return this->m_target != nullptr; } + + using object_finder_common_base<ioport_port, false>::object_finder_common_base; +}; + + /// \brief I/O port finder template /// /// Template argument is whether the I/O port is required. It is a @@ -854,16 +892,6 @@ public: /// remains valid until resolution time. ioport_finder(device_t &base, char const *tag); - /// \brief Read I/O port if found or return default value - /// - /// If the I/O port was found, this reads a value from the I/O port - /// and returns it. If the I/O port was not found, the default - /// value (supplied as a parameter) is returned. - /// \param [in] defval Value to return if I/O port was not found. - /// \return Value read from I/O port if found, or supplied default - /// value otherwise. - ioport_value read_safe(ioport_value defval) { return this->m_target ? this->m_target->read() : defval; } - private: /// \brief Find I/O port /// diff --git a/src/mame/drivers/maxaflex.cpp b/src/mame/drivers/maxaflex.cpp index bb7a3d01754..fdc24aa5c5b 100644 --- a/src/mame/drivers/maxaflex.cpp +++ b/src/mame/drivers/maxaflex.cpp @@ -285,12 +285,12 @@ INPUT_PORTS_END uint8_t maxaflex_state::pia_pa_r() { - return atari_input_disabled() ? 0xff : m_joy01.read_safe(0); + return atari_input_disabled() ? 0xff : m_joy01->read(); } uint8_t maxaflex_state::pia_pb_r() { - return atari_input_disabled() ? 0xff : m_joy23.read_safe(0); + return atari_input_disabled() ? 0xff : m_joy23->read(); } diff --git a/src/mame/drivers/meyc8088.cpp b/src/mame/drivers/meyc8088.cpp index ebb3568b920..24c9cbb5068 100644 --- a/src/mame/drivers/meyc8088.cpp +++ b/src/mame/drivers/meyc8088.cpp @@ -244,10 +244,10 @@ uint8_t meyc8088_state::input_r() uint8_t ret = 0xff; // multiplexed switch inputs - if (~m_common & 1) ret &= m_switches[0].read_safe(0); // bit switches - if (~m_common & 2) ret &= m_switches[1].read_safe(0); // control switches - if (~m_common & 4) ret &= m_switches[2].read_safe(0); // light switches - if (~m_common & 8) ret &= m_switches[3].read_safe(0); // light switches + if (~m_common & 1) ret &= m_switches[0]->read(); // bit switches + if (~m_common & 2) ret &= m_switches[1]->read(); // control switches + if (~m_common & 4) ret &= m_switches[2]->read(); // light switches + if (~m_common & 8) ret &= m_switches[3]->read(); // light switches return ret; } diff --git a/src/mame/drivers/sun4.cpp b/src/mame/drivers/sun4.cpp index 713d4d7c6ac..1059bfe3741 100644 --- a/src/mame/drivers/sun4.cpp +++ b/src/mame/drivers/sun4.cpp @@ -1494,7 +1494,7 @@ void sun4c_state::sun4c(machine_config &config) m_maincpu->set_mmu(m_mmu); // SBus - SBUS(config, m_sbus, 20'000'000, "maincpu", "type1"); + SBUS(config, m_sbus, 20'000'000, m_maincpu, m_type1space, 0); m_sbus->irq<0>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ1>)); m_sbus->irq<1>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ2>)); m_sbus->irq<2>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ3>)); diff --git a/src/mame/drivers/topspeed.cpp b/src/mame/drivers/topspeed.cpp index 5550b21e71c..2cd71f6691d 100644 --- a/src/mame/drivers/topspeed.cpp +++ b/src/mame/drivers/topspeed.cpp @@ -192,7 +192,7 @@ u8 topspeed_state::input_bypass_r() { // Read port number const u8 port = m_tc0040ioc->port_r(); - const u16 steer = 0xff80 + m_steer.read_safe(0); + const u16 steer = 0xff80 + m_steer->read(); switch (port) { @@ -209,14 +209,14 @@ u8 topspeed_state::input_bypass_r() CUSTOM_INPUT_MEMBER(topspeed_state::gas_pedal_r) { - static const u8 retval[8] = { 0,1,3,2,6,7,5,4 }; - return retval[m_gas.read_safe(0) & 7]; + static constexpr u8 retval[8] = { 0,1,3,2,6,7,5,4 }; + return retval[m_gas->read() & 7]; } CUSTOM_INPUT_MEMBER(topspeed_state::brake_pedal_r) { - static const u8 retval[8] = { 0,1,3,2,6,7,5,4 }; - return retval[m_brake.read_safe(0) & 7]; + static constexpr u8 retval[8] = { 0,1,3,2,6,7,5,4 }; + return retval[m_brake->read() & 7]; } // TODO: proper motorcpu hook-up diff --git a/src/mame/video/dooyong.h b/src/mame/video/dooyong.h index bc871d94fb3..31846057958 100644 --- a/src/mame/video/dooyong.h +++ b/src/mame/video/dooyong.h @@ -16,7 +16,7 @@ DECLARE_DEVICE_TYPE(DOOYONG_RAM_TILEMAP, dooyong_ram_tilemap_device) class dooyong_tilemap_device_base : public device_t { public: - template <typename T> void set_gfxdecode_tag(T &&cpu_tag) { m_gfxdecode.set_tag(std::forward<T>(cpu_tag)); } + template <typename T> void set_gfxdecode_tag(T &&gfxdecode_tag) { m_gfxdecode.set_tag(std::forward<T>(gfxdecode_tag)); } void set_gfxnum(int gfxnum) { m_gfxnum = gfxnum; } void draw(screen_device &screen, bitmap_ind16 &dest, rectangle const &cliprect, u32 flags, u8 priority, u8 priority_mask = 0xff); |