summaryrefslogtreecommitdiffstatshomepage
path: root/docs/source/techspecs/object_finders.rst
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-11-13 15:26:31 +1100
committer Vas Crabb <vas@vastheman.com>2020-11-13 15:26:31 +1100
commitfe9ac15ca9f027d0eb5e21aa5496e3d6fa674e45 (patch)
treeb48da30d7948f1e251b3f468de3fa7f3405d2a29 /docs/source/techspecs/object_finders.rst
parent52285c255363d1f431eee95f0e8d01b546c33d48 (diff)
-emu/devfind: More cleanup/consistency changes.
* Removed .mask(), as it’s not reliable in the general case. * Added asserts to things that assume power-of-two sizes. * Got rid of virtual qualifier on pointer-to-member operator. * Made helpers a bit more assertive about logging warnings. -emu/rendlay.cpp: Use delegates to avoid hot conditional branches. -docs: Finished off description of object finders and output finders.
Diffstat (limited to 'docs/source/techspecs/object_finders.rst')
-rw-r--r--docs/source/techspecs/object_finders.rst375
1 files changed, 366 insertions, 9 deletions
diff --git a/docs/source/techspecs/object_finders.rst b/docs/source/techspecs/object_finders.rst
index 1acb475a7fa..2256d74b677 100644
--- a/docs/source/techspecs/object_finders.rst
+++ b/docs/source/techspecs/object_finders.rst
@@ -515,10 +515,10 @@ object finder to access it. We’ll use the Sega X-board device as an example:
{
}
- optional_device<z80_device> m_soundcpu;
- optional_device<z80_device> m_soundcpu2;
- required_device<mb3773_device> m_watchdog;
- required_device<segaic16_video_device> m_segaic16vid;
+ optional_device<z80_device> m_soundcpu;
+ optional_device<z80_device> m_soundcpu2;
+ required_device<mb3773_device> m_watchdog;
+ required_device<segaic16_video_device> m_segaic16vid;
bool m_adc_reverse[8];
u8 m_pc_0;
u8 m_lastsurv_mux;
@@ -564,7 +564,7 @@ otherwise:
return value;
}
- uint8_t segaxbd_state::lastsurv_port_r()
+ u8 segaxbd_state::lastsurv_port_r()
{
return m_mux_ports[m_lastsurv_mux].read_safe(0xff);
}
@@ -611,17 +611,17 @@ functions for configuring them:
public:
vboy_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
- template <typename T> void set_exp(T &&tag, int no, offs_t base)
+ template <typename T> void set_exp(T &&tag, int no, offs_t base)
{
m_exp_space.set_tag(std::forward<T>(tag), no);
m_exp_base = base;
}
- template <typename T> void set_chip(T &&tag, int no, offs_t base)
+ template <typename T> void set_chip(T &&tag, int no, offs_t base)
{
m_chip_space.set_tag(std::forward<T>(tag), no);
m_chip_base = base;
}
- template <typename T> void set_rom(T &&tag, int no, offs_t base)
+ template <typename T> void set_rom(T &&tag, int no, offs_t base)
{
m_rom_space.set_tag(std::forward<T>(tag), no);
m_rom_base = base;
@@ -638,7 +638,7 @@ functions for configuring them:
offs_t m_chip_base;
offs_t m_rom_base;
- device_vboy_cart_interface *m_cart;
+ device_vboy_cart_interface *m_cart;
};
DECLARE_DEVICE_TYPE(VBOY_CART_SLOT, vboy_cart_slot_device)
@@ -680,3 +680,360 @@ have been configured but aren’t present:
m_cart = get_card_device();
}
+
+
+Object finder types in more detail
+----------------------------------
+
+All object finders provide configuration functionality:
+
+.. code-block:: C++
+
+ char const *finder_tag() const { return m_tag; }
+ std::pair<device_t &, char const *> finder_target();
+ void set_tag(device_t &base, char const *tag);
+ void set_tag(char const *tag);
+ void set_tag(finder_base const &finder);
+
+The ``finder_tag`` and ``finder_target`` member function provides access to the
+currently configured target. Note that the tag returned by ``finder`` tag is
+relative to the base device. It is not sufficient on its own to identify the
+target.
+
+The ``set_tag`` member functions configure the target of the object finder.
+These members must not be called after the object finder is resolved. The first
+form configures the base device and relative tag. The second form sets the
+relative tag and also implicitly sets the base device to the device that is
+currently being configured. This form must only be called from machine
+configuration functions. The third form sets the base object and relative tag
+to the current target of another object finder.
+
+Note that the ``set_tag`` member functions **do not** copy the relative tag. It
+is the caller’s responsibility to ensure the C string remains valid until the
+object finder is resolved (or reconfigured with a different tag). The base
+device must also be valid at resolution time. This may not be the case if the
+device could be removed or replaced later.
+
+All object finders provide the same interface for accessing the target object:
+
+.. code-block:: C++
+
+ ObjectClass *target() const;
+ operator ObjectClass *() const;
+ ObjectClass *operator->() const;
+
+These members all provide access to the target object. The ``target`` member
+function and cast-to-pointer operator will return ``nullptr`` if the target has
+not been found. The pointer member access operator asserts that the target has
+been found.
+
+Optional object finders additionally provide members for testing whether the
+target object has been found:
+
+.. code-block:: C++
+
+ bool found() const;
+ explicit operator bool() const;
+
+These members return ``true`` if the target was found, on the assumption
+that the target pointer will be non-null if the target was found.
+
+Device finders
+~~~~~~~~~~~~~~
+
+Device finders require one template argument for the expected device class.
+This should derive from either ``device_t`` or ``device_interface``. The target
+device object must either be an instance of this class, an instance of a class
+that derives from it. A warning message is logged if a matching device is found
+but it is not an instance of the expected class.
+
+Device finders provide an additional ``set_tag`` overload:
+
+.. code-block:: C++
+
+ set_tag(DeviceClass &object);
+
+This is equivalent to calling ``set_tag(object, DEVICE_SELF)``. Note that the
+device object must not be removed or replaced before the object finder is
+resolved.
+
+Memory system object finders
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The memory system object finders, ``required_memory_region``,
+``optional_memory_region``, ``required_memory_bank``, ``optional_memory_bank``
+and ``memory_bank_creator``, do not have any special functionality. They are
+often used in place of literal tags when installing memory banks in an address
+space.
+
+Example using memory bank finders in an address map:
+
+.. code-block:: C++
+
+ class qvt70_state : public driver_device
+ {
+ public:
+ qvt70_state(machine_config const &mconfig, device_type type, char const *tag) :
+ driver_device(mconfig, type, tag),
+ m_rombank(*this, "rom"),
+ m_rambank(*this, "ram%d", 0U),
+ { }
+
+ private:
+ required_memory_bank m_rombank;
+ required_memory_bank_array<2> m_rambank;
+
+ void mem_map(address_map &map);
+
+ void rombank_w(u8 data);
+ };
+
+ void qvt70_state::mem_map(address_map &map)
+ {
+ map(0x0000, 0x7fff).bankr(m_rombank);
+ map(0x8000, 0x8000).w(FUNC(qvt70_state::rombank_w));
+ map(0xa000, 0xbfff).ram();
+ map(0xc000, 0xdfff).bankrw(m_rambank[0]);
+ map(0xe000, 0xffff).bankrw(m_rambank[1]);
+ }
+
+Example using a memory bank creator to install a memory bank dynamically:
+
+.. code-block:: C++
+
+ class vegaeo_state : public eolith_state
+ {
+ public:
+ vegaeo_state(machine_config const &mconfig, device_type type, char const *tag) :
+ eolith_state(mconfig, type, tag),
+ m_qs1000_bank(*this, "qs1000_bank")
+ {
+ }
+
+ void init_vegaeo();
+
+ private:
+ memory_bank_creator m_qs1000_bank;
+ };
+
+ void vegaeo_state::init_vegaeo()
+ {
+ // Set up the QS1000 program ROM banking, taking care not to overlap the internal RAM
+ m_qs1000->cpu().space(AS_IO).install_read_bank(0x0100, 0xffff, m_qs1000_bank);
+ m_qs1000_bank->configure_entries(0, 8, memregion("qs1000:cpu")->base() + 0x100, 0x10000);
+
+ init_speedup();
+ }
+
+I/O port finders
+~~~~~~~~~~~~~~~~
+
+Optional I/O port finders provide an additional convenience member function:
+
+.. code-block:: C++
+
+ ioport_value read_safe(ioport_value defval);
+
+This will read the port’s value if the target I/O port was found, or return
+``defval`` otherwise. It is useful in situations where certain input devices
+are not always present.
+
+
+Address space finders
+~~~~~~~~~~~~~~~~~~~~~
+
+Address space finders accept an additional argument for the address space number
+to find. A required data width can optionally be supplied to the constructor.
+
+.. code-block:: C++
+
+ address_space_finder(device_t &base, char const *tag, int spacenum, u8 width = 0);
+ void set_tag(device_t &base, char const *tag, int spacenum);
+ void set_tag(char const *tag, int spacenum);
+ void set_tag(finder_base const &finder, int spacenum);
+ template <bool R> void set_tag(address_space_finder<R> const &finder);
+
+The base device and tag must identify a device that implements
+``device_memory_interface``. The address space number is a zero-based index to
+one of the device’s address spaces.
+
+If the width is non-zero, it must match the target address space’s data width in
+bits. If the target address space exists but has a different data width, a
+warning message will be logged, and it will be treated as not being found. If
+the width is zero (the default argument value), the target address space’s data
+width won’t be checked.
+
+Member functions are also provided to get the configured address space number
+and set the required data width:
+
+.. code-block:: C++
+
+ int spacenum() const;
+ void set_data_width(u8 width);
+
+Memory pointer finders
+~~~~~~~~~~~~~~~~~~~~~~
+
+The memory pointer finders, ``required_region_ptr``, ``optional_region_ptr``,
+``required_shared_ptr``, ``optional_shared_ptr`` and ``memory_share_creator``,
+all require one template argument for the element type of the memory area. This
+should usually be an explicitly-sized unsigned integer type (``u8``, ``u16``,
+``u32`` or ``u64``). The size of this type is compared to the width of the
+memory area. If it doesn’t match, a warning message is logged and the region or
+share is treated as not being found.
+
+The memory pointer finders provide an array access operator, and members for
+accessing the size of the memory area:
+
+.. code-block:: C++
+
+ PointerType &operator[](int index) const;
+ size_t length() const;
+ size_t bytes() const;
+
+The array access operator returns a non-\ ``const`` reference to an element of
+the memory area. The index is in units of the element type; it must be
+non-negative and less than the length of the memory area. The ``length`` member
+returns the number of elements in the memory area. The ``bytes`` member returns
+the size of the memory area in bytes. These members should not be called if the
+target region/share has not been found.
+
+The ``memory_share_creator`` requires additional constructor arguments for the
+size and Endianness of the memory share:
+
+.. code-block:: C++
+
+ memory_share_creator(device_t &base, char const *tag, size_t bytes, endianness_t endianness);
+
+The size is specified in bytes. If an existing memory share is found, it is an
+error if its size does not match the specified size. If the width is wider than
+eight bits and an existing memory share is found, it is an error if its
+Endianness does not match the specified Endianness.
+
+The ``memory_share_creator`` provides additional members for accessing
+properties of the memory share:
+
+.. code-block:: C++
+
+ endianness_t endianness() const;
+ u8 bitwidth() const;
+ u8 bytewidth() const;
+
+These members return the Endianness, width in bits and width in bytes of the
+memory share, respectively. They must not be called if the memory share has not
+been found.
+
+
+Output finders
+--------------
+
+Output finders are used for exposing outputs that can be used by the artwork
+system, or by external programs. A common application using an external program
+is a control panel or cabinet lighting controller.
+
+Output finders are not really object finders, but they’re described here because
+they’re used in a similar way. There are a number of important differences to
+be aware of:
+
+* Output finders always create outputs if they do not exist.
+* Output finders must be manually resolved, they are not automatically resolved.
+* Output finders cannot have their target changed after construction.
+* Output finders are array-like, and support an arbitrary number of dimensions.
+* Output names are global, the base device has no influence. (This will change
+ in the future.)
+
+Output finders take a variable number of template arguments corresponding to the
+number of array dimensions you want. Let’s look at an example that uses zero-,
+one- and two-dimensional output finders:
+
+.. code-block:: C++
+
+ class mmd2_state : public driver_device
+ {
+ public:
+ mmd2_state(machine_config const &mconfig, device_type type, char const *tag) :
+ driver_device(mconfig, type, tag),
+ m_digits(*this, "digit%u", 0U),
+ m_p(*this, "p%u_%u", 0U, 0U),
+ m_led_halt(*this, "led_halt"),
+ m_led_hold(*this, "led_hold")
+ { }
+
+ protected:
+ virtual void machine_start() override;
+
+ private:
+ void round_leds_w(offs_t, u8);
+ void digit_w(u8 data);
+ void status_callback(u8 data);
+
+ u8 m_digit;
+
+ output_finder<9> m_digits;
+ output_finder<3, 8> m_p;
+ output_finder<> m_led_halt;
+ output_finder<> m_led_hold;
+ };
+
+The ``m_led_halt`` and ``m_led_hold`` members are zero-dimensional output
+finders. They find a single output each. The ``m_digits`` member is a
+one-dimensional output finder. It finds nine outputs organised as a
+single-dimensional array. The ``m_p`` member is a two-dimensional output
+finder. It finds 24 outputs organised as three rows of eight columns each.
+Larger numbers of dimensions are supported.
+
+The output finder constructor takes a base device reference, a format string,
+and an index offset for each dimension. In this case, all the offsets are
+zero. The one-dimensional output finder ``m_digits`` will find outputs
+``digit0``, ``digit1``, ``digit2``, … ``digit8``. The two-dimensional output
+finder ``m_p`` will find the outputs ``p0_0``, ``p0_1``, … ``p0_7`` for the
+first row, ``p1_0``, ``p1_1``, … ``p1_7`` for the second row, and ``p2_0``,
+``p2_1``, … ``p2_7`` for the third row.
+
+You must call ``resolve`` on each output finder before it can be used. This
+should be done at start time for the output values to be included in save
+states:
+
+.. code-block:: C++
+
+ void mmd2_state::machine_start()
+ {
+ m_digits.resolve();
+ m_p.resolve();
+ m_led_halt.resolve();
+ m_led_hold.resolve();
+
+ save_item(NAME(m_digit));
+ }
+
+Output finders provide operators allowing them to be assigned from or cast to
+32-bit signed integers. The assignment operator will send a notification if the
+new value is different to the output’s current value.
+
+.. code-block:: C++
+
+ operator s32() const;
+ s32 operator=(s32 value);
+
+To set output values, assign through the output finders, as you would with an
+array of the same rank:
+
+.. code-block:: C++
+
+ void mmd2_state::round_leds_w(offs_t offset, u8 data)
+ {
+ for (u8 i = 0; i < 8; i++)
+ m_p[offset][i] = BIT(~data, i);
+ }
+
+ void mmd2_state::digit_w(u8 data)
+ {
+ if (m_digit < 9)
+ m_digits[m_digit] = data;
+ }
+
+ void mmd2_state::status_callback(u8 data)
+ {
+ m_led_halt = (~data & i8080_cpu_device::STATUS_HLTA) ? 1 : 0;
+ m_led_hold = (data & i8080_cpu_device::STATUS_WO) ? 1 : 0;
+ }