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<std::pair<int,constaddress_space_config*>>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 <https://git.redump.net/mame/tree/src/devices/cpu/v60/v60.cpp?h=mame0226>`_* Conditional ``AS_OPCODES``:
`z80_device <https://git.redump.net/mame/tree/src/devices/cpu/z80/z80.cpp?h=mame0226>`_* Inherit configuration and add a space:
`hd647180x_device <https://git.redump.net/mame/tree/src/devices/cpu/z180/hd647180x.cpp?h=mame0226>`_* Inherit configuration and modify a space:
`tmpz84c011_device <https://git.redump.net/mame/tree/src/devices/cpu/z80/tmpz84c011.cpp?h=mame0226>`_..code-block::C++boolhas_configured_map(intindex=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++voidset_addrmap(intspacenum,T&obj,Ret(U::*func)(Params...));voidset_addrmap(intspacenum,Ret(T::*func)(Params...));voidset_addrmap(intspacenum,address_map_constructormap);
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++classhnayayoi_state:publicdriver_device{public:voidhnayayoi(machine_config&config);voidhnfubuki(machine_config&config);private:
required_device<cpu_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(intindex=0)const;
Returns the specified address space post-initialization. The specified
address space must exist.
..code-block::C++boolhas_space(intindex=0)const;
Indicates whether a given space actually exists.
5. MMU support for disassembler
-------------------------------
..code-block::C++booltranslate(intspacenum,intintention,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.