text/html; charset=UTF-8 Last-Modified: Sat, 03 May 2025 18:50:34 GMT Expires: Tue, 01 May 2035 18:50:34 GMT mame - MAME - Multiple Arcade Machine Emulator
summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/devices/machine/i8155.cpp3
-rw-r--r--src/mame/drivers/mcb216.cpp18
-rw-r--r--src/mame/drivers/mccpm.cpp103
-rw-r--r--src/mame/drivers/mice.cpp96
-rw-r--r--src/mame/drivers/pimps.cpp2
5 files changed, 106 insertions, 116 deletions
diff --git a/src/devices/machine/i8155.cpp b/src/devices/machine/i8155.cpp
index 721575f1468..fcb44bafe30 100644
--- a/src/devices/machine/i8155.cpp
+++ b/src/devices/machine/i8155.cpp
@@ -460,7 +460,8 @@ void i8155_device::register_w(int offset, uint8_t data)
{
// load mode and CNT length and start immediately after loading (if timer is not running)
m_counter = m_count_length & 0x3fff;
- m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
+ if (clock() > 0) // a clock of 0 causes MAME to freeze.
+ m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
// clear timer command so this won't execute twice
m_command &= ~COMMAND_TM_MASK;
diff --git a/src/mame/drivers/mcb216.cpp b/src/mame/drivers/mcb216.cpp
index 0190e2b4100..ded1dc04ba9 100644
--- a/src/mame/drivers/mcb216.cpp
+++ b/src/mame/drivers/mcb216.cpp
@@ -9,7 +9,7 @@
TODO:
- Find out cpu clock speed
- - Find out what UART type is used
+ - Find out what UART type is used (init byte = 94)
Memory allocation
- 0000 to 0FFF - standard roms
@@ -36,17 +36,15 @@
#include "cpu/z80/z80.h"
#include "machine/terminal.h"
-#define TERMINAL_TAG "terminal"
class mcb216_state : public driver_device
{
public:
mcb216_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_terminal(*this, TERMINAL_TAG)
- {
- }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_terminal(*this, "terminal")
+ { }
void kbd_put(u8 data);
DECLARE_READ8_MEMBER(keyin_r);
@@ -70,7 +68,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START(mcb216_io, AS_IO, 8, mcb216_state)
ADDRESS_MAP_GLOBAL_MASK(0xff)
AM_RANGE(0x00, 0x00) AM_READ(status_r)
- AM_RANGE(0x01, 0x01) AM_READ(keyin_r) AM_DEVWRITE(TERMINAL_TAG, generic_terminal_device, write)
+ AM_RANGE(0x01, 0x01) AM_READ(keyin_r) AM_DEVWRITE("terminal", generic_terminal_device, write)
ADDRESS_MAP_END
static ADDRESS_MAP_START(cb308_mem, AS_PROGRAM, 8, mcb216_state)
@@ -123,7 +121,7 @@ static MACHINE_CONFIG_START( mcb216 )
MCFG_MACHINE_RESET_OVERRIDE(mcb216_state, mcb216)
/* video hardware */
- MCFG_DEVICE_ADD(TERMINAL_TAG, GENERIC_TERMINAL, 0)
+ MCFG_DEVICE_ADD("terminal", GENERIC_TERMINAL, 0)
MCFG_GENERIC_TERMINAL_KEYBOARD_CB(PUT(mcb216_state, kbd_put))
MACHINE_CONFIG_END
@@ -135,7 +133,7 @@ static MACHINE_CONFIG_START( cb308 )
MCFG_MACHINE_RESET_OVERRIDE(mcb216_state, cb308)
/* video hardware */
- MCFG_DEVICE_ADD(TERMINAL_TAG, GENERIC_TERMINAL, 0)
+ MCFG_DEVICE_ADD("terminal", GENERIC_TERMINAL, 0)
MCFG_GENERIC_TERMINAL_KEYBOARD_CB(PUT(mcb216_state, kbd_put))
MACHINE_CONFIG_END
diff --git a/src/mame/drivers/mccpm.cpp b/src/mame/drivers/mccpm.cpp
index 03003623456..a56ba8a2002 100644
--- a/src/mame/drivers/mccpm.cpp
+++ b/src/mame/drivers/mccpm.cpp
@@ -19,93 +19,51 @@ Z - print 'EFFF'
URL for v3.4: http://www.hanshehl.de/mc-prog.htm (German language)
-I/O ports (my guess)
+unknown I/O ports (my guess)
30 - fdc (1st drive)
40 - fdc (2nd drive)
-F0 - terminal in/out
-F1 - terminal status
-
-SIO? - F0 to F3
-PIO A-Data 0F4h, A-Command 0F5h, B-Data 0F6h, B-Command 0F7h
-
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 01 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 00 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 03 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = E1 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 04 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 4C & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = 05 & FF
-'maincpu' (F59C): unmapped i/o memory write to 00F1 = EA & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 01 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 00 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 03 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = E1 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 04 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 4C & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = 05 & FF
-'maincpu' (F5A5): unmapped i/o memory write to 00F3 = EA & FF
-'maincpu' (F5A9): unmapped i/o memory write to 00F5 = CF & FF
-'maincpu' (F5AD): unmapped i/o memory write to 00F5 = 7F & FF
-'maincpu' (F5B1): unmapped i/o memory write to 00F7 = CF & FF
-'maincpu' (F5B4): unmapped i/o memory write to 00F7 = 00 & FF
-'maincpu' (F149): unmapped i/o memory write to 0040 = D0 & FF
-'maincpu' (F14B): unmapped i/o memory write to 0030 = D0 & FF
+
****************************************************************************/
#include "emu.h"
#include "cpu/z80/z80.h"
-#include "machine/terminal.h"
+#include "machine/z80pio.h"
+#include "machine/z80sio.h"
+#include "machine/clock.h"
+#include "bus/rs232/rs232.h"
-#define TERMINAL_TAG "terminal"
class mccpm_state : public driver_device
{
public:
mccpm_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_terminal(*this, TERMINAL_TAG),
- m_p_ram(*this, "p_ram")
- {
- }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_p_ram(*this, "ram")
+ , m_sio(*this, "sio")
+ { }
+
+ DECLARE_WRITE_LINE_MEMBER(clock_tick);
+private:
+ virtual void machine_reset() override;
required_device<cpu_device> m_maincpu;
- required_device<generic_terminal_device> m_terminal;
- DECLARE_READ8_MEMBER(mccpm_f0_r);
- DECLARE_READ8_MEMBER(mccpm_f1_r);
- void kbd_put(u8 data);
required_shared_ptr<uint8_t> m_p_ram;
- uint8_t m_term_data;
- virtual void machine_reset() override;
+ required_device<z80sio_device> m_sio;
};
-
-READ8_MEMBER( mccpm_state::mccpm_f0_r )
-{
- uint8_t ret = m_term_data;
- m_term_data = 0;
- return ret;
-}
-
-// bit 0 - key pressed
-// bit 2 - ready to send to terminal
-READ8_MEMBER( mccpm_state::mccpm_f1_r )
-{
- return (m_term_data) ? 5 : 4;
-}
-
static ADDRESS_MAP_START(mccpm_mem, AS_PROGRAM, 8, mccpm_state)
ADDRESS_MAP_UNMAP_HIGH
- AM_RANGE(0x0000, 0xffff) AM_RAM AM_SHARE("p_ram")
+ AM_RANGE(0x0000, 0xffff) AM_RAM AM_SHARE("ram")
ADDRESS_MAP_END
static ADDRESS_MAP_START( mccpm_io, AS_IO, 8, mccpm_state)
ADDRESS_MAP_UNMAP_HIGH
ADDRESS_MAP_GLOBAL_MASK(0xff)
- AM_RANGE(0xf0, 0xf0) AM_READ(mccpm_f0_r) AM_DEVWRITE(TERMINAL_TAG, generic_terminal_device, write)
- AM_RANGE(0xf1, 0xf1) AM_READ(mccpm_f1_r)
+ AM_RANGE(0xf0, 0xf3) AM_DEVREADWRITE("sio", z80sio_device, ba_cd_r, ba_cd_w)
+ AM_RANGE(0xf4, 0xf7) AM_DEVREADWRITE("pio", z80pio_device, read_alt, write_alt) // init bytes look like those for a Z80PIO
ADDRESS_MAP_END
/* Input ports */
@@ -119,9 +77,10 @@ void mccpm_state::machine_reset()
memcpy(m_p_ram, bios, 0x1000);
}
-void mccpm_state::kbd_put(u8 data)
+WRITE_LINE_MEMBER( mccpm_state::clock_tick )
{
- m_term_data = data;
+ m_sio->txca_w(state);
+ m_sio->rxca_w(state);
}
static MACHINE_CONFIG_START( mccpm )
@@ -130,9 +89,21 @@ static MACHINE_CONFIG_START( mccpm )
MCFG_CPU_PROGRAM_MAP(mccpm_mem)
MCFG_CPU_IO_MAP(mccpm_io)
- /* video hardware */
- MCFG_DEVICE_ADD(TERMINAL_TAG, GENERIC_TERMINAL, 0)
- MCFG_GENERIC_TERMINAL_KEYBOARD_CB(PUT(mccpm_state, kbd_put))
+ /* Devices */
+ MCFG_DEVICE_ADD("uart_clock", CLOCK, 153600)
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(mccpm_state, clock_tick))
+
+ MCFG_Z80SIO_ADD("sio", XTAL_4MHz, 0, 0, 0, 0)
+ MCFG_Z80SIO_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0))
+ MCFG_Z80SIO_OUT_TXDA_CB(DEVWRITELINE("rs232", rs232_port_device, write_txd))
+ MCFG_Z80SIO_OUT_DTRA_CB(DEVWRITELINE("rs232", rs232_port_device, write_dtr))
+ MCFG_Z80SIO_OUT_RTSA_CB(DEVWRITELINE("rs232", rs232_port_device, write_rts))
+
+ MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, "terminal")
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("sio", z80sio_device, rxa_w))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("sio", z80sio_device, ctsa_w))
+
+ MCFG_DEVICE_ADD("pio", Z80PIO, XTAL_4MHz)
MACHINE_CONFIG_END
/* ROM definition */
diff --git a/src/mame/drivers/mice.cpp b/src/mame/drivers/mice.cpp
index 61661a6965a..d03c0959df4 100644
--- a/src/mame/drivers/mice.cpp
+++ b/src/mame/drivers/mice.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Miodrag Milanovic, Robbbert
/***************************************************************************
-Microtek International Inc MICE
+Microtek International Inc MICE (Micro-In-Circuit Emulator)
2013-08-27 Skeleton driver.
@@ -13,61 +13,59 @@ Each CPU has a plugin card with various chips. The usual complement is
The
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria,Aaron Giles,Vas Crabb
/*********************************************************************

    romload.h

    ROM loading functions.

*********************************************************************/

