From 538221861b3fa38da4df2e75c0809e594693beba Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 9 Nov 2020 03:55:50 +1100 Subject: -emu/dirom.{h,ipp}: Cleaned up and made it stricter. * Made it an error to specify address map and explicit ROM region. * Made it an error if explicitly specified ROM region is not found. * Made the ROM region tag apply relative to the current device. -Cleaned up formatting for a couple more documentation pages. --- docs/source/techspecs/device_memory_interface.rst | 170 ++++++++++++++-------- docs/source/techspecs/device_rom_interface.rst | 112 ++++++++------ docs/source/techspecs/memory.rst | 3 + src/emu/dimemory.cpp | 5 +- src/emu/dirom.h | 21 +-- src/emu/dirom.ipp | 62 ++++++-- src/mame/includes/hnayayoi.h | 30 ++-- 7 files changed, 260 insertions(+), 143 deletions(-) diff --git a/docs/source/techspecs/device_memory_interface.rst b/docs/source/techspecs/device_memory_interface.rst index 4efa6a75234..3e9356e2bd6 100644 --- a/docs/source/techspecs/device_memory_interface.rst +++ b/docs/source/techspecs/device_memory_interface.rst @@ -1,18 +1,22 @@ 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 (logically) address/data bus -other devices can be connected to. It's mainly, but not only, cpus. +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 positive values. The IDs should stay small because they -index vectors to keep the lookup fast. Spaces number 0-3 have an -associated constant name: +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 | @@ -26,91 +30,135 @@ associated constant name: | 3 | AS_OPCODES | +----+---------------+ -Spaces 0 and 3, e.g. AS_PROGRAM and AS_OPCODE, are special for the -debugger and some CPUs. AS_PROGRAM is use by the debugger and the -cpus as the space from with the cpu reads its instructions for the -disassembler. When present, AS_OPCODE 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. For the 68000 is -means every instruction word plus the PC-relative accesses. The main, -but not only, use of AS_OPCODE is to implement hardware decrypting -instructions separately from the data. +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 -------- -| std::vector>\ **memory_space_config**\ (int spacenum) const +.. 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 its associated -**address_space_config** describing its configuration. Some examples -to look up when needed: +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_OPCODE: z80_device -* Inherit config and add a space: m6801_device -* Inherit config and patch a space: tmpz84c011_device +* Standard two-space vector: + `v60_device `_ +* Conditional ``AS_OPCODES``: + `z80_device `_ +* Inherit configuration and add a space: m6801_device +* Inherit configuration and modify a space: + `tmpz84c011_device `_ +.. code-block:: C++ -| bool **has_configured_map**\ () const -| bool **has_configured_map**\ (int index) const + 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. -The **has_configured_map** method allows to test in the -**memory_space_config** method whether an **address_map** has been -associated with a given space. That allows to implement optional -memory spaces, such as AS_OPCODES in certain cpu cores. The -parameterless version tests for space 0. 3. Associating maps to spaces ----------------------------- -Associating maps to spaces is done at the machine config level, after the device declaration. +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. -| **MCFG_DEVICE_ADDRESS_MAP**\ (_space, _map) -| **MCFG_DEVICE_PROGRAM_MAP**\ (_map) -| **MCFG_DEVICE_DATA_MAP**\ (_map) -| **MCFG_DEVICE_IO_MAP**\ (_map) -| **MCFG_DEVICE_OPCODES_MAP**\ (_map) +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). -The generic macro and the four specific ones associate a map to a -given space. Address maps associated to non-existing spaces are -ignored (no warning given). devcpu.h defines MCFG_CPU_*_MAP aliases -to the specific macros. +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: -| **MCFG_DEVICE_REMOVE_ADDRESS_MAP**\ (_space) +.. code-block:: C++ -That macro removes a memory map associated to a given space. Useful -when removing a map for an optional space in a machine config -derivative. + 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 ----------------------- -| address_space &\ **space**\ () const -| address_space &\ **space**\ (int index) const +.. code-block:: C++ + + address_space &space(int index = 0) const; -Returns a given address space post-initialization. The parameterless -version tests for AS_PROGRAM/AS_0. Aborts if the space doesn't exist. +Returns the specified address space post-initialization. The specified +address space must exist. -| bool **has_space**\ () const -| bool **has_space**\ (int index) const +.. code-block:: C++ -Indicates whether a given space actually exists. The parameterless -version tests for AS_PROGRAM/AS_0. + bool has_space(int index = 0) const; + +Indicates whether a given space actually exists. 5. MMU support for disassembler ------------------------------- -| bool **translate**\ (int spacenum, int intention, offs_t &address) +.. code-block:: C++ + + bool translate(int spacenum, int intention, offs_t &address); Does a logical to physical address translation through the device's -MMU. spacenum gives the space number, intention the type of the -future access (TRANSLATE_(READ\|WRITE\|FETCH)(\|_USER\|_DEBUG)) and -address is an inout parameter with the address to translate and its -translated version. Should return true if the translation went -correctly, false if the address is unmapped. - -Note that for some historical reason the device itself must override -the virtual method **memory_translate** with the same signature. +MMU. spacenum gives the space number, intention for the type of the +future access (``TRANSLATE_(READ\|WRITE\|FETCH)(\|_USER\|_DEBUG)``) +and address is an in/out parameter holding the address to translate on +entry and the translated version on return. Should return ``true`` if +the translation went correctly, or ``false`` if the address is unmapped. + +Note that for some historical reason, the device itself must override +the virtual method ``memory_translate`` with the same signature. diff --git a/docs/source/techspecs/device_rom_interface.rst b/docs/source/techspecs/device_rom_interface.rst index 366fa763233..4125bc9536a 100644 --- a/docs/source/techspecs/device_rom_interface.rst +++ b/docs/source/techspecs/device_rom_interface.rst @@ -1,89 +1,113 @@ The device_rom_interface ======================== +.. contents:: :local: + + 1. Capabilities --------------- -This interface is designed for devices which expect to have a rom -connected to them on a dedicated bus. It's mostly designed for sound +This interface is designed for devices that expect to have a ROM +connected to them on a dedicated bus. It’s mostly designed for sound chips. Other devices types may be interested but other considerations -may make it impratical (graphics decode caching for instance). The -interface provides the capability of either connecting a ROM_REGION, -connecting an ADDRESS_MAP or dynamically setting up a block of memory -as rom. In the region/block cases, banking is automatically handled. +may make it impractical (graphics decode caching, for instance). The +interface provides the capability to connect a ROM region, connect an +address map, or dynamically set up a block of memory as ROM. In the +region/memory block cases, banking is handled automatically. + 2. Setup -------- -| device_rom_interface +.. code-block:: C++ + + device_rom_interface -The interface is a template that takes the address bus width of the +The interface is a template that takes the address width of the dedicated bus as a parameter. In addition the data bus width (if not -byte), address shift (if not 0) and endianness (if not little endian +byte), address shift (if non-zero) and Endianness (if not little Endian or byte-sized bus) can be provided. Data bus width is 0 for byte, 1 for word, etc. -| **MCFG_DEVICE_ADDRESS_MAP**\ (AS_0, map) +.. code-block:: C++ -Use that method at machine config time to provide an address map for -the bus to connect to. It has priority over a rom region if one is + void set_map(map); + +Use that method at machine configuration time to provide an address map +for the bus to connect to. It has priority over a ROM region if one is also present. -| **MCFG_DEVICE_ROM**\ (tag) +.. code-block:: C++ + + void set_device_rom_tag(tag); + +Used to specify a ROM region to use if a device address map is not +given. Defaults to ``DEVICE_SELF``, i.e. the device’s tag. -Used to select a rom region to use if a device address map is not -given. Defaults to DEVICE_SELF, e.g. the device tag. +.. code-block:: C++ -| **ROM_REGION**\ (length, tag, flags) + ROM_REGION(length, tag, flags) -If a rom region with a tag as given with **MCFG_DEVICE_ROM** if +If a ROM region with the tag specified using ``set_device_rom_tag`` if present, or identical to the device tag otherwise, is provided in the -rom description for the system, it will be automatically picked up as -the connected rom. An address map has priority over the region if -present in the machine config. +ROM definitions for the system, it will be automatically picked up as +the connected ROM. An address map has priority over the region if +present in the machine configuration. -| void **override_address_width**\ (u8 width) +.. code-block:: C++ -This method allows to override the address bus width. It must be + void override_address_width(u8 width); + +This method allows the address bus width to be overridden. It must be called from within the device before **config_complete** time. -| void **set_rom**\ (const void \*base, u32 size); +.. code-block:: C++ + + void set_rom(const void *base, u32 size); -At any time post- **interface_pre_start**, a memory block can be -setup as the connected rom with that method. It overrides any +At any time post-\ ``interface_pre_start``, a memory block can be +set up as the connected ROM with that method. It overrides any previous setup that may have been provided. It can be done multiple times. -3. Rom access + +3. ROM access ------------- -| u8 **read_byte**\ (offs_t byteaddress) -| u16 **read_word**\ (offs_t byteaddress) -| u32 **read_dword**\ (offs_t byteaddress) -| u64 **read_qword**\ (offs_t byteaddress) +.. code-block:: C++ + + u8 read_byte(offs_t addr); + u16 read_word(offs_t addr); + u32 read_dword(offs_t addr); + u64 read_qword(offs_t addr); -These methods provide read access to the connected rom. Out-of-bounds -access results in standard unmapped read logerror messages. +These methods provide read access to the connected ROM. Out-of-bounds +access results in standard unmapped read ``logerror`` messages. -4. Rom banking + +4. ROM banking -------------- -If the rom region or the memory block in set_rom is larger than the -address bus, banking is automatically setup. +If the ROM region or the memory block in ``set_rom`` is larger than the +address bus can access, banking is automatically set up. + +.. code-block:: C++ -| void **set_rom_bank**\ (int bank) + void set_rom_bank(int bank); That method selects the current bank number. + 5. Caveats ---------- Using that interface makes the device derive from -**device_memory_interface**. If the device wants to actually use the -memory interface for itself, remember that AS_0/AS_PROGRAM is used by -the rom interface, and don't forget to upcall **memory_space_config**. - -For devices which have outputs that can be used to address ROMs but -only to forward the data to another device for processing, it may be -helpful to disable the interface when it is not required. This can be -done by overriding **memory_space_config** to return an empty vector. +``device_memory_interface``. If the device wants to actually use the +memory interface for itself, remember that space zero (0, or +``AS_PROGRAM``) is used by the ROM interface, and don’t forget to call +the base ``memory_space_config`` method. + +For devices which have outputs that can be used to address ROMs but only +to forward the data to another device for processing, it may be helpful +to disable the interface when it is not required. This can be done by +overriding ``memory_space_config`` to return an empty vector. diff --git a/docs/source/techspecs/memory.rst b/docs/source/techspecs/memory.rst index e069c02f05b..0b9b24dc7f4 100644 --- a/docs/source/techspecs/memory.rst +++ b/docs/source/techspecs/memory.rst @@ -1,6 +1,9 @@ Emulated system memory and address spaces management ==================================================== +.. contents:: :local: + + 1. Overview ----------- diff --git a/src/emu/dimemory.cpp b/src/emu/dimemory.cpp index 206235a48ce..da6116248ef 100644 --- a/src/emu/dimemory.cpp +++ b/src/emu/dimemory.cpp @@ -50,9 +50,10 @@ device_memory_interface::~device_memory_interface() void device_memory_interface::set_addrmap(int spacenum, address_map_constructor map) { + assert(0 <= spacenum); if (spacenum >= int(m_address_map.size())) - m_address_map.resize(spacenum+1); - m_address_map[spacenum] = map; + m_address_map.resize(spacenum + 1); + m_address_map[spacenum] = std::move(map); } diff --git a/src/emu/dirom.h b/src/emu/dirom.h index c5dd94fedae..8243400c547 100644 --- a/src/emu/dirom.h +++ b/src/emu/dirom.h @@ -7,11 +7,11 @@ Interface to a rom, either through a memory map or a region ***************************************************************************/ +#ifndef MAME_EMU_DIROM_H +#define MAME_EMU_DIROM_H #pragma once -#ifndef MAME_EMU_DIROM_H -#define MAME_EMU_DIROM_H // Beware, DataWidth is 0-3 template class device_rom_interface : public device_memory_interface @@ -20,12 +20,13 @@ public: device_rom_interface(const machine_config &mconfig, device_t &device); virtual ~device_rom_interface() = default; - void set_device_rom_tag(const char *tag) { m_rom_tag = tag; } + template void set_map(T &&... args) { set_addrmap(0, std::forward(args)...); } + template void set_device_rom_tag(T &&tag) { m_rom_region.set_tag(std::forward(tag)); } - inline u8 read_byte(offs_t byteaddress) { return m_rom_cache.read_byte(byteaddress); } - inline u16 read_word(offs_t byteaddress) { return m_rom_cache.read_word(byteaddress); } - inline u32 read_dword(offs_t byteaddress) { return m_rom_cache.read_dword(byteaddress); } - inline u64 read_qword(offs_t byteaddress) { return m_rom_cache.read_qword(byteaddress); } + u8 read_byte(offs_t addr) { return m_rom_cache.read_byte(addr); } + u16 read_word(offs_t addr) { return m_rom_cache.read_word(addr); } + u32 read_dword(offs_t addr) { return m_rom_cache.read_dword(addr); } + u64 read_qword(offs_t addr) { return m_rom_cache.read_qword(addr); } void set_rom(const void *base, u32 size); void set_rom_bank(int bank); @@ -37,14 +38,16 @@ protected: void override_address_width(u8 width); private: - const char *m_rom_tag; + optional_memory_region m_rom_region; address_space_config m_rom_config; typename memory_access::cache m_rom_cache; memory_bank_creator m_bank; - int m_cur_bank, m_bank_count; + u32 m_cur_bank, m_bank_count; + virtual void interface_validity_check(validity_checker &valid) const override; virtual void interface_pre_start() override; + virtual void interface_post_start() override; virtual void interface_post_load() override; }; diff --git a/src/emu/dirom.ipp b/src/emu/dirom.ipp index 42904bf27fd..24697a0fbba 100644 --- a/src/emu/dirom.ipp +++ b/src/emu/dirom.ipp @@ -1,10 +1,14 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert +#ifndef MAME_EMU_DIROM_IPP +#define MAME_EMU_DIROM_IPP + +#pragma once template device_rom_interface::device_rom_interface(const machine_config &mconfig, device_t &device) : device_memory_interface(mconfig, device), - m_rom_tag(device.basetag()), + m_rom_region(device, DEVICE_SELF), m_rom_config("rom", Endian, 8 << DataWidth, AddrWidth, AddrShift), m_bank(device, "bank"), m_cur_bank(-1) @@ -33,7 +37,7 @@ template void device_rom_interface::set_rom_bank(int bank) { if(!m_bank) - emu_fatalerror("%s: device_rom_interface::set_rom_bank called without banking setup", device().tag()); + throw emu_fatalerror("%s: device_rom_interface::set_rom_bank called without banking setup", device().tag()); if(bank >= m_bank_count) { device().logerror("Warning: requested bank %x higher than actual bank count %x\n", bank, m_bank_count); @@ -50,6 +54,8 @@ void device_rom_interface::set_rom_bank template void device_rom_interface::interface_post_load() { + device_memory_interface::interface_post_load(); + if(m_bank) m_bank->set_entry(m_cur_bank); } @@ -57,9 +63,9 @@ void device_rom_interface::interface_po template void device_rom_interface::set_rom(const void *base, u32 size) { - u32 mend = m_rom_config.addr_width() == 32 ? 0xffffffff : (1 << m_rom_config.addr_width()) - 1; - u32 rend = size-1; - m_bank_count = mend == 0xffffffff ? 1 : (rend+1) / (mend+1); + const u32 mend = make_bitmask(m_rom_config.addr_width()); + const u32 rend = size-1; + m_bank_count = (mend == 0xffffffff) ? 1 : (rend+1) / (mend+1); if(m_bank_count < 1) m_bank_count = 1; @@ -85,25 +91,53 @@ void device_rom_interface::set_rom(cons } } +template +void device_rom_interface::interface_validity_check(validity_checker &valid) const +{ + device_memory_interface::interface_validity_check(valid); + + if(has_configured_map(0)) { + const auto rom_target = m_rom_region.finder_target(); + if((&rom_target.first != &device()) || strcmp(rom_target.second, DEVICE_SELF)) + osd_printf_error("Address map and ROM region both specified\n"); + } +} + template void device_rom_interface::interface_pre_start() { + device_memory_interface::interface_pre_start(); + if(!has_space(0)) return; space().cache(m_rom_cache); - device().save_item(NAME(m_cur_bank)); - device().save_item(NAME(m_bank_count)); - if(!has_configured_map(0)) { - memory_region *reg = device().owner()->memregion(m_rom_tag); - if(reg) - set_rom(reg->base(), reg->bytes()); + if(m_rom_region.found()) + set_rom(m_rom_region->base(), m_rom_region->bytes()); else { - device().logerror("ROM region '%s' not found\n", m_rom_tag); - u32 end = m_rom_config.addr_width() == 32 ? 0xffffffff : (1 << m_rom_config.addr_width()) - 1; - space().unmap_read(0, end); + const auto rom_target = m_rom_region.finder_target(); + if((&rom_target.first != &device()) || strcmp(rom_target.second, DEVICE_SELF)) + throw emu_fatalerror("%s: device_rom_interface ROM region '%s' not found", device().tag(), rom_target.first.subtag(rom_target.second)); + + device().logerror("ROM region '%s' not found\n", rom_target.first.subtag(rom_target.second)); + space().unmap_read(0, make_bitmask(m_rom_config.addr_width())); } + } else { + const auto rom_target = m_rom_region.finder_target(); + if((&rom_target.first != &device()) || strcmp(rom_target.second, DEVICE_SELF)) + throw emu_fatalerror("%s: device_rom_interface has configured address map and ROM region", device().tag()); } } + +template +void device_rom_interface::interface_post_start() +{ + device_memory_interface::interface_post_start(); + + device().save_item(NAME(m_cur_bank)); + device().save_item(NAME(m_bank_count)); +} + +#endif // MAME_EMU_DIROM_IPP diff --git a/src/mame/includes/hnayayoi.h b/src/mame/includes/hnayayoi.h index 34d4bea9653..1ebe78e7efa 100644 --- a/src/mame/includes/hnayayoi.h +++ b/src/mame/includes/hnayayoi.h @@ -26,24 +26,34 @@ public: m_palette(*this, "palette") { } - void untoucha(machine_config &config); void hnayayoi(machine_config &config); void hnfubuki(machine_config &config); + void untoucha(machine_config &config); void init_hnfubuki(); +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + private: /* video-related */ std::unique_ptr m_pixmap[8]; int m_palbank; - uint8_t m_blit_layer; - uint16_t m_blit_dest; - uint32_t m_blit_src; + uint8_t m_blit_layer; + uint16_t m_blit_dest; + uint32_t m_blit_src; /* misc */ int m_keyb; bool m_nmi_enable; + required_device m_maincpu; + required_device m_mainlatch; + required_device m_msm; + required_device m_palette; + uint8_t keyboard_0_r(); uint8_t keyboard_1_r(); void keyboard_w(uint8_t data); @@ -55,9 +65,6 @@ private: DECLARE_WRITE_LINE_MEMBER(coin_counter_w); DECLARE_WRITE_LINE_MEMBER(nmi_enable_w); DECLARE_WRITE_LINE_MEMBER(nmi_clock_w); - virtual void machine_start() override; - virtual void machine_reset() override; - virtual void video_start() override; DECLARE_VIDEO_START(untoucha); MC6845_UPDATE_ROW(hnayayoi_update_row); MC6845_UPDATE_ROW(untoucha_update_row); @@ -65,15 +72,12 @@ private: void copy_pixel( int x, int y, int pen ); void draw_layer_interleaved(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t row, uint16_t y, uint8_t x_count, int left_pixmap, int right_pixmap, int palbase, bool transp); DECLARE_WRITE_LINE_MEMBER(irqhandler); - required_device m_maincpu; - required_device m_mainlatch; - required_device m_msm; - required_device m_palette; - void hnayayoi_io_map(address_map &map); + void hnayayoi_map(address_map &map); + void hnayayoi_io_map(address_map &map); void hnfubuki_map(address_map &map); - void untoucha_io_map(address_map &map); void untoucha_map(address_map &map); + void untoucha_io_map(address_map &map); }; #endif // MAME_INCLUDES_HNAYAYOI_H -- cgit v1.2.3