The device_memory_interface =========================== .. contents:: :local: 1. Capabilities --------------- The device memory interface provides devices with the capability of creating address spaces, to which address maps can be associated. It’s used for any device that provides a (logical) address/data bus that other devices can be connected to. That’s mainly, but not solely, CPUs. The interface allows for an unlimited set of address spaces, numbered with small, non-negative values. The IDs index vectors, so they should stay small to keep the lookup fast. Spaces numbered 0-3 have associated constant name: +----+---------------+ | ID | Name | +====+===============+ | 0 | AS_PROGRAM | +----+---------------+ | 1 | AS_DATA | +----+---------------+ | 2 | AS_IO | +----+---------------+ | 3 | AS_OPCODES | +----+---------------+ Spaces 0 and 3, i.e. ``AS_PROGRAM`` and ``AS_OPCODES``, are special for the debugger and some CPUs. ``AS_PROGRAM`` is use by the debugger and the CPUs as the space from which the CPU reads its instructions for the disassembler. When present, ``AS_OPCODES`` is used by the debugger and some CPUs to read the opcode part of the instruction. What opcode means is device-dependant, for instance for the Z80 it's the initial byte(s) which are read with the M1 signal asserted, while for the 68000 is means every instruction word plus PC-relative accesses. The main, but not only, use of ``AS_OPCODES`` is to implement hardware decryption of instructions separately from data. 2. Setup -------- .. code-block:: C++ std::vector> memory_space_config() const; The device must override that method to provide a vector of pairs comprising of a space number and an associated ``address_space_config`` describing its configuration. Some examples to look up when needed: * Standard two-space vector: `v60_device `_ * Conditional ``AS_OPCODES``: `z80_device `_ * Inherit configuration and add a space: `hd647180x_device `_ * Inherit configuration and modify a space: `tmpz84c011_device `_ .. code-block:: C++ bool has_configured_map(int index = 0) const; The ``has_configured_map`` method allows to test whether an ``address_map`` has been associated with a given space in the ``memory_space_config`` method . That allows optional memory spaces to be implemented, such as ``AS_OPCODES`` in certain CPU cores. 3. Associating maps to spaces ----------------------------- Associating maps to spaces is done at the machine configuration level, after the device is instantiated. .. code-block:: C++ void set_addrmap(int spacenum, T &obj, Ret (U::*func)(Params...)); void set_addrmap(int spacenum, Ret (T::*func)(Params...)); void set_addrmap(int spacenum, address_map_constructor map); These function associate a map with a given space. Address maps associated with non-existent spaces are ignored (no warning given). The first form takes a reference to an object and a method to call on that object. The second form takes a method to call on the current device being configured. The third form takes an ``address_map_constructor`` to copy. In each case, the function must be callable with reference to an ``address_map`` object as an argument. To remove a previously configured address map, call ``set_addrmap`` with a default-constructed ``address_map_constructor`` (useful for removing a map for an optional space in a derived machine configuration). As an example, here’s the address map configuration for the main CPU in the Hana Yayoi and Hana Fubuki machines, with all distractions removed: .. code-block:: C++ class hnayayoi_state : public driver_device { public: void hnayayoi(machine_config &config); void hnfubuki(machine_config &config); private: required_device m_maincpu; void hnayayoi_map(address_map &map); void hnayayoi_io_map(address_map &map); void hnfubuki_map(address_map &map); }; void hnayayoi_state::hnayayoi(machine_config &config) { Z80(config, m_maincpu, 20000000/4); m_maincpu->set_addrmap(AS_PROGRAM, &hnayayoi_state::hnayayoi_map); m_maincpu->set_addrmap(AS_IO, &hnayayoi_state::hnayayoi_io_map); } void hnayayoi_state::hnfubuki(machine_config &config) { hnayayoi(config); m_maincpu->set_addrmap(AS_PROGRAM, &hnayayoi_state::hnfubuki_map); m_maincpu->set_addrmap(AS_IO, address_map_constructor()); } 4. Accessing the spaces ----------------------- .. code-block:: C++ address_space &space(int index = 0) const; Returns the specified address space post-initialization. The specified address space must exist. .. code-block:: C++ bool has_space(int index = 0) const; Indicates whether a given space actually exists. 5. MMU support for disassembler ------------------------------- .. code-block:: C++ bool translate(int spacenum, int intention, offs_t &address, address_space *&target_space); Does a logical to physical address translation through the device's MMU. spacenum gives the space number, intention for the type of the future access (``TR_(READ\|WRITE\|FETCH)``), address is an in/out parameter holding the address to translate on entry and the translated version on return, and finally target_space is the actual space the access would end up in, which may be in a different device. Should return ``true`` if the translation went correctly, or ``false`` if the address is unmapped. The call must not change the state of the device. Note that for some historical reason, the device itself must override the virtual method ``memory_translate`` with the same signature.