#ifndef MAME_EMU_ROMLOAD_H
#define MAME_EMU_ROMLOAD_H

#pragma once

#include "chd.h"

#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <vector>


/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/


/***************************************************************************
    MACROS
***************************************************************************/

template <typename T> inline std::enable_if_t<!std::is_pointer<T>::value, T const &> ROMENTRY_UNWRAP(T const &r) { return r; }
template <typename T> inline T const &ROMENTRY_UNWRAP(T const *r) { return *r; }

/* ----- per-entry macros ----- */
template <typename T> inline u32  ROMENTRY_GETTYPE(T const &r)         { return ROMENTRY_UNWRAP(r).get_flags() & ROMENTRY_TYPEMASK; }
template <typename T> inline bool ROMENTRY_ISSPECIAL(T const &r)       { return ROMENTRY_GETTYPE(r) != ROMENTRYTYPE_ROM; }
template <typename T> inline bool ROMENTRY_ISFILE(T const &r)          { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_ROM; }
template <typename T> inline bool ROMENTRY_ISREGION(T const &r)        { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_REGION; }
template <typename T> inline bool ROMENTRY_ISEND(T const &r)           { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_END; }
template <typename T> inline bool ROMENTRY_ISRELOAD(T const &r)        { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_RELOAD; }
template <typename T> inline bool ROMENTRY_ISCONTINUE(T const &r)      { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_CONTINUE; }
template <typename T> inline bool ROMENTRY_ISFILL(T const &r)          { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_FILL; }
template <typename T> inline bool ROMENTRY_ISCOPY(T const &r)          { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_COPY; }
template <typename T> inline bool ROMENTRY_ISIGNORE(T const &r)        { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_IGNORE; }
template <typename T> inline bool ROMENTRY_ISSYSTEM_BIOS(T const &r)   { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_SYSTEM_BIOS; }
template <typename T> inline bool ROMENTRY_ISDEFAULT_BIOS(T const &r)  { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_DEFAULT_BIOS; }
template <typename T> inline bool ROMENTRY_ISPARAMETER(T const &r)     { return ROMENTRY_GETTYPE(r) == ROMENTRYTYPE_PARAMETER; }
template <typename T> inline bool ROMENTRY_ISREGIONEND(T const &r)     { return ROMENTRY_ISREGION(r) || ROMENTRY_ISPARAMETER(r) || ROMENTRY_ISEND(r); }

/* ----- per-region macros ----- */
template <typename T> inline u32  ROMREGION_GETLENGTH(T const &r)      { return ROMENTRY_UNWRAP(r).get_length(); }
template <typename T> inline u32  ROMREGION_GETFLAGS(T const &r)       { return ROMENTRY_UNWRAP(r).get_flags(); }
template <typename T> inline u32  ROMREGION_GETWIDTH(T const &r)       { return 8 << ((ROMREGION_GETFLAGS(r) & ROMREGION_WIDTHMASK) >> 8); }
template <typename T> inline bool ROMREGION_ISLITTLEENDIAN(T const &r) { return (ROMREGION_GETFLAGS(r) & ROMREGION_ENDIANMASK) == ROMREGION_LE; }
template <typename T> inline bool ROMREGION_ISBIGENDIAN(T const &r)    { return (ROMREGION_GETFLAGS(r) & ROMREGION_ENDIANMASK) == ROMREGION_BE; }
template <typename T> inline bool ROMREGION_ISINVERTED(T const &r)     { return (ROMREGION_GETFLAGS(r) & ROMREGION_INVERTMASK) == ROMREGION_INVERT; }
template <typename T> inline bool ROMREGION_ISERASE(T const &r)        { return (ROMREGION_GETFLAGS(r) & ROMREGION_ERASEMASK) == ROMREGION_ERASE; }
template <typename T> inline u32  ROMREGION_GETERASEVAL(T const &r)    { return (ROMREGION_GETFLAGS(r) & ROMREGION_ERASEVALMASK) >> 16; }
template <typename T> inline u32  ROMREGION_GETDATATYPE(T const &r)    { return ROMREGION_GETFLAGS(r) & ROMREGION_DATATYPEMASK; }
template <typename T> inline bool ROMREGION_ISROMDATA(T const &r)      { return ROMREGION_GETDATATYPE(r) == ROMREGION_DATATYPEROM; }
template <typename T> inline bool ROMREGION_ISDISKDATA(T const &r)     { return ROMREGION_GETDATATYPE(r) == ROMREGION_DATATYPEDISK; }


/* ----- per-ROM macros ----- */
#define ROM_GETNAME(r)              ((r)->name().c_str())
#define ROM_SAFEGETNAME(r)          (ROMENTRY_ISFILL(r) ? "fill" : ROMENTRY_ISCOPY(r) ? "copy" : ROM_GETNAME(r))
template <typename T> inline u32  ROM_GETOFFSET(T const &r)            { return ROMENTRY_UNWRAP(r).get_offset(); }
template <typename T> inline u32  ROM_GETLENGTH(T const &r)            { return ROMENTRY_UNWRAP(r).get_length(); }
template <typename T> inline u32  ROM_GETFLAGS(T const &r)             { return ROMENTRY_UNWRAP(r).get_flags(); }
template <typename T> inline bool ROM_ISOPTIONAL(T const &r)           { return (ROM_GETFLAGS(r) & ROM_OPTIONALMASK) == ROM_OPTIONAL; }
template <typename T> inline u32  ROM_GETGROUPSIZE(T const &r)         { return ((ROM_GETFLAGS(r) & ROM_GROUPMASK) >> 8) + 1; }
template <typename T> inline u32  ROM_GETSKIPCOUNT(T const &r)         { return (ROM_GETFLAGS(r) & ROM_SKIPMASK) >> 12; }
template <typename T> inline bool ROM_ISREVERSED(T const &r)           { return (ROM_GETFLAGS(r) & ROM_REVERSEMASK) == ROM_REVERSE; }
template <typename T> inline u32  ROM_GETBITWIDTH(T const &r)          { return (ROM_GETFLAGS(r) & ROM_BITWIDTHMASK) ? ((ROM_GETFLAGS(r) & ROM_BITWIDTHMASK) >> 16) : 8; }
template <typename T> inline u32  ROM_GETBITSHIFT(T const &r)          { return (ROM_GETFLAGS(r) & ROM_BITSHIFTMASK) >> 20; }
template <typename T> inline bool ROM_INHERITSFLAGS(T const &r)        { return (ROM_GETFLAGS(r) & ROM_INHERITFLAGSMASK) == ROM_INHERITFLAGS; }
template <typename T> inline u32  ROM_GETBIOSFLAGS(T const &r)         { return (ROM_GETFLAGS(r) & ROM_BIOSFLAGSMASK) >> 24; }


/* ----- per-disk macros ----- */
template <typename T> inline u32  DISK_GETINDEX(T const &r)            { return ROMENTRY_UNWRAP(r).get_offset(); }
template <typename T> inline bool DISK_ISREADONLY(T const &r)          { return (ROM_GETFLAGS(r) & DISK_READONLYMASK) == DISK_READONLY; }


namespace romload {

template <typename T>
class const_entry_iterator
{
protected:
	tiny_rom_entry const *m_data;

	constexpr const_entry_iterator() noexcept : m_data(nullptr) { }
	constexpr const_entry_iterator(tiny_rom_entry const *data) noexcept : m_data(data) { }
	constexpr const_entry_iterator(const_entry_iterator const &) noexcept = default;
	const_entry_iterator(const_entry_iterator &&) noexcept = default;
	const_entry_iterator &operator=(const_entry_iterator const &) noexcept = default;
	const_entry_iterator &operator=(const_entry_iterator &&) noexcept = default;

public:
	using value_type = T;
	using pointer = value_type const *;
	using reference = value_type const &;
	using difference_type = std::ptrdiff_t;
	using iterator_category = std::forward_iterator_tag;

	reference operator*() const noexcept { return reinterpret_cast<reference>(*m_data); }
	pointer operator->() const noexcept { return reinterpret_cast<pointer>(m_data); }
};


class file final : tiny_rom_entry
{
private:
	file() = default;
	file(file const &) = delete;
	file &operator=(file const &) = delete;

public:
	// ROM
	constexpr char const *get_name()       const { return name; }
	constexpr u32         get_offset()     const { return offset; }
	constexpr u32         get_length()     const { return length; }
	constexpr u32         get_flags()      const { return flags; }
	constexpr char const *get_hashdata()   const { return hashdata; }
	constexpr bool        is_optional()    const { return (flags & ROM_OPTIONALMASK) == ROM_OPTIONAL; }
	constexpr u32         get_groupsize()  const { return ((flags & ROM_GROUPMASK) >> 8) + 1; }
	constexpr u32         get_skipcount()  const { return (flags & ROM_SKIPMASK) >> 12; }
	constexpr bool        is_reversed()    const { return (flags & ROM_REVERSEMASK) == ROM_REVERSE; }
	constexpr u32         get_bitwidth()   const { return (flags & ROM_BITWIDTHMASK) ? ((flags & ROM_BITWIDTHMASK) >> 16) : 8; }
	constexpr u32         get_bitshift()   const { return (flags & ROM_BITSHIFTMASK) >> 20; }
	constexpr bool        inherits_flags() const { return (flags & ROM_INHERITFLAGSMASK) == ROM_INHERITFLAGS; }
	constexpr u32         get_bios_flags() const { return (flags & ROM_BIOSFLAGSMASK) >> 24; }

	// disk
	constexpr u32         get_index()      const { return offset; }
	constexpr bool        is_readonly()    const { return (flags & DISK_READONLYMASK) == DISK_READONLY; }
};

class files
{
private:
	tiny_rom_entry const *m_data;

public:
	class const_iterator : public const_entry_iterator<file>
	{
	private:
		friend class files;

		constexpr const_iterator(tiny_rom_entry const *data) noexcept : const_entry_iterator<file>(data) { }

	public:
		constexpr const_iterator() noexcept = default;
		constexpr const_iterator(const_iterator const &) noexcept = default;
		const_iterator(const_iterator &&) noexcept = default;
		const_iterator &operator=(const_iterator const &) noexcept = default;
		const_iterator &operator=(const_iterator &&) noexcept = default;

		const_iterator &operator++() noexcept
		{
			while (m_data)
			{
				++m_data;
				if (ROMENTRY_ISFILE(m_data))
					break;
				else if (ROMENTRY_ISREGIONEND(m_data))
					m_data = nullptr;
			}
			return *this;
		}

		const_iterator operator++(int) noexcept { const_iterator result(*this); operator++(); return result; }

		constexpr bool operator==(const_iterator const &rhs) const noexcept { return m_data == rhs.m_data; }
		constexpr bool operator!=(const_iterator const &rhs) const noexcept { return m_data != rhs.m_data; }
	};

	files(tiny_rom_entry const *data) : m_data(data)
	{
		while (m_data && !ROMENTRY_ISFILE(m_data))
		{
			if (ROMENTRY_ISREGIONEND(m_data))
				m_data = nullptr;
			else
				++m_data;
		}
	}

	const_iterator begin() const { return const_iterator(m_data); }
	const_iterator cbegin() const { return const_iterator(m_data); }
	const_iterator end() const { return const_iterator(nullptr); }
	const_iterator cend() const { return const_iterator(nullptr); }
};


class region final : tiny_rom_entry
{
private:
	region() = default;
	region(region const &) = delete;
	region &operator=(region const &) = delete;

public:
	constexpr char const *get_tag()         const { return name; }
	constexpr u32         get_length()      const { return length; }
	constexpr u32         get_width()       const { return 8 << ((flags & ROMREGION_WIDTHMASK) >> 8); }
	constexpr bool        is_littleendian() const { return (flags & ROMREGION_ENDIANMASK) == ROMREGION_LE; }
	constexpr bool        is_bigendian()    const { return (flags & ROMREGION_ENDIANMASK) == ROMREGION_BE; }
	constexpr bool        is_inverted()     const { return (flags & ROMREGION_INVERTMASK) == ROMREGION_INVERT; }
	constexpr bool        is_erase()        const { return (flags & ROMREGION_ERASEMASK) == ROMREGION_ERASE; }
	constexpr u32         get_eraseval()    const { return (flags & ROMREGION_ERASEVALMASK) >> 16; }
	constexpr u32         get_datatype()    const { return flags & ROMREGION_DATATYPEMASK; }
	constexpr bool        is_romdata()      const { return get_datatype() == ROMREGION_DATATYPEROM; }
	constexpr bool        is_diskdata()     const { return get_datatype() == ROMREGION_DATATYPEDISK; }

	files get_files() const { return files(static_cast<tiny_rom_entry const *>(this) + 1); }
};

class regions
{
private:
	tiny_rom_entry const *m_data;

public:
	class const_iterator : public const_entry_iterator<region>
	{
	private:
		friend class regions;

		constexpr const_iterator(tiny_rom_entry const *data) noexcept : const_entry_iterator<region>(data) { }

	public:
		constexpr const_iterator() noexcept = default;
		constexpr const_iterator(const_iterator const &) noexcept = default;
		const_iterator(const_iterator &&) noexcept = default;
		const_iterator &operator=(const_iterator const &) noexcept = default;
		const_iterator &operator=(const_iterator &&) noexcept = default;

		const_iterator &operator++() noexcept
		{
			while (m_data)
			{
				++m_data;
				if (ROMENTRY_ISREGION(m_data))
					break;
				else if (ROMENTRY_ISEND(m_data))
					m_data = nullptr;
			}
			return *this;
		}

		const_iterator operator++(int) noexcept { const_iterator result(*this); operator++(); return result; }

		constexpr bool operator==(const_iterator const &rhs) const noexcept { return m_data == rhs.m_data; }
		constexpr bool operator!=(const_iterator const &rhs) const noexcept { return m_data != rhs.m_data; }
	};

	regions(tiny_rom_entry const *data) : m_data(data)
	{
		while (m_data && !ROMENTRY_ISREGION(m_data))
		{
			if (ROMENTRY_ISEND(m_data))
				m_data = nullptr;
			else
				++m_data;
		}
	}

	const_iterator begin() const { return const_iterator(m_data); }
	const_iterator cbegin() const { return const_iterator(m_data); }
	const_iterator end() const { return const_iterator(nullptr); }
	const_iterator cend() const { return const_iterator(nullptr); }
};


class system_bios final : tiny_rom_entry
{
private:
	system_bios() = default;
	system_bios(system_bios const &) = delete;
	system_bios &operator=(system_bios const &) = delete;

public:
	constexpr u32         get_value()       const { return (flags & ROM_BIOSFLAGSMASK) >> 24; }
	constexpr char const *get_name()        const { return name; }
	constexpr char const *get_description() const { return hashdata; }
};

class system_bioses
{
private:
	tiny_rom_entry const *m_data;

public:
	class const_iterator : public const_entry_iterator<system_bios>
	{
	private:
		friend class system_bioses;

		constexpr const_iterator(tiny_rom_entry const *data) noexcept : const_entry_iterator<system_bios>(data) { }

	public:
		constexpr const_iterator() noexcept = default;
		constexpr const_iterator(const_iterator const &) noexcept = default;
		const_iterator(const_iterator &&) noexcept = default;
		const_iterator &operator=(const_iterator const &) noexcept = default;
		const_iterator &operator=(const_iterator &&) noexcept = default;

		const_iterator &operator++() noexcept
		{
			while (m_data)
			{
				++m_data;
				if (ROMENTRY_ISSYSTEM_BIOS(m_data))
					break;
				else if (ROMENTRY_ISEND(m_data))
					m_data = nullptr;
			}
			return *this;
		}

		const_iterator operator++(int) noexcept { const_iterator result(*this); operator++(); return result; }

		constexpr bool operator==(const_iterator const &rhs) const noexcept { return m_data == rhs.m_data; }
		constexpr bool operator!=(const_iterator const &rhs) const noexcept { return m_data != rhs.m_data; }
	};

	system_bioses(tiny_rom_entry const *data) : m_data(data)
	{
		while (m_data && !ROMENTRY_ISSYSTEM_BIOS(m_data))
		{
			if (ROMENTRY_ISEND(m_data))
				m_data = nullptr;
			else
				++m_data;
		}
	}

	const_iterator begin() const { return const_iterator(m_data); }
	const_iterator cbegin() const { return const_iterator(m_data); }
	const_iterator end() const { return const_iterator(nullptr); }
	const_iterator cend() const { return const_iterator(nullptr); }
};


class default_bios final : tiny_rom_entry
{
private:
	default_bios() = default;
	default_bios(default_bios const &) = delete;
	default_bios &operator=(default_bios const &) = delete;

public:
	constexpr char const *get_name() const { return name; }
};


class entries
{
private:
	tiny_rom_entry const *m_data;

public:
	constexpr entries(tiny_rom_entry const *data) : m_data(data) { }

	regions get_regions() const { return regions(m_data); }
	system_bioses get_system_bioses() const { return system_bioses(m_data); }
};

} // namespace romload


/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/

// ======================> rom_load_manager

class rom_load_manager
{
	class open_chd
	{
	public:
		open_chd(std::string_view region) : m_region(region) { }
		open_chd(std::string &&region) : m_region(std::move(region)) { }

		std::string_view region() const { return m_region; }
		chd_file &chd() { return m_diffchd.opened() ? m_diffchd : m_origchd; }
		chd_file &orig_chd() { return m_origchd; }
		chd_file &diff_chd() { return m_diffchd; }

	private:
		std::string m_region;   // disk region we came from
		chd_file    m_origchd;  // handle to the original CHD
		chd_file    m_diffchd;  // handle to the diff CHD
	};

public:
	// construction/destruction
	rom_load_manager(running_machine &machine);

	// getters
	running_machine &machine() const { return m_machine; }

	/* return the number of warnings we generated */
	int warnings() const { return m_warnings; }

	std::string& software_load_warnings_message() { return m_softwarningstring; }

	/* return the number of BAD_DUMP/NO_DUMP warnings we generated */
	int knownbad() const { return m_knownbad; }

	/* ----- disk handling ----- */

	/* return a pointer to the CHD file associated with the given region */
	chd_file *get_disk_handle(std::string_view region);

	/* set a pointer to the CHD file associated with the given region */
	std::error_condition set_disk_handle(std::string_view region, std::string_view fullpath);

	void load_software_part_region(device_t &device, software_list_device &swlist, std::string_view swname, const rom_entry *start_region);

	/* get search path for a software item */
	static std::vector<std::string> get_software_searchpath(software_list_device &swlist, const software_info &swinfo);

	/* open a disk image, searching up the parent and loading by checksum */
	static std::error_condition open_disk_image(emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd);
	static std::error_condition open_disk_image(emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd);

private:
	using search_paths = std::initializer_list<std::reference_wrapper<const std::vector<std::string> > >;

	void determine_bios_rom(device_t &device, std::string_view specbios);
	void count_roms();
	void fill_random(u8 *base, u32 length);
	void handle_missing_file(const rom_entry *romp, const std::vector<std::string> &tried_file_names, std::error_condition chderr);
	void dump_wrong_and_correct_checksums(const util::hash_collection &hashes, const util::hash_collection &acthashes);
	void verify_length_and_hash(emu_file *file, std::string_view name, u32 explength, const util::hash_collection &hashes);
	void display_loading_rom_message(const char *name, bool from_list);
	void display_rom_load_results(bool from_list);
	void region_post_process(memory_region *region, bool invert);
	std::unique_ptr<emu_file> open_rom_file(
			const std::vector<std::string> &searchpath,
			const rom_entry *romp,
			std::vector<std::string> &tried_file_names,
			bool from_list);
	std::unique_ptr<emu_file> open_rom_file(
			const std::vector<std::string> &paths,
			std::vector<std::string> &tried,
			bool has_crc,
			u32 crc,
			std::string_view name,
			std::error_condition &filerr);
	int rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region);
	int read_rom_data(emu_file *file, memory_region &region, const rom_entry *parent_region, const rom_entry *romp);
	void fill_rom_data(memory_region &region, const rom_entry *romp);
	void copy_rom_data(device_t &device, memory_region &region, const rom_entry *romp);
	void process_rom_entries(
			device_t &device,
			const std::vector<std::string> &searchpath,
			u8 bios,
			memory_region &region,
			const rom_entry *parent_region,
			const rom_entry *romp,
			bool from_list);
	std::error_condition open_disk_diff(
			emu_options &options,
			const rom_entry *romp,
			chd_file &source,
			chd_file &diff_chd);
	void process_disk_entries(
			search_paths searchpath,
			std::string_view regiontag,
			const rom_entry *romp,
			std::function<const rom_entry * ()> next_parent,
			const chd_file::open_parent_func &open_parent);
	void normalize_flags_for_device(std::string_view rgntag, u8 &width, endianness_t &endian);
	void process_region_list();

	// internal state
	running_machine &   m_machine;            // reference to our machine

	int                 m_warnings;           // warning count during processing
	int                 m_knownbad;           // BAD_DUMP/NO_DUMP count during processing
	int                 m_errors;             // error count during processing

	int                 m_romsloaded;         // current ROMs loaded count
	int                 m_romstotal;          // total number of ROMs to read
	u64                 m_romsloadedsize;     // total size of ROMs loaded so far
	u64                 m_romstotalsize;      // total size of ROMs to read

	std::vector<std::unique_ptr<open_chd>> m_chd_list;     /* disks */

	std::string         m_errorstring;        // error string
	std::string         m_softwarningstring;  // software warning string
};


/* ----- Helpers ----- */

/* return pointer to the first ROM region within a source */
const rom_entry *rom_first_region(const device_t &device);
const rom_entry *rom_first_region(const rom_entry *romp);

/* return pointer to the next ROM region within a source */
const rom_entry *rom_next_region(const rom_entry *romp);

/* return pointer to the first ROM file within a region */
const rom_entry *rom_first_file(const rom_entry *romp);

/* return pointer to the next ROM file within a region */
const rom_entry *rom_next_file(const rom_entry *romp);

/* return the expected size of a file given the ROM description */
u32 rom_file_size(const rom_entry *romp);

/* return pointer to the first per-game parameter */
const rom_entry *rom_first_parameter(const device_t &device);

/* return pointer to the next per-game parameter */
const rom_entry *rom_next_parameter(const rom_entry *romp);

// builds a rom_entry vector from a tiny_rom_entry array
std::vector<rom_entry> rom_build_entries(const tiny_rom_entry *tinyentries);

#endif  // MAME_EMU_ROMLOAD_H