summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/addrmap.cpp3
-rw-r--r--src/emu/addrmap.h114
-rw-r--r--src/emu/attotime.cpp8
-rw-r--r--src/emu/attotime.h9
-rw-r--r--src/emu/bookkeeping.cpp2
-rw-r--r--src/emu/config.cpp186
-rw-r--r--src/emu/config.h34
-rw-r--r--src/emu/crsshair.cpp1
-rw-r--r--src/emu/debug/debugbuf.cpp43
-rw-r--r--src/emu/debug/debugcmd.cpp1650
-rw-r--r--src/emu/debug/debugcmd.h191
-rw-r--r--src/emu/debug/debugcon.cpp758
-rw-r--r--src/emu/debug/debugcon.h70
-rw-r--r--src/emu/debug/debugcpu.cpp418
-rw-r--r--src/emu/debug/debugcpu.h73
-rw-r--r--src/emu/debug/debughlp.cpp235
-rw-r--r--src/emu/debug/debughlp.h2
-rw-r--r--src/emu/debug/debugvw.cpp4
-rw-r--r--src/emu/debug/dvbpoints.cpp2
-rw-r--r--src/emu/debug/dvmemory.cpp82
-rw-r--r--src/emu/debug/dvmemory.h1
-rw-r--r--src/emu/debug/dvrpoints.cpp2
-rw-r--r--src/emu/debug/express.cpp42
-rw-r--r--src/emu/debug/express.h25
-rw-r--r--src/emu/debug/points.cpp255
-rw-r--r--src/emu/debug/points.h54
-rw-r--r--src/emu/devcb.cpp8
-rw-r--r--src/emu/devcb.h520
-rw-r--r--src/emu/devcpu.cpp56
-rw-r--r--src/emu/devcpu.h19
-rw-r--r--src/emu/devdelegate.h292
-rw-r--r--src/emu/devfind.cpp34
-rw-r--r--src/emu/devfind.h105
-rw-r--r--src/emu/device.cpp102
-rw-r--r--src/emu/device.h91
-rw-r--r--src/emu/device.ipp9
-rw-r--r--src/emu/diexec.cpp37
-rw-r--r--src/emu/diexec.h18
-rw-r--r--src/emu/diimage.cpp668
-rw-r--r--src/emu/diimage.h224
-rw-r--r--src/emu/dimemory.cpp3
-rw-r--r--src/emu/dimemory.h39
-rw-r--r--src/emu/dinetwork.cpp89
-rw-r--r--src/emu/dinetwork.h42
-rw-r--r--src/emu/dinvram.cpp3
-rw-r--r--src/emu/dinvram.h21
-rw-r--r--src/emu/dipalette.h16
-rw-r--r--src/emu/dipty.h2
-rw-r--r--src/emu/dirom.h5
-rw-r--r--src/emu/dirom.ipp9
-rw-r--r--src/emu/dirtc.cpp6
-rw-r--r--src/emu/dirtc.h7
-rw-r--r--src/emu/diserial.cpp40
-rw-r--r--src/emu/diserial.h8
-rw-r--r--src/emu/dislot.cpp50
-rw-r--r--src/emu/dislot.h20
-rw-r--r--src/emu/distate.cpp16
-rw-r--r--src/emu/distate.h17
-rw-r--r--src/emu/divtlb.cpp31
-rw-r--r--src/emu/divtlb.h57
-rw-r--r--src/emu/drawgfxt.ipp33
-rw-r--r--src/emu/driver.cpp46
-rw-r--r--src/emu/driver.h31
-rw-r--r--src/emu/drivers/empty.cpp5
-rw-r--r--src/emu/drivers/testcpu.cpp4
-rw-r--r--src/emu/emu.h15
-rw-r--r--src/emu/emucore.cpp4
-rw-r--r--src/emu/emucore.h121
-rw-r--r--src/emu/emufwd.h38
-rw-r--r--src/emu/emumem.cpp58
-rw-r--r--src/emu/emumem.h883
-rw-r--r--src/emu/emumem_aspace.cpp492
-rw-r--r--src/emu/emumem_hea.h4
-rw-r--r--src/emu/emumem_hedp.cpp60
-rw-r--r--src/emu/emumem_hedp.h16
-rw-r--r--src/emu/emumem_hedr.h4
-rw-r--r--src/emu/emumem_hedr.ipp83
-rw-r--r--src/emu/emumem_hedw.h4
-rw-r--r--src/emu/emumem_hedw.ipp79
-rw-r--r--src/emu/emumem_hem.cpp60
-rw-r--r--src/emu/emumem_hem.h16
-rw-r--r--src/emu/emumem_hep.h16
-rw-r--r--src/emu/emumem_het.cpp35
-rw-r--r--src/emu/emumem_het.h16
-rw-r--r--src/emu/emumem_heu.cpp76
-rw-r--r--src/emu/emumem_heu.h8
-rw-r--r--src/emu/emumem_heun.cpp75
-rw-r--r--src/emu/emumem_heun.h16
-rw-r--r--src/emu/emumem_hws.cpp311
-rw-r--r--src/emu/emumem_hws.h162
-rw-r--r--src/emu/emumem_mud.cpp4
-rw-r--r--src/emu/emumem_mud.h2
-rw-r--r--src/emu/emumem_mview.cpp440
-rw-r--r--src/emu/emuopts.cpp396
-rw-r--r--src/emu/emuopts.h3
-rw-r--r--src/emu/emupal.h8
-rw-r--r--src/emu/fileio.cpp41
-rw-r--r--src/emu/fileio.h4
-rw-r--r--src/emu/gamedrv.h239
-rw-r--r--src/emu/hashfile.cpp1
-rw-r--r--src/emu/http.cpp29
-rw-r--r--src/emu/http.h13
-rw-r--r--src/emu/image.cpp47
-rw-r--r--src/emu/image.h2
-rw-r--r--src/emu/inpttype.h353
-rw-r--r--src/emu/inpttype.ipp1228
-rw-r--r--src/emu/input.cpp466
-rw-r--r--src/emu/input.h925
-rw-r--r--src/emu/inputdev.cpp229
-rw-r--r--src/emu/inputdev.h58
-rw-r--r--src/emu/ioport.cpp767
-rw-r--r--src/emu/ioport.h475
-rw-r--r--src/emu/layout/dualhovu.lay2
-rw-r--r--src/emu/layout/dualhsxs.lay2
-rw-r--r--src/emu/layout/dualhuov.lay2
-rw-r--r--src/emu/layout/ex800.lay2
-rw-r--r--src/emu/layout/exorterm155.lay2
-rw-r--r--src/emu/layout/generic.h3
-rw-r--r--src/emu/layout/hp9122c.lay2
-rw-r--r--src/emu/layout/ie15.lay2
-rw-r--r--src/emu/layout/lx800.lay2
-rw-r--r--src/emu/layout/monitors.lay41
-rw-r--r--src/emu/layout/nes_rob.lay64
-rw-r--r--src/emu/layout/noscreens.lay6
-rw-r--r--src/emu/layout/quadhsxs.lay2
-rw-r--r--src/emu/layout/qx10ascii.lay98
-rw-r--r--src/emu/layout/qx10hasci.lay86
-rw-r--r--src/emu/layout/smartboard.lay75
-rw-r--r--src/emu/layout/triphsxs.lay2
-rw-r--r--src/emu/machine.cpp160
-rw-r--r--src/emu/machine.h21
-rw-r--r--src/emu/main.cpp19
-rw-r--r--src/emu/main.h24
-rw-r--r--src/emu/mconfig.cpp21
-rw-r--r--src/emu/mconfig.h2
-rw-r--r--src/emu/memarray.cpp9
-rw-r--r--src/emu/memarray.h2
-rw-r--r--src/emu/natkeyboard.cpp13
-rw-r--r--src/emu/natkeyboard.h7
-rw-r--r--src/emu/network.cpp13
-rw-r--r--src/emu/profiler.cpp10
-rw-r--r--src/emu/profiler.h114
-rw-r--r--src/emu/recording.cpp13
-rw-r--r--src/emu/render.cpp696
-rw-r--r--src/emu/render.h69
-rw-r--r--src/emu/rendersw.hxx17
-rw-r--r--src/emu/rendertypes.h10
-rw-r--r--src/emu/rendfont.cpp304
-rw-r--r--src/emu/rendfont.h8
-rw-r--r--src/emu/rendlay.cpp313
-rw-r--r--src/emu/rendlay.h96
-rw-r--r--src/emu/rendutil.cpp410
-rw-r--r--src/emu/rendutil.h19
-rw-r--r--src/emu/romentry.h23
-rw-r--r--src/emu/romload.cpp548
-rw-r--r--src/emu/romload.h72
-rw-r--r--src/emu/save.cpp56
-rw-r--r--src/emu/save.h8
-rw-r--r--src/emu/schedule.cpp521
-rw-r--r--src/emu/schedule.h87
-rw-r--r--src/emu/screen.cpp243
-rw-r--r--src/emu/screen.h38
-rw-r--r--src/emu/softlist.cpp3
-rw-r--r--src/emu/softlist_dev.cpp24
-rw-r--r--src/emu/softlist_dev.h10
-rw-r--r--src/emu/sound.cpp147
-rw-r--r--src/emu/sound.h12
-rw-r--r--src/emu/speaker.cpp61
-rw-r--r--src/emu/speaker.h13
-rw-r--r--src/emu/tilemap.cpp48
-rw-r--r--src/emu/ui/uimain.h4
-rw-r--r--src/emu/uiinput.cpp268
-rw-r--r--src/emu/uiinput.h88
-rw-r--r--src/emu/validity.cpp215
-rw-r--r--src/emu/validity.h3
-rw-r--r--src/emu/video.cpp152
-rw-r--r--src/emu/video.h4
-rw-r--r--src/emu/video/resnet.h2
-rw-r--r--src/emu/video/rgbgen.h68
-rw-r--r--src/emu/video/rgbvmx.cpp2
-rw-r--r--src/emu/video/rgbvmx.h102
-rw-r--r--src/emu/xtal.cpp39
182 files changed, 11895 insertions, 9158 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp
index 8a6294e7279..81e91457e71 100644
--- a/src/emu/addrmap.cpp
+++ b/src/emu/addrmap.cpp
@@ -42,6 +42,9 @@ address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t
, m_share(nullptr)
, m_region(nullptr)
, m_rgnoffs(0)
+ , m_before_time(device)
+ , m_before_delay(device)
+ , m_after_delay(device)
, m_rproto8(device)
, m_rproto16(device)
, m_rproto32(device)
diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h
index 69e4a9ab8b7..7d350c14afd 100644
--- a/src/emu/addrmap.h
+++ b/src/emu/addrmap.h
@@ -71,13 +71,6 @@ class address_map_entry
{
friend class address_map;
- template <typename T, typename Ret, typename... Params>
- using is_addrmap_method = std::bool_constant<std::is_constructible_v<address_map_constructor, Ret (T::*)(Params...), const char *, T *> >;
-
- template <typename T, typename Ret, typename... Params>
- static std::enable_if_t<is_addrmap_method<T, Ret, Params...>::value, address_map_constructor> make_delegate(Ret (T::*func)(Params...), const char *name, T *obj)
- { return address_map_constructor(func, name, obj); }
-
template <typename T, bool Reqd>
static device_t &find_device(const device_finder<T, Reqd> &finder) {
const std::pair<device_t &, const char *> target(finder.finder_target());
@@ -212,109 +205,157 @@ public:
// view initialization
void view(memory_view &mv);
+
+ // wait-states, implicit base -> delegate converter
+ template <typename T>
+ address_map_entry &before_time(u64 (T::*ws)(offs_t, u64), const char *name)
+ { m_before_time = ws_time_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; }
+
+ template <typename T>
+ address_map_entry &before_delay(u32 (T::*ws)(offs_t), const char *name)
+ { m_before_delay = ws_delay_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; }
+
+ template <typename T>
+ address_map_entry &after_delay(u32 (T::*ws)(offs_t), const char *name)
+ { m_after_delay = ws_delay_delegate(*make_pointer<T>(m_devbase), ws, name); return *this; }
+
+ // wait-states, device tag -> delegate converter
+ template <typename T>
+ address_map_entry &before_time(const char *tag, u64 (T::*ws)(offs_t, u64), const char *name)
+ { m_before_time = ws_time_delegate(m_devbase, tag, ws, name); return *this; }
+
+ template <typename T>
+ address_map_entry &before_delay(const char *tag, u32 (T::*ws)(offs_t), const char *name)
+ { m_before_delay = ws_delay_delegate(m_devbase, tag, ws, name); return *this; }
+
+ template <typename T>
+ address_map_entry &after_delay(const char *tag, u32 (T::*ws)(offs_t), const char *name)
+ { m_after_delay = ws_delay_delegate(m_devbase, tag, ws, name); return *this; }
+
+ // wait-states, device reference -> delegate converter
+ template <typename T, typename U>
+ address_map_entry &before_time(T &obj, u64 (U::*ws)(offs_t, u64), const char *name)
+ { m_before_time = ws_time_delegate(obj, ws, name); return *this; }
+
+ template <typename T, typename U>
+ address_map_entry &before_delay(T &obj, u32 (U::*ws)(offs_t), const char *name)
+ { m_before_delay = ws_delay_delegate(obj, ws, name); return *this; }
+
+ template <typename T, typename U>
+ address_map_entry &after_delay(T &obj, u32 (U::*ws)(offs_t), const char *name)
+ { m_after_delay = ws_delay_delegate(obj, ws, name); return *this; }
+
+ // wait-states, lambda -> delegate converter
+ template <typename T>
+ address_map_entry &before_time(T &&ws, const char *name)
+ { m_before_time = ws_time_delegate(m_devbase, std::forward<T>(ws), name); return *this; }
+
+ template <typename T>
+ address_map_entry &before_delay(T &&ws, const char *name)
+ { m_before_delay = ws_delay_delegate(m_devbase, std::forward<T>(ws), name); return *this; }
+
+ template <typename T>
+ address_map_entry &after_delay(T &&ws, const char *name)
+ { m_after_delay = ws_delay_delegate(m_devbase, std::forward<T>(ws), name); return *this; }
+
+
// implicit base -> delegate converter
template <typename T, typename Ret, typename... Params>
address_map_entry &r(Ret (T::*read)(Params...), const char *read_name)
- { return r(emu::detail::make_delegate(*make_pointer<T>(m_devbase), read, read_name)); }
+ { return r(emu::rw_delegate(*make_pointer<T>(m_devbase), read, read_name)); }
template <typename T, typename Ret, typename... Params>
address_map_entry &w(Ret (T::*write)(Params...), const char *write_name)
- { return w(emu::detail::make_delegate(*make_pointer<T>(m_devbase), write, write_name)); }
+ { return w(emu::rw_delegate(*make_pointer<T>(m_devbase), write, write_name)); }
template <typename T, typename RetR, typename... ParamsR, typename U, typename RetW, typename... ParamsW>
address_map_entry &rw(RetR (T::*read)(ParamsR...), const char *read_name, RetW (U::*write)(ParamsW...), const char *write_name)
- { return r(emu::detail::make_delegate(*make_pointer<T>(m_devbase), read, read_name)).w(emu::detail::make_delegate(*make_pointer<U>(m_devbase), write, write_name)); }
+ { return r(emu::rw_delegate(*make_pointer<T>(m_devbase), read, read_name)).w(emu::rw_delegate(*make_pointer<U>(m_devbase), write, write_name)); }
template <typename T, typename Ret, typename... Params>
address_map_entry &m(Ret (T::*map)(Params...), const char *map_name)
- { return m(&m_devbase, make_delegate(map, map_name, make_pointer<T>(m_devbase))); }
+ { return m(&m_devbase, address_map_constructor(map, map_name, make_pointer<T>(m_devbase))); }
// device tag -> delegate converter
template <typename T, typename Ret, typename... Params>
address_map_entry &r(const char *tag, Ret (T::*read)(Params...), const char *read_name)
- { return r(emu::detail::make_delegate(m_devbase, tag, read, read_name)); }
+ { return r(emu::rw_delegate(m_devbase, tag, read, read_name)); }
template <typename T, typename Ret, typename... Params>
address_map_entry &w(const char *tag, Ret (T::*write)(Params...), const char *write_name)
- { return w(emu::detail::make_delegate(m_devbase, tag, write, write_name)); }
+ { return w(emu::rw_delegate(m_devbase, tag, write, write_name)); }
template <typename T, typename RetR, typename... ParamsR, typename U, typename RetW, typename... ParamsW>
address_map_entry &rw(const char *tag, RetR (T::*read)(ParamsR...), const char *read_name, RetW (U::*write)(ParamsW...), const char *write_name)
- { return r(emu::detail::make_delegate(m_devbase, tag, read, read_name)).w(emu::detail::make_delegate(m_devbase, tag, write, write_name)); }
+ { return r(emu::rw_delegate(m_devbase, tag, read, read_name)).w(emu::rw_delegate(m_devbase, tag, write, write_name)); }
template <typename T, typename Ret, typename... Params>
address_map_entry &m(const char *tag, Ret (T::*map)(Params...), const char *map_name)
- { return m(tag, make_delegate(map, map_name, static_cast<T *>(nullptr))); }
+ { return m(tag, address_map_constructor(map, map_name, static_cast<T *>(nullptr))); }
// device reference -> delegate converter
template <typename T, typename U, typename Ret, typename... Params>
address_map_entry &r(T &obj, Ret (U::*read)(Params...), const char *read_name)
- { return r(emu::detail::make_delegate(*make_pointer<U>(obj), read, read_name)); }
+ { return r(emu::rw_delegate(*make_pointer<U>(obj), read, read_name)); }
template <typename T, typename U, typename Ret, typename... Params>
address_map_entry &w(T &obj, Ret (U::*write)(Params...), const char *write_name)
- { return w(emu::detail::make_delegate(*make_pointer<U>(obj), write, write_name)); }
+ { return w(emu::rw_delegate(*make_pointer<U>(obj), write, write_name)); }
template <typename T, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW>
address_map_entry &rw(T &obj, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name)
- { return r(emu::detail::make_delegate(*make_pointer<U>(obj), read, read_name)).w(emu::detail::make_delegate(make_pointer<V>(obj), write, write_name)); }
+ { return r(emu::rw_delegate(*make_pointer<U>(obj), read, read_name)).w(emu::rw_delegate(make_pointer<V>(obj), write, write_name)); }
template <typename T, typename U, typename Ret, typename... Params>
address_map_entry &m(T &obj, Ret (U::*map)(Params...), const char *map_name)
- { return m(make_pointer<device_t>(obj), make_delegate(map, map_name, make_pointer<U>(obj))); }
+ { return m(make_pointer<device_t>(obj), address_map_constructor(map, map_name, make_pointer<U>(obj))); }
// device finder -> delegate converter
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &r(device_finder<T, Reqd> &finder, Ret (U::*read)(Params...), const char *read_name) {
- device_t &device(find_device(finder));
- return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name));
+ return r(emu::rw_delegate(finder, read, read_name));
}
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &r(const device_finder<T, Reqd> &finder, Ret (U::*read)(Params...), const char *read_name) {
- device_t &device(find_device(finder));
- return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name));
+ return r(emu::rw_delegate(finder, read, read_name));
}
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &w(device_finder<T, Reqd> &finder, Ret (U::*write)(Params...), const char *write_name) {
- device_t &device(find_device(finder));
- return w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name));
+ return w(emu::rw_delegate(finder, write, write_name));
}
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &w(const device_finder<T, Reqd> &finder, Ret (U::*write)(Params...), const char *write_name) {
- device_t &device(find_device(finder));
- return w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name));
+ return w(emu::rw_delegate(finder, write, write_name));
}
template <typename T, bool Reqd, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW>
address_map_entry &rw(device_finder<T, Reqd> &finder, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name) {
- device_t &device(find_device(finder));
- return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name))
- .w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name));
+ return r(emu::rw_delegate(finder, read, read_name))
+ .w(emu::rw_delegate(finder, write, write_name));
}
template <typename T, bool Reqd, typename U, typename RetR, typename... ParamsR, typename V, typename RetW, typename... ParamsW>
address_map_entry &rw(const device_finder<T, Reqd> &finder, RetR (U::*read)(ParamsR...), const char *read_name, RetW (V::*write)(ParamsW...), const char *write_name) {
- device_t &device(find_device(finder));
- return r(emu::detail::make_delegate(device, DEVICE_SELF, read, read_name))
- .w(emu::detail::make_delegate(device, DEVICE_SELF, write, write_name));
+ return r(emu::rw_delegate(finder, read, read_name))
+ .w(emu::rw_delegate(finder, write, write_name));
}
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &m(device_finder<T, Reqd> &finder, Ret (U::*map)(Params...), const char *map_name) {
device_t &device(find_device(finder));
- return m(&device, make_delegate(map, map_name, make_pointer<U>(device)));
+ return m(&device, address_map_constructor(map, map_name, make_pointer<U>(device)));
}
template <typename T, bool Reqd, typename U, typename Ret, typename... Params>
address_map_entry &m(const device_finder<T, Reqd> &finder, Ret (U::*map)(Params...), const char *map_name) {
device_t &device(find_device(finder));
- return m(&device, make_delegate(map, map_name, make_pointer<U>(device)));
+ return m(&device, address_map_constructor(map, map_name, make_pointer<U>(device)));
}
@@ -374,6 +415,9 @@ public:
const char * m_share; // tag of a shared memory block
const char * m_region; // tag of region containing the memory backing this entry
offs_t m_rgnoffs; // offset within the region
+ ws_time_delegate m_before_time; // before-time wait-state
+ ws_delay_delegate m_before_delay; // before-delay wait-state
+ ws_delay_delegate m_after_delay; // after-delay wait-state
// handlers
read8_delegate m_rproto8; // 8-bit read proto-delegate
diff --git a/src/emu/attotime.cpp b/src/emu/attotime.cpp
index a1ba4d9ed61..030c3193551 100644
--- a/src/emu/attotime.cpp
+++ b/src/emu/attotime.cpp
@@ -119,11 +119,11 @@ const char *attotime::as_string(int precision) const
// special case: never
if (*this == never)
- sprintf(buffer, "%-*s", precision, "(never)");
+ snprintf(buffer, 30, "%-*s", precision, "(never)");
// case 1: we want no precision; seconds only
else if (precision == 0)
- sprintf(buffer, "%d", m_seconds);
+ snprintf(buffer, 30, "%d", m_seconds);
// case 2: we want 9 or fewer digits of precision
else if (precision <= 9)
@@ -135,7 +135,7 @@ const char *attotime::as_string(int precision) const
upper /= 10;
temp++;
}
- sprintf(buffer, "%d.%0*d", m_seconds, precision, upper);
+ snprintf(buffer, 30, "%d.%0*d", m_seconds, precision, upper);
}
// case 3: more than 9 digits of precision
@@ -149,7 +149,7 @@ const char *attotime::as_string(int precision) const
lower /= 10;
temp++;
}
- sprintf(buffer, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower);
+ snprintf(buffer, 30, "%d.%09d%0*d", m_seconds, upper, precision - 9, lower);
}
return buffer;
}
diff --git a/src/emu/attotime.h b/src/emu/attotime.h
index e056ee90034..39fcf6e5310 100644
--- a/src/emu/attotime.h
+++ b/src/emu/attotime.h
@@ -38,9 +38,10 @@
#include "emucore.h"
#include "xtal.h"
+#include "eminline.h"
+
#include <cmath>
-#undef min
-#undef max
+
//**************************************************************************
// CONSTANTS
@@ -180,7 +181,7 @@ public:
//**************************************************************************
/** handle addition between two attotimes */
-inline attotime operator+(const attotime &left, const attotime &right) noexcept
+inline constexpr attotime operator+(const attotime &left, const attotime &right) noexcept
{
attotime result;
@@ -230,7 +231,7 @@ inline attotime &attotime::operator+=(const attotime &right) noexcept
/** handle subtraction between two attotimes */
-inline attotime operator-(const attotime &left, const attotime &right) noexcept
+inline constexpr attotime operator-(const attotime &left, const attotime &right) noexcept
{
attotime result;
diff --git a/src/emu/bookkeeping.cpp b/src/emu/bookkeeping.cpp
index 4ae4c1ecf2b..9f3e414e03f 100644
--- a/src/emu/bookkeeping.cpp
+++ b/src/emu/bookkeeping.cpp
@@ -11,6 +11,8 @@
#include "emu.h"
#include "config.h"
+#include "xmlfile.h"
+
//**************************************************************************
// BOOKKEEPING MANAGER
diff --git a/src/emu/config.cpp b/src/emu/config.cpp
index 792da6f255d..8e9423415ee 100644
--- a/src/emu/config.cpp
+++ b/src/emu/config.cpp
@@ -13,25 +13,39 @@
#include "drivenum.h"
#include "emuopts.h"
+#include "fileio.h"
#include "xmlfile.h"
+#include <system_error>
+#include <utility>
+
#define DEBUG_CONFIG 0
+
//**************************************************************************
// CONFIGURATION MANAGER
//**************************************************************************
-//-------------------------------------------------
-// configuration_manager - constructor
-//-------------------------------------------------
+/*************************************
+ *
+ * Construction/destruction
+ *
+ *************************************/
+
+configuration_manager::configuration_manager(running_machine &machine) :
+ m_machine(machine),
+ m_typelist()
+{
+}
-configuration_manager::configuration_manager(running_machine &machine)
- : m_machine(machine)
+configuration_manager::~configuration_manager()
{
}
+
+
/*************************************
*
* Register to be involved in config
@@ -39,14 +53,9 @@ configuration_manager::configuration_manager(running_machine &machine)
*
*************************************/
-void configuration_manager::config_register(const char *nodename, load_delegate load, save_delegate save)
+void configuration_manager::config_register(std::string_view name, load_delegate &&load, save_delegate &&save)
{
- config_element element;
- element.name = nodename;
- element.load = std::move(load);
- element.save = std::move(save);
-
- m_typelist.emplace_back(std::move(element));
+ m_typelist.emplace(name, config_handler{ std::move(load), std::move(save) });
}
@@ -60,44 +69,31 @@ void configuration_manager::config_register(const char *nodename, load_delegate
bool configuration_manager::load_settings()
{
// loop over all registrants and call their init function
- for (const auto &type : m_typelist)
- type.load(config_type::INIT, config_level::DEFAULT, nullptr);
+ for (auto const &type : m_typelist)
+ type.second.load(config_type::INIT, config_level::DEFAULT, nullptr);
// now load the controller file
char const *const controller = machine().options().ctrlr();
if (controller && *controller)
{
- // open the config file
emu_file file(machine().options().ctrlr_path(), OPEN_FLAG_READ);
- osd_printf_verbose("Attempting to parse: %s.cfg\n", controller);
- std::error_condition const filerr = file.open(std::string(controller) + ".cfg");
-
- if (filerr)
- throw emu_fatalerror("Could not open controller file %s.cfg (%s:%d %s)", controller, filerr.category().name(), filerr.value(), filerr.message());
-
- // load the XML
- if (!load_xml(file, config_type::CONTROLLER))
- throw emu_fatalerror("Could not load controller file %s.cfg", controller);
+ if (!attempt_load(machine().system(), file, std::string(controller) + ".cfg", config_type::CONTROLLER))
+ throw emu_fatalerror("Could not load controller configuration file %s.cfg", controller);
}
// next load the defaults file
emu_file file(machine().options().cfg_directory(), OPEN_FLAG_READ);
- std::error_condition filerr = file.open("default.cfg");
- osd_printf_verbose("Attempting to parse: default.cfg\n");
- if (!filerr)
- load_xml(file, config_type::DEFAULT);
+ attempt_load(machine().system(), file, "default.cfg", config_type::DEFAULT);
- // finally, load the game-specific file
- filerr = file.open(machine().basename() + ".cfg");
- osd_printf_verbose("Attempting to parse: %s.cfg\n",machine().basename());
- const bool loaded = !filerr && load_xml(file, config_type::SYSTEM);
+ // load the system-specific file
+ bool const loaded = attempt_load(machine().system(), file, machine().basename() + ".cfg", config_type::SYSTEM);
// loop over all registrants and call their final function
- for (const auto &type : m_typelist)
- type.load(config_type::FINAL, config_level::DEFAULT, nullptr);
+ for (auto const &type : m_typelist)
+ type.second.load(config_type::FINAL, config_level::DEFAULT, nullptr);
// if we didn't find a saved config, return false so the main core knows that it
- // is the first time the game is run and it should display the disclaimer.
+ // is the first time the system has been run
return loaded;
}
@@ -105,8 +101,8 @@ bool configuration_manager::load_settings()
void configuration_manager::save_settings()
{
// loop over all registrants and call their init function
- for (const auto &type : m_typelist)
- type.save(config_type::INIT, nullptr);
+ for (auto const &type : m_typelist)
+ type.second.save(config_type::INIT, nullptr);
// save the defaults file
emu_file file(machine().options().cfg_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
@@ -120,8 +116,8 @@ void configuration_manager::save_settings()
save_xml(file, config_type::SYSTEM);
// loop over all registrants and call their final function
- for (const auto &type : m_typelist)
- type.save(config_type::FINAL, nullptr);
+ for (auto const &type : m_typelist)
+ type.second.save(config_type::FINAL, nullptr);
}
@@ -132,13 +128,39 @@ void configuration_manager::save_settings()
*
*************************************/
-bool configuration_manager::load_xml(emu_file &file, config_type which_type)
+bool configuration_manager::attempt_load(game_driver const &system, emu_file &file, std::string_view name, config_type which_type)
+{
+ std::error_condition const filerr = file.open(std::string(name));
+ if (std::errc::no_such_file_or_directory == filerr)
+ {
+ osd_printf_verbose("Configuration file %s not found\n", name);
+ return false;
+ }
+ else if (filerr)
+ {
+ osd_printf_warning(
+ "Error opening configuration file %s (%s:%d %s)\n",
+ name,
+ filerr.category().name(),
+ filerr.value(),
+ filerr.message());
+ return false;
+ }
+ else
+ {
+ osd_printf_verbose("Attempting to parse: %s\n", name);
+ return load_xml(system, file, which_type);
+ }
+}
+
+
+bool configuration_manager::load_xml(game_driver const &system, emu_file &file, config_type which_type)
{
// read the file
util::xml::file::ptr const root(util::xml::file::read(file, nullptr));
if (!root)
{
- osd_printf_verbose("Error parsing XML configuration file %s\n", file.filename());
+ osd_printf_warning("Error parsing XML configuration file %s\n", file.filename());
return false;
}
@@ -146,7 +168,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
util::xml::data_node const *const confignode = root->get_child("mameconfig");
if (!confignode)
{
- osd_printf_verbose("Could not find root mameconfig element in configuration file %s\n", file.filename());
+ osd_printf_warning("Could not find root mameconfig element in configuration file %s\n", file.filename());
return false;
}
@@ -154,18 +176,18 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
int const version = confignode->get_attribute_int("version", 0);
if (version != CONFIG_VERSION)
{
- osd_printf_verbose("Configuration file %s has unsupported version %d\n", file.filename(), version);
+ osd_printf_warning("Configuration file %s has unsupported version %d\n", file.filename(), version);
return false;
}
// strip off all the path crap from the source filename
- const char *srcfile = strrchr(machine().system().type.source(), '/');
+ char const *srcfile = strrchr(system.type.source(), '/');
if (!srcfile)
- srcfile = strrchr(machine().system().type.source(), '\\');
+ srcfile = strrchr(system.type.source(), '\\');
if (!srcfile)
- srcfile = strrchr(machine().system().type.source(), ':');
+ srcfile = strrchr(system.type.source(), ':');
if (!srcfile)
- srcfile = machine().system().type.source();
+ srcfile = system.type.source();
else
srcfile++;
@@ -174,7 +196,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
for (util::xml::data_node const *systemnode = confignode->get_child("system"); systemnode; systemnode = systemnode->get_next_sibling("system"))
{
// look up the name of the system here; skip if none
- const char *name = systemnode->get_attribute_string("name", "");
+ char const *name = systemnode->get_attribute_string("name", "");
// based on the file type, determine whether we have a match
config_level level = config_level::DEFAULT;
@@ -182,7 +204,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
{
case config_type::SYSTEM:
// only match on the specific system name
- if (strcmp(name, machine().system().name))
+ if (strcmp(name, system.name))
{
osd_printf_verbose("Ignoring configuration for system %s in system configuration file %s\n", name, file.filename());
continue;
@@ -209,7 +231,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
osd_printf_verbose("Applying default configuration from controller configuration file %s\n", file.filename());
level = config_level::DEFAULT;
}
- else if (!strcmp(name, machine().system().name))
+ else if (!strcmp(name, system.name))
{
osd_printf_verbose("Applying configuration for system %s from controller configuration file %s\n", name, file.filename());
level = config_level::SYSTEM;
@@ -220,7 +242,7 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
level = config_level::SOURCE;
}
else if (
- ((clone_of = driver_list::clone(machine().system())) != -1 && !strcmp(name, driver_list::driver(clone_of).name)) ||
+ ((clone_of = driver_list::clone(system)) != -1 && !strcmp(name, driver_list::driver(clone_of).name)) ||
(clone_of != -1 && ((clone_of = driver_list::clone(clone_of)) != -1) && !strcmp(name, driver_list::driver(clone_of).name)))
{
osd_printf_verbose("Applying configuration for parent/BIOS %s from controller configuration file %s\n", name, file.filename());
@@ -242,9 +264,15 @@ bool configuration_manager::load_xml(emu_file &file, config_type which_type)
osd_printf_debug("Entry: %s -- processing\n", name);
// loop over all registrants and call their load function
- for (const auto &type : m_typelist)
- type.load(which_type, level, systemnode->get_child(type.name.c_str()));
+ for (auto const &type : m_typelist)
+ type.second.load(which_type, level, systemnode->get_child(type.first.c_str()));
count++;
+
+ // save unhandled settings for default and system types
+ if (config_type::DEFAULT == which_type)
+ save_unhandled(m_unhandled_default, *systemnode);
+ else if (config_type::SYSTEM == which_type)
+ save_unhandled(m_unhandled_system, *systemnode);
}
// error if this isn't a valid match
@@ -279,21 +307,65 @@ bool configuration_manager::save_xml(emu_file &file, config_type which_type)
systemnode->set_attribute("name", (which_type == config_type::DEFAULT) ? "default" : machine().system().name);
// loop over all registrants and call their save function
- for (const auto &type : m_typelist)
+ util::xml::data_node *curnode = nullptr;
+ for (auto const &type : m_typelist)
{
- util::xml::data_node *const curnode = systemnode->add_child(type.name.c_str(), nullptr);
+ if (!curnode || (type.first != curnode->get_name()))
+ curnode = systemnode->add_child(type.first.c_str(), nullptr);
if (!curnode)
return false;
- type.save(which_type, curnode);
+ type.second.save(which_type, curnode);
// if nothing was added, just nuke the node
if (!curnode->get_value() && !curnode->get_first_child() && !curnode->count_attributes())
+ {
curnode->delete_node();
+ curnode = nullptr;
+ }
}
- // flush the file
+ // restore unhandled settings
+ if ((config_type::DEFAULT == which_type) && m_unhandled_default)
+ restore_unhandled(*m_unhandled_default, *systemnode);
+ else if ((config_type::SYSTEM == which_type) && m_unhandled_system)
+ restore_unhandled(*m_unhandled_system, *systemnode);
+
+ // write out the file
root->write(file);
// free and get out of here
return true;
}
+
+
+
+/*************************************
+ *
+ * Preserving unhandled settings
+ *
+ *************************************/
+
+void configuration_manager::save_unhandled(
+ std::unique_ptr<util::xml::file> &unhandled,
+ util::xml::data_node const &systemnode)
+{
+ for (util::xml::data_node const *curnode = systemnode.get_first_child(); curnode; curnode = curnode->get_next_sibling())
+ {
+ auto const handler = m_typelist.lower_bound(curnode->get_name());
+ if ((m_typelist.end() == handler) || (handler->first != curnode->get_name()))
+ {
+ if (!unhandled)
+ unhandled = util::xml::file::create();
+ curnode->copy_into(*unhandled);
+ }
+ }
+}
+
+
+void configuration_manager::restore_unhandled(
+ util::xml::file const &unhandled,
+ util::xml::data_node &systemnode)
+{
+ for (util::xml::data_node const *curnode = unhandled.get_first_child(); curnode; curnode = curnode->get_next_sibling())
+ curnode->copy_into(systemnode);
+}
diff --git a/src/emu/config.h b/src/emu/config.h
index 2a273ba248f..4d3dd4f3b75 100644
--- a/src/emu/config.h
+++ b/src/emu/config.h
@@ -13,7 +13,10 @@
#pragma once
-#include "xmlfile.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <string_view>
enum class config_type : int
@@ -45,28 +48,35 @@ public:
// construction/destruction
configuration_manager(running_machine &machine);
+ ~configuration_manager();
+
+ void config_register(std::string_view name, load_delegate &&load, save_delegate &&save);
- void config_register(const char *nodename, load_delegate load, save_delegate save);
bool load_settings();
void save_settings();
- // getters
- running_machine &machine() const { return m_machine; }
-
private:
- struct config_element
+ struct config_handler
{
- std::string name; // node name
- load_delegate load; // load callback
- save_delegate save; // save callback
+ load_delegate load;
+ save_delegate save;
};
- bool load_xml(emu_file &file, config_type which_type);
+ running_machine &machine() const { return m_machine; }
+
+ bool attempt_load(game_driver const &system, emu_file &file, std::string_view name, config_type which_type);
+
+ bool load_xml(game_driver const &system, emu_file &file, config_type which_type);
bool save_xml(emu_file &file, config_type which_type);
+ void save_unhandled(std::unique_ptr<util::xml::file> &unhandled, util::xml::data_node const &systemnode);
+ void restore_unhandled(util::xml::file const &unhandled, util::xml::data_node &systemnode);
+
// internal state
- running_machine & m_machine; // reference to our machine
- std::vector<config_element> m_typelist;
+ running_machine &m_machine;
+ std::multimap<std::string, config_handler> m_typelist;
+ std::unique_ptr<util::xml::file> m_unhandled_default;
+ std::unique_ptr<util::xml::file> m_unhandled_system;
};
#endif // MAME_EMU_CONFIG_H
diff --git a/src/emu/crsshair.cpp b/src/emu/crsshair.cpp
index 3c6a6b807f0..d90cc9a7f5e 100644
--- a/src/emu/crsshair.cpp
+++ b/src/emu/crsshair.cpp
@@ -13,6 +13,7 @@
#include "config.h"
#include "emuopts.h"
+#include "fileio.h"
#include "render.h"
#include "rendutil.h"
#include "screen.h"
diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp
index 85ec19d5fb9..616567b398e 100644
--- a/src/emu/debug/debugbuf.cpp
+++ b/src/emu/debug/debugbuf.cpp
@@ -82,6 +82,8 @@ void debug_disasm_buffer::debug_data_buffer::fill(offs_t lstart, offs_t size) co
}
}
+ // FIXME: This buffer tends to hog more memory than necessary for typical disassembly tasks.
+ // If the PC values supplied are far enough apart, the buffer may suddenly increase in size to a gigabyte or more.
if(m_buffer.empty()) {
m_lstart = lstart;
m_lend = lend;
@@ -209,8 +211,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = get_ptr<u16>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = m_intf.pc_linear_to_real(lpc);
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -220,14 +223,13 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
m_do_fill = [this](offs_t lstart, offs_t lend) {
auto dis = m_space->device().machine().disable_side_effects();
u8 *dest = get_ptr<u8>(lstart);
- u32 steps = 0;
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = m_intf.pc_linear_to_real(lpc);
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_byte(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_byte(tpc);
else
*dest++ = 0;
- steps++;
}
};
break;
@@ -241,8 +243,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u64 *dest = get_ptr<u64>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_qword(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_qword(tpc);
else
*dest++ = 0;
}
@@ -255,8 +258,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u32 *dest = get_ptr<u32>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_dword(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_dword(tpc);
else
*dest++ = 0;
}
@@ -269,8 +273,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = get_ptr<u16>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -283,8 +288,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u8 *dest = get_ptr<u8>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_byte(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_byte(tpc);
else
*dest++ = 0;
}
@@ -297,8 +303,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -1390,7 +1397,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) :
// pc to string conversion
int aw = pspace.logaddr_width();
bool is_octal = pspace.is_octal();
- if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) {
+ if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL && aw > (m_dintf.page_address_bits() + m_dintf.page2_address_bits())) {
int bits1 = m_dintf.page_address_bits();
int bits2 = m_dintf.page2_address_bits();
int bits3 = aw - bits1 - bits2;
@@ -1421,7 +1428,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) :
};
}
- } else if(m_flags & util::disasm_interface::PAGED) {
+ } else if((m_flags & util::disasm_interface::PAGED) && aw > m_dintf.page_address_bits()) {
int bits1 = m_dintf.page_address_bits();
int bits2 = aw - bits1;
offs_t sm1 = (1 << bits1) - 1;
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 20431072cff..ad463ace500 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -21,8 +21,10 @@
#include "debugger.h"
#include "emuopts.h"
+#include "fileio.h"
#include "natkeyboard.h"
#include "render.h"
+#include "screen.h"
#include "softlist.h"
#include "corestr.h"
@@ -30,35 +32,7 @@
#include <algorithm>
#include <cctype>
#include <fstream>
-
-
-
-namespace {
-
-template <typename T>
-inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim)
-{
- unsigned parens = 0;
- for (std::string_view::size_type i = 0; str.length() > i; ++i)
- {
- if (str[i] == '(')
- {
- ++parens;
- }
- else if (parens)
- {
- if (str[i] == ')')
- --parens;
- }
- else if (is_delim(str[i]))
- {
- return i;
- }
- }
- return std::string_view::npos;
-}
-
-} // anonymous namespace
+#include <sstream>
@@ -79,7 +53,8 @@ const size_t debugger_commands::MAX_GLOBALS = 1000;
bool debugger_commands::cheat_address_is_valid(address_space &space, offs_t address)
{
- return space.device().memory().translate(space.spacenum(), TRANSLATE_READ, address) && (space.get_write_ptr(address) != nullptr);
+ address_space *tspace;
+ return space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace) && (tspace->get_write_ptr(address) != nullptr);
}
@@ -130,14 +105,15 @@ u64 debugger_commands::cheat_system::read_extended(offs_t address) const
{
address &= space->logaddrmask();
u64 value = space->unmap();
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
{
switch (width)
{
- case 1: value = space->read_byte(address); break;
- case 2: value = space->read_word_unaligned(address); break;
- case 4: value = space->read_dword_unaligned(address); break;
- case 8: value = space->read_qword_unaligned(address); break;
+ case 1: value = tspace->read_byte(address); break;
+ case 2: value = tspace->read_word_unaligned(address); break;
+ case 4: value = tspace->read_dword_unaligned(address); break;
+ case 8: value = tspace->read_qword_unaligned(address); break;
}
}
return sign_extend(byte_swap(value));
@@ -194,7 +170,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
if ((valcount == 1) && (blockcount == 1) && strstr(name, "/globals/"))
{
char symname[100];
- sprintf(symname, ".%s", strrchr(name, '/') + 1);
+ snprintf(symname, 100, ".%s", strrchr(name, '/') + 1);
m_global_array[itemnum].base = base;
m_global_array[itemnum].size = valsize;
symtable.add(
@@ -231,6 +207,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("gtime", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1));
m_console.register_command("gt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1));
m_console.register_command("gp", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_privilege, this, _1));
+ m_console.register_command("gbt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, true, _1));
+ m_console.register_command("gbf", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, false, _1));
+ m_console.register_command("gni", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_next_instruction, this, _1));
m_console.register_command("next", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1));
m_console.register_command("n", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1));
m_console.register_command("focus", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_focus, this, _1));
@@ -239,6 +218,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("suspend", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_suspend, this, _1));
m_console.register_command("resume", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_resume, this, _1));
m_console.register_command("cpulist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_cpulist, this, _1));
+ m_console.register_command("time", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_time, this, _1));
m_console.register_command("comadd", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1));
m_console.register_command("//", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1));
@@ -275,6 +255,13 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("rpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1));
m_console.register_command("rplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rplist, this, _1));
+ m_console.register_command("epset", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("ep", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("epclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epclear, this, _1));
+ m_console.register_command("epdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, false, _1));
+ m_console.register_command("epenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, true, _1));
+ m_console.register_command("eplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_eplist, this, _1));
+
m_console.register_command("statesave", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("ss", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("stateload", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1));
@@ -442,475 +429,15 @@ void debugger_commands::global_set(global_entry *global, u64 value)
-/***************************************************************************
- PARAMETER VALIDATION HELPERS
-***************************************************************************/
-
-/// \brief Validate parameter as a Boolean value
-///
-/// Validates a parameter as a Boolean value. Fixed strings and
-/// expressions evaluating to numeric values are recognised. The result
-/// is unchanged for an empty string.
-/// \param [in] param The parameter string.
-/// \param [in,out] result The default value on entry, and the value of
-/// the parameter interpreted as a Boolean on success. Unchanged if
-/// the parameter is an empty string.
-/// \return true if the parameter is a valid Boolean value or an empty
-/// string, or false otherwise.
-bool debugger_commands::validate_boolean_parameter(const std::string &param, bool &result)
-{
- // nullptr parameter does nothing and returns no error
- if (param.empty())
- return true;
-
- // evaluate the expression; success if no error
- bool const is_true = !core_stricmp(param.c_str(), "true");
- bool const is_false = !core_stricmp(param.c_str(), "false");
-
- if (is_true || is_false)
- {
- result = is_true;
- return true;
- }
-
- // try to evaluate as a number
- u64 val;
- if (!validate_number_parameter(param, val))
- return false;
-
- result = val != 0;
- return true;
-}
-
-
-/// \brief Validate parameter as a numeric value
-///
-/// Parses the parameter as an expression and evaluates it as a number.
-/// \param [in] param The parameter string.
-/// \param [out] result The numeric value of the expression on success.
-/// Unchanged on failure.
-/// \return true if the parameter is a valid expression that evaluates
-/// to a numeric value, or false otherwise.
-bool debugger_commands::validate_number_parameter(std::string_view param, u64 &result)
-{
- // evaluate the expression; success if no error
- try
- {
- result = parsed_expression(m_console.visible_symtable(), param).execute();
- return true;
- }
- catch (expression_error const &error)
- {
- // print an error pointing to the character that caused it
- m_console.printf("Error in expression: %s\n", param);
- m_console.printf(" %*s^", error.offset(), "");
- m_console.printf("%s\n", error.code_string());
- return false;
- }
-}
-
-
-/// \brief Validate parameter as a device
-///
-/// Validates a parameter as a device identifier and retrieves the
-/// device on success. A string corresponding to the tag of a device
-/// refers to that device; an empty string refers to the current CPU
-/// with debugger focus; any other string is parsed as an expression
-/// and treated as an index of a device implementing
-/// #device_execute_interface and #device_state_interface, and exposing
-/// a generic PC base value.
-/// \param [in] param The parameter string.
-/// \param [out] result A pointer to the device on success, or unchanged
-/// on failure.
-/// \return true if the parameter refers to a device in the current
-/// system, or false otherwise.
-bool debugger_commands::validate_device_parameter(std::string_view param, device_t *&result)
-{
- // if no parameter, use the visible CPU
- if (param.empty())
- {
- device_t *const current = m_console.get_visible_cpu();
- if (current)
- {
- result = current;
- return true;
- }
- else
- {
- m_console.printf("No valid CPU is currently selected\n");
- return false;
- }
- }
-
- // next look for a tag match
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- device_t *device = base.subdevice(strmakelower(relative));
- if (device)
- {
- result = device;
- return true;
- }
-
- // then evaluate as an expression; on an error assume it was a tag
- u64 cpunum;
- try
- {
- cpunum = parsed_expression(m_console.visible_symtable(), param).execute();
- }
- catch (expression_error &)
- {
- m_console.printf("Unable to find device '%s'\n", param);
- return false;
- }
-
- // attempt to find by numerical index
- device = get_cpu_by_index(cpunum);
- if (device)
- {
- result = device;
- return true;
- }
- else
- {
- // if out of range, complain
- m_console.printf("Invalid CPU index %u\n", cpunum);
- return false;
- }
-}
-
-
-/// \brief Validate a parameter as a CPU
-///
-/// Validates a parameter as a CPU identifier. Uses the same rules as
-/// #validate_device_parameter to identify devices, but additionally
-/// checks that the device is a "CPU" for the debugger's purposes.
-/// \param [in] The parameter string.
-/// \param [out] result The device on success, or unchanged on failure.
-/// \return true if the parameter refers to a CPU-like device in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_cpu_parameter(std::string_view param, device_t *&result)
-{
- // first do the standard device thing
- device_t *device;
- if (!validate_device_parameter(param, device))
- return false;
-
- // check that it's a "CPU" for the debugger's purposes
- device_execute_interface const *execute;
- if (device->interface(execute))
- {
- result = device;
- return true;
- }
-
- m_console.printf("Device %s is not a CPU\n", device->name());
- return false;
-}
-
-
-/// \brief Validate a parameter as an address space identifier
-///
-/// Validates a parameter as an address space identifier. Uses the same
-/// rules as #validate_device_parameter to identify devices. If the
-/// default address space number is negative, the first address space
-/// exposed by the device will be used as the default.
-/// \param [in] The parameter string.
-/// \param [in] spacenum The default address space index. If negative,
-/// the first address space exposed by the device (i.e. the address
-/// space with the lowest index) will be used as the default.
-/// \param [out] result The address space on success, or unchanged on
-/// failure.
-/// \return true if the parameter refers to an address space in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result)
-{
- device_t *device;
- std::string spacename;
- if (param.empty())
- {
- // if no parameter, use the visible CPU
- device = m_console.get_visible_cpu();
- if (!device)
- {
- m_console.printf("No valid CPU is currently selected\n");
- return false;
- }
- }
- else
- {
- // look for a tag match on the whole parameter value
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- device = base.subdevice(strmakelower(relative));
-
- // if that failed, treat the last component as an address space
- if (!device)
- {
- auto const delimiter = relative.find_last_of(":^");
- bool const found = std::string_view::npos != delimiter;
- if (!found || (':' == relative[delimiter]))
- {
- spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0));
- relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
- if (!relative.empty())
- device = base.subdevice(strmakelower(relative));
- else if (m_console.get_visible_cpu())
- device = m_console.get_visible_cpu();
- else
- device = &m_machine.root_device();
- }
- }
- }
-
- // if still no device found, evaluate as an expression
- if (!device)
- {
- u64 cpunum;
- try
- {
- cpunum = parsed_expression(m_console.visible_symtable(), param).execute();
- }
- catch (expression_error const &)
- {
- // parsing failed - assume it was a tag
- m_console.printf("Unable to find device '%s'\n", param);
- return false;
- }
-
- // attempt to find by numerical index
- device = get_cpu_by_index(cpunum);
- if (!device)
- {
- // if out of range, complain
- m_console.printf("Invalid CPU index %u\n", cpunum);
- return false;
- }
- }
-
- // ensure the device implements the memory interface
- device_memory_interface *memory;
- if (!device->interface(memory))
- {
- m_console.printf("No memory interface found for device %s\n", device->name());
- return false;
- }
-
- // fall back to supplied default space if appropriate
- if (spacename.empty() && (0 <= spacenum))
- {
- if (memory->has_space(spacenum))
- {
- result = &memory->space(spacenum);
- return true;
- }
- else
- {
- m_console.printf("No matching memory space found for device '%s'\n", device->tag());
- return false;
- }
- }
-
- // otherwise find the specified space or fall back to the first populated space
- for (int i = 0; memory->max_space_count() > i; ++i)
- {
- if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename)))
- {
- result = &memory->space(i);
- return true;
- }
- }
-
- // report appropriate error message
- if (spacename.empty())
- m_console.printf("No memory spaces found for device '%s'\n", device->tag());
- else
- m_console.printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag());
- return false;
-}
-
-
-/// \brief Validate a parameter as a target address
-///
-/// Validates a parameter as an numeric expression to use as an address
-/// optionally followed by a colon and a device identifier. If the
-/// device identifier is not presnt, the current CPU with debugger focus
-/// is assumed. See #validate_device_parameter for information on how
-/// device parametersare interpreted.
-/// \param [in] The parameter string.
-/// \param [in] spacenum The default address space index. If negative,
-/// the first address space exposed by the device (i.e. the address
-/// space with the lowest index) will be used as the default.
-/// \param [out] space The address space on success, or unchanged on
-/// failure.
-/// \param [out] addr The address on success, or unchanged on failure.
-/// \return true if the address is a valid expression evaluating to a
-/// number and the address space is found, or false otherwise.
-bool debugger_commands::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr)
-{
- // check for the device delimiter
- std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; });
- std::string_view device;
- if (devdelim != std::string::npos)
- device = param.substr(devdelim + 1);
-
- // parse the address first
- u64 addrval;
- if (!validate_number_parameter(param.substr(0, devdelim), addrval))
- return false;
-
- // find the address space
- if (!validate_device_space_parameter(device, spacenum, space))
- return false;
-
- // set the address now that we have the space
- addr = addrval;
- return true;
-}
-
-
-/// \brief Validate a parameter as a memory region
-///
-/// Validates a parameter as a memory region tag and retrieves the
-/// specified memory region.
-/// \param [in] The parameter string.
-/// \param [out] result The memory region on success, or unchanged on
-/// failure.
-/// \return true if the parameter refers to a memory region in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_memory_region_parameter(std::string_view param, memory_region *&result)
-{
- auto const &regions = m_machine.memory().regions();
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- auto const iter = regions.find(base.subtag(strmakelower(relative)));
- if (regions.end() != iter)
- {
- result = iter->second.get();
- return true;
- }
- else
- {
- m_console.printf("No matching memory region found for '%s'\n", param);
- return false;
- }
-}
-
-
-/// \brief Get search base for device or address space parameter
-///
-/// Handles prefix prefixes used to indicate that a device tag should be
-/// interpreted relative to the selected CPU. Removes the recognised
-/// prefixes from the parameter value.
-/// \param [in,out] param The parameter string. Recognised prefixes
-/// affecting the search base are removed, leaving a tag relative to
-/// the base device.
-/// \return A reference to the base device that the tag should be
-/// interpreted relative to.
-device_t &debugger_commands::get_device_search_base(std::string_view &param)
-{
- if (!param.empty())
- {
- // handle ".:" or ".^" prefix for tag relative to current CPU if any
- if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1])))
- {
- param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1);
- device_t *const current = m_console.get_visible_cpu();
- return current ? *current : m_machine.root_device();
- }
-
- // a sibling path makes most sense relative to current CPU
- if ('^' == param[0])
- {
- device_t *const current = m_console.get_visible_cpu();
- return current ? *current : m_machine.root_device();
- }
- }
-
-
- // default to root device
- return m_machine.root_device();
-}
-
-
-/// \brief Get CPU by index
-///
-/// Looks up a CPU by the number the debugger assigns it based on its
-/// position in the device tree relative to other CPUs.
-/// \param [in] cpunum Zero-based index of the CPU to find.
-/// \return A pointer to the CPU if found, or \c nullptr if no CPU has
-/// the specified index.
-device_t *debugger_commands::get_cpu_by_index(u64 cpunum)
-{
- unsigned index = 0;
- for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
- {
- // real CPUs should have pcbase
- device_state_interface const *state;
- if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE))
- {
- if (index++ == cpunum)
- {
- return &exec.device();
- }
- }
- }
- return nullptr;
-}
-
-
-/*-------------------------------------------------
- debug_command_parameter_expression - validates
- an expression parameter
--------------------------------------------------*/
-
-bool debugger_commands::debug_command_parameter_expression(std::string_view param, parsed_expression &result)
-{
- try
- {
- // parse the expression; success if no error
- result.parse(param);
- return true;
- }
- catch (expression_error const &err)
- {
- // output an error
- m_console.printf("Error in expression: %s\n", param);
- m_console.printf(" %*s^", err.offset(), "");
- m_console.printf("%s\n", err.code_string());
- return false;
- }
-}
-
-
-/*-------------------------------------------------
- debug_command_parameter_command - validates a
- command parameter
--------------------------------------------------*/
-
-bool debugger_commands::debug_command_parameter_command(const char *param)
-{
- /* nullptr parameter does nothing and returns no error */
- if (param == nullptr)
- return true;
-
- /* validate the comment; success if no error */
- CMDERR err = m_console.validate_command(param);
- if (err.error_class() == CMDERR::NONE)
- return true;
-
- /* output an error */
- m_console.printf("Error in command: %s\n", param);
- m_console.printf(" %*s^", err.error_offset(), "");
- m_console.printf("%s\n", debugger_console::cmderr_to_string(err));
- return 0;
-}
+//**************************************************************************
+// COMMAND IMPLEMENTATIONS
+//**************************************************************************
/*-------------------------------------------------
execute_help - execute the help command
-------------------------------------------------*/
-void debugger_commands::execute_help(const std::vector<std::string> &params)
+void debugger_commands::execute_help(const std::vector<std::string_view> &params)
{
if (params.size() == 0)
m_console.printf_wrap(80, "%s\n", debug_get_help(std::string_view()));
@@ -923,12 +450,12 @@ void debugger_commands::execute_help(const std::vector<std::string> &params)
execute_print - execute the print command
-------------------------------------------------*/
-void debugger_commands::execute_print(const std::vector<std::string> &params)
+void debugger_commands::execute_print(const std::vector<std::string_view> &params)
{
/* validate the other parameters */
u64 values[MAX_COMMAND_PARAMS];
for (int i = 0; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
+ if (!m_console.validate_number_parameter(params[i], values[i]))
return;
/* then print each one */
@@ -942,131 +469,177 @@ void debugger_commands::execute_print(const std::vector<std::string> &params)
mini_printf - safe printf to a buffer
-------------------------------------------------*/
-int debugger_commands::mini_printf(char *buffer, const char *format, int params, u64 *param)
+bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> &params)
{
- const char *f = format;
- char *p = buffer;
+ std::string_view const format(params[0]);
+ auto f = format.begin();
+
+ int param = 1;
+ u64 number;
- /* parse the string looking for % signs */
- for (;;)
+ // parse the string looking for % signs
+ while (f != format.end())
{
char c = *f++;
- if (!c) break;
- /* escape sequences */
+ // escape sequences
if (c == '\\')
{
+ if (f == format.end()) break;
c = *f++;
- if (!c) break;
switch (c)
{
- case '\\': *p++ = c; break;
- case 'n': *p++ = '\n'; break;
+ case '\\': stream << c; break;
+ case 'n': stream << '\n'; break;
default: break;
}
continue;
}
- /* formatting */
+ // formatting
else if (c == '%')
{
+ bool left_justify = false;
+ bool zero_fill = false;
int width = 0;
- int zerofill = 0;
+ int precision = 0;
- /* parse out the width */
- for (;;)
+ // parse optional left justification flag
+ if (f != format.end() && *f == '-')
{
- c = *f++;
- if (!c || c < '0' || c > '9') break;
- if (c == '0' && width == 0)
- zerofill = 1;
- width = width * 10 + (c - '0');
+ left_justify = true;
+ f++;
+ }
+
+ // parse optional zero fill flag
+ if (f != format.end() && *f == '0')
+ {
+ zero_fill = true;
+ f++;
+ }
+
+ // parse optional width
+ while (f != format.end() && isdigit(*f))
+ width = width * 10 + (*f++ - '0');
+ if (f == format.end())
+ break;
+
+ // apply left justification
+ if (left_justify)
+ width = -width;
+
+ if ((c = *f++) == '.')
+ {
+ // parse optional precision
+ while (f != format.end() && isdigit(*f))
+ precision = precision * 10 + (*f++ - '0');
+
+ // get the format
+ if (f != format.end())
+ c = *f++;
+ else
+ break;
}
- if (!c) break;
- /* get the format */
switch (c)
{
case '%':
- *p++ = c;
+ stream << c;
break;
case 'X':
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*X" : "%*X", width, number);
+ else
+ {
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
+ }
+ break;
case 'x':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*x" : "%*x", width, number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- if (u32(*param >> 32) != 0)
- p += sprintf(p, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, u32(*param >> 32));
- else if (width > 8)
- p += sprintf(p, zerofill ? "%0*X" : "%*X", width - 8, 0);
- p += sprintf(p, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, u32(*param));
- param++;
- params--;
break;
case 'O':
case 'o':
- if (params == 0)
- {
- m_console.printf("Not enough parameters for format!\n");
- return 0;
- }
- if (u32(*param >> 60) != 0)
- {
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 20) ? 1 : width - 20, u32(*param >> 60));
- p += sprintf(p, "%0*o", 10, u32(BIT(*param, 30, 30)));
- }
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number);
else
{
- if (width > 20)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 20, 0);
- if (u32(BIT(*param, 30, 30)) != 0)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 10) ? 1 : width - 10, u32(BIT(*param, 30, 30)));
- else if (width > 10)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 10, 0);
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
}
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width < 10) ? width : 10, u32(BIT(*param, 0, 30)));
- param++;
- params--;
break;
case 'D':
case 'd':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*d" : "%*d", width, number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, zerofill ? "%0*d" : "%*d", width, u32(*param));
- param++;
- params--;
break;
+
case 'C':
case 'c':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ stream << char(number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, "%c", char(*param));
- param++;
- params--;
break;
+ case 's':
+ {
+ address_space *space;
+ if (param < params.size() && m_console.validate_target_address_parameter(params[param++], -1, space, number))
+ {
+ address_space *tspace;
+ std::string s;
+
+ for (u32 address = u32(number), taddress; space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, taddress = address, tspace); address++)
+ {
+ u8 const data = tspace->read_byte(taddress);
+
+ if (!data)
+ break;
+
+ s += data;
+
+ if (precision == 1)
+ break;
+ else if (precision)
+ precision--;
+ }
+
+ util::stream_format(stream, "%*s", width, s);
+ }
+ else
+ {
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
+ }
+ }
+ break;
}
}
- /* normal stuff */
+ // normal stuff
else
- *p++ = c;
+ stream << c;
}
- /* NULL-terminate and exit */
- *p = 0;
- return 1;
+ return true;
}
@@ -1076,12 +649,12 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
-------------------------------------------------*/
template <typename T>
-void debugger_commands::execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message)
+void debugger_commands::execute_index_command(std::vector<std::string_view> const &params, T &&apply, char const *unused_message)
{
std::vector<u64> index(params.size());
for (int paramnum = 0; paramnum < params.size(); paramnum++)
{
- if (!validate_number_parameter(params[paramnum], index[paramnum]))
+ if (!m_console.validate_number_parameter(params[paramnum], index[paramnum]))
return;
}
@@ -1105,18 +678,12 @@ void debugger_commands::execute_index_command(std::vector<std::string> const &pa
execute_printf - execute the printf command
-------------------------------------------------*/
-void debugger_commands::execute_printf(const std::vector<std::string> &params)
+void debugger_commands::execute_printf(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_console.printf("%s\n", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params))
+ m_console.printf("%s\n", std::move(buffer).str());
}
@@ -1124,18 +691,12 @@ void debugger_commands::execute_printf(const std::vector<std::string> &params)
execute_logerror - execute the logerror command
-------------------------------------------------*/
-void debugger_commands::execute_logerror(const std::vector<std::string> &params)
+void debugger_commands::execute_logerror(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_machine.logerror("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params))
+ m_machine.logerror("%s", std::move(buffer).str());
}
@@ -1143,18 +704,12 @@ void debugger_commands::execute_logerror(const std::vector<std::string> &params)
execute_tracelog - execute the tracelog command
-------------------------------------------------*/
-void debugger_commands::execute_tracelog(const std::vector<std::string> &params)
+void debugger_commands::execute_tracelog(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1162,11 +717,10 @@ void debugger_commands::execute_tracelog(const std::vector<std::string> &params)
execute_tracesym - execute the tracesym command
-------------------------------------------------*/
-void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
+void debugger_commands::execute_tracesym(const std::vector<std::string_view> &params)
{
// build a format string appropriate for the parameters and validate them
std::stringstream format;
- u64 values[MAX_COMMAND_PARAMS];
for (int i = 0; i < params.size(); i++)
{
// find this symbol
@@ -1181,16 +735,16 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
util::stream_format(format, "%s=%s ",
params[i],
sym->format().empty() ? "%16X" : sym->format());
-
- // validate the parameter
- if (!validate_number_parameter(params[i], values[i]))
- return;
}
+ // build parameters for printf
+ std::vector<std::string_view> printf_params(params);
+ printf_params.insert(printf_params.begin(), format.str());
+
// then do a printf
- char buffer[1024];
- if (mini_printf(buffer, format.str().c_str(), params.size(), values))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, printf_params))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1198,7 +752,7 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
execute_cls - execute the cls command
-------------------------------------------------*/
-void debugger_commands::execute_cls(const std::vector<std::string> &params)
+void debugger_commands::execute_cls(const std::vector<std::string_view> &params)
{
text_buffer_clear(m_console.get_console_textbuf());
}
@@ -1208,7 +762,7 @@ void debugger_commands::execute_cls(const std::vector<std::string> &params)
execute_quit - execute the quit command
-------------------------------------------------*/
-void debugger_commands::execute_quit(const std::vector<std::string> &params)
+void debugger_commands::execute_quit(const std::vector<std::string_view> &params)
{
osd_printf_warning("Exited via the debugger\n");
m_machine.schedule_exit();
@@ -1219,10 +773,10 @@ void debugger_commands::execute_quit(const std::vector<std::string> &params)
execute_do - execute the do command
-------------------------------------------------*/
-void debugger_commands::execute_do(const std::vector<std::string> &params)
+void debugger_commands::execute_do(const std::vector<std::string_view> &params)
{
u64 dummy;
- validate_number_parameter(params[0], dummy);
+ m_console.validate_number_parameter(params[0], dummy);
}
@@ -1230,11 +784,11 @@ void debugger_commands::execute_do(const std::vector<std::string> &params)
execute_step - execute the step command
-------------------------------------------------*/
-void debugger_commands::execute_step(const std::vector<std::string> &params)
+void debugger_commands::execute_step(const std::vector<std::string_view> &params)
{
/* if we have a parameter, use it */
u64 steps = 1;
- if (params.size() > 0 && !validate_number_parameter(params[0], steps))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps))
return;
m_console.get_visible_cpu()->debug()->single_step(steps);
@@ -1245,11 +799,11 @@ void debugger_commands::execute_step(const std::vector<std::string> &params)
execute_over - execute the over command
-------------------------------------------------*/
-void debugger_commands::execute_over(const std::vector<std::string> &params)
+void debugger_commands::execute_over(const std::vector<std::string_view> &params)
{
/* if we have a parameter, use it */
u64 steps = 1;
- if (params.size() > 0 && !validate_number_parameter(params[0], steps))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps))
return;
m_console.get_visible_cpu()->debug()->single_step_over(steps);
@@ -1260,7 +814,7 @@ void debugger_commands::execute_over(const std::vector<std::string> &params)
execute_out - execute the out command
-------------------------------------------------*/
-void debugger_commands::execute_out(const std::vector<std::string> &params)
+void debugger_commands::execute_out(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->single_step_out();
}
@@ -1270,12 +824,12 @@ void debugger_commands::execute_out(const std::vector<std::string> &params)
execute_go - execute the go command
-------------------------------------------------*/
-void debugger_commands::execute_go(const std::vector<std::string> &params)
+void debugger_commands::execute_go(const std::vector<std::string_view> &params)
{
u64 addr = ~0;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], addr))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], addr))
return;
m_console.get_visible_cpu()->debug()->go(addr);
@@ -1287,7 +841,7 @@ void debugger_commands::execute_go(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_go_vblank(const std::vector<std::string> &params)
+void debugger_commands::execute_go_vblank(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->go_vblank();
}
@@ -1297,12 +851,12 @@ void debugger_commands::execute_go_vblank(const std::vector<std::string> &params
execute_go_interrupt - execute the goint command
-------------------------------------------------*/
-void debugger_commands::execute_go_interrupt(const std::vector<std::string> &params)
+void debugger_commands::execute_go_interrupt(const std::vector<std::string_view> &params)
{
u64 irqline = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], irqline))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], irqline))
return;
m_console.get_visible_cpu()->debug()->go_interrupt(irqline);
@@ -1312,16 +866,16 @@ void debugger_commands::execute_go_interrupt(const std::vector<std::string> &par
execute_go_exception - execute the goex command
-------------------------------------------------*/
-void debugger_commands::execute_go_exception(const std::vector<std::string> &params)
+void debugger_commands::execute_go_exception(const std::vector<std::string_view> &params)
{
u64 exception = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], exception))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], exception))
return;
parsed_expression condition(m_console.visible_symtable());
- if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition))
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
return;
m_console.get_visible_cpu()->debug()->go_exception(exception, condition.is_empty() ? "1" : condition.original_string());
@@ -1332,12 +886,12 @@ void debugger_commands::execute_go_exception(const std::vector<std::string> &par
execute_go_time - execute the gtime command
-------------------------------------------------*/
-void debugger_commands::execute_go_time(const std::vector<std::string> &params)
+void debugger_commands::execute_go_time(const std::vector<std::string_view> &params)
{
u64 milliseconds = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], milliseconds))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], milliseconds))
return;
m_console.get_visible_cpu()->debug()->go_milliseconds(milliseconds);
@@ -1348,20 +902,76 @@ void debugger_commands::execute_go_time(const std::vector<std::string> &params)
/*-------------------------------------------------
execute_go_privilege - execute the gp command
-------------------------------------------------*/
-void debugger_commands::execute_go_privilege(const std::vector<std::string> &params)
+void debugger_commands::execute_go_privilege(const std::vector<std::string_view> &params)
{
parsed_expression condition(m_console.visible_symtable());
- if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
+ if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition))
return;
m_console.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string());
}
+
+/*-------------------------------------------------
+ execute_go_branch - execute gbt or gbf command
+-------------------------------------------------*/
+
+void debugger_commands::execute_go_branch(bool sense, const std::vector<std::string_view> &params)
+{
+ parsed_expression condition(m_console.visible_symtable());
+ if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition))
+ return;
+
+ m_console.get_visible_cpu()->debug()->go_branch(sense, (condition.is_empty()) ? "1" : condition.original_string());
+}
+
+
+/*-------------------------------------------------
+ execute_go_next_instruction - execute gni command
+-------------------------------------------------*/
+
+void debugger_commands::execute_go_next_instruction(const std::vector<std::string_view> &params)
+{
+ u64 count = 1;
+ static constexpr u64 MAX_COUNT = 512;
+
+ // if we have a parameter, use it instead */
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], count))
+ return;
+ if (count == 0)
+ return;
+ if (count > MAX_COUNT)
+ {
+ m_console.printf("Too many instructions (must be %d or fewer)\n", MAX_COUNT);
+ return;
+ }
+
+ device_state_interface *stateintf;
+ device_t *cpu = m_console.get_visible_cpu();
+ if (!cpu->interface(stateintf))
+ {
+ m_console.printf("No state interface available for %s\n", cpu->name());
+ return;
+ }
+ u32 pc = stateintf->pcbase();
+
+ debug_disasm_buffer buffer(*cpu);
+ while (count-- != 0)
+ {
+ // disassemble the current instruction and get the length
+ u32 result = buffer.disassemble_info(pc);
+ pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK);
+ }
+
+ cpu->debug()->go(pc);
+}
+
+
/*-------------------------------------------------
execute_next - execute the next command
-------------------------------------------------*/
-void debugger_commands::execute_next(const std::vector<std::string> &params)
+void debugger_commands::execute_next(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->go_next_device();
}
@@ -1371,11 +981,11 @@ void debugger_commands::execute_next(const std::vector<std::string> &params)
execute_focus - execute the focus command
-------------------------------------------------*/
-void debugger_commands::execute_focus(const std::vector<std::string> &params)
+void debugger_commands::execute_focus(const std::vector<std::string_view> &params)
{
// validate params
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
// first clear the ignore flag on the focused CPU
@@ -1393,7 +1003,7 @@ void debugger_commands::execute_focus(const std::vector<std::string> &params)
execute_ignore - execute the ignore command
-------------------------------------------------*/
-void debugger_commands::execute_ignore(const std::vector<std::string> &params)
+void debugger_commands::execute_ignore(const std::vector<std::string_view> &params)
{
if (params.empty())
{
@@ -1425,7 +1035,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
// set the ignore flags
@@ -1456,7 +1066,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> &params)
execute_observe - execute the observe command
-------------------------------------------------*/
-void debugger_commands::execute_observe(const std::vector<std::string> &params)
+void debugger_commands::execute_observe(const std::vector<std::string_view> &params)
{
if (params.empty())
{
@@ -1488,7 +1098,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
// clear the ignore flags
@@ -1504,7 +1114,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> &params)
execute_suspend - suspend execution on cpu
-------------------------------------------------*/
-void debugger_commands::execute_suspend(const std::vector<std::string> &params)
+void debugger_commands::execute_suspend(const std::vector<std::string_view> &params)
{
// if there are no parameters, dump the ignore list
if (params.empty())
@@ -1534,7 +1144,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
for (int paramnum = 0; paramnum < params.size(); paramnum++)
@@ -1563,7 +1173,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> &params)
execute_resume - Resume execution on CPU
-------------------------------------------------*/
-void debugger_commands::execute_resume(const std::vector<std::string> &params)
+void debugger_commands::execute_resume(const std::vector<std::string_view> &params)
{
// if there are no parameters, dump the ignore list
if (params.empty())
@@ -1593,7 +1203,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
for (int paramnum = 0; paramnum < params.size(); paramnum++)
@@ -1608,7 +1218,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> &params)
// execute_cpulist - list all CPUs
//-------------------------------------------------
-void debugger_commands::execute_cpulist(const std::vector<std::string> &params)
+void debugger_commands::execute_cpulist(const std::vector<std::string_view> &params)
{
int index = 0;
for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
@@ -1619,20 +1229,29 @@ void debugger_commands::execute_cpulist(const std::vector<std::string> &params)
}
}
+//-------------------------------------------------
+// execute_time - execute the time command
+//-------------------------------------------------
+
+void debugger_commands::execute_time(const std::vector<std::string_view> &params)
+{
+ m_console.printf("%s\n", m_machine.time().as_string());
+}
+
/*-------------------------------------------------
execute_comment - add a comment to a line
-------------------------------------------------*/
-void debugger_commands::execute_comment_add(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_add(const std::vector<std::string_view> &params)
{
// param 1 is the address for the comment
u64 address;
- if (!validate_number_parameter(params[0], address))
+ if (!m_console.validate_number_parameter(params[0], address))
return;
// CPU parameter is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// make sure param 2 exists
@@ -1643,7 +1262,8 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> &para
}
// Now try adding the comment
- cpu->debug()->comment_add(address, params[1].c_str(), 0x00ff0000);
+ std::string const text(params[1]);
+ cpu->debug()->comment_add(address, text.c_str(), 0x00ff0000);
cpu->machine().debug_view().update_all(DVT_DISASSEMBLY);
}
@@ -1652,16 +1272,16 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> &para
execute_comment_del - remove a comment from an addr
--------------------------------------------------------*/
-void debugger_commands::execute_comment_del(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_del(const std::vector<std::string_view> &params)
{
// param 1 can either be a command or the address for the comment
u64 address;
- if (!validate_number_parameter(params[0], address))
+ if (!m_console.validate_number_parameter(params[0], address))
return;
// CPU parameter is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// If it's a number, it must be an address
@@ -1671,25 +1291,25 @@ void debugger_commands::execute_comment_del(const std::vector<std::string> &para
}
/**
- * @fn void execute_comment_list(const std::vector<std::string> &params)
+ * @fn void execute_comment_list(const std::vector<std::string_view> &params)
* @brief Print current list of comments in debugger
*
*
*/
-void debugger_commands::execute_comment_list(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_list(const std::vector<std::string_view> &params)
{
if (!m_machine.debugger().cpu().comment_load(false))
m_console.printf("Error while parsing XML file\n");
}
/**
- * @fn void execute_comment_commit(const std::vector<std::string> &params)
+ * @fn void execute_comment_commit(const std::vector<std::string_view> &params)
* @brief Add and Save current list of comments in debugger
*
*/
-void debugger_commands::execute_comment_commit(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_commit(const std::vector<std::string_view> &params)
{
execute_comment_add(params);
execute_comment_save(params);
@@ -1699,7 +1319,7 @@ void debugger_commands::execute_comment_commit(const std::vector<std::string> &p
execute_comment - add a comment to a line
-------------------------------------------------*/
-void debugger_commands::execute_comment_save(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_save(const std::vector<std::string_view> &params)
{
if (m_machine.debugger().cpu().comment_save())
m_console.printf("Comment successfully saved\n");
@@ -1709,7 +1329,7 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par
// TODO: add color hex editing capabilities for comments, see below for more info
/**
- * @fn void execute_comment_color(const std::vector<std::string> &params)
+ * @fn void execute_comment_color(const std::vector<std::string_view> &params)
* @brief Modifies comment given at address $xx with given color
* Useful for marking comment with a different color scheme (for example by marking start and end of a given function visually).
* @param[in] "address,color" First is the comment address in the current context, color can be hexadecimal or shorthanded to common 1bpp RGB names.
@@ -1726,12 +1346,12 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par
command
-------------------------------------------------*/
-void debugger_commands::execute_bpset(const std::vector<std::string> &params)
+void debugger_commands::execute_bpset(const std::vector<std::string_view> &params)
{
// param 1 is the address/CPU
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], AS_PROGRAM, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], AS_PROGRAM, space, address))
return;
device_execute_interface const *execute;
@@ -1750,12 +1370,12 @@ void debugger_commands::execute_bpset(const std::vector<std::string> &params)
// param 2 is the condition
parsed_expression condition(debug->symtable());
- if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition))
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
return;
// param 3 is the action
- const char *action = nullptr;
- if (params.size() > 2 && !debug_command_parameter_command(action = params[2].c_str()))
+ std::string_view action;
+ if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2]))
return;
// set the breakpoint
@@ -1769,7 +1389,7 @@ void debugger_commands::execute_bpset(const std::vector<std::string> &params)
clear command
-------------------------------------------------*/
-void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_bpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -1798,7 +1418,7 @@ void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -1827,7 +1447,7 @@ void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::
command
-------------------------------------------------*/
-void debugger_commands::execute_bplist(const std::vector<std::string> &params)
+void debugger_commands::execute_bplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -1856,7 +1476,7 @@ void debugger_commands::execute_bplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -1878,13 +1498,13 @@ void debugger_commands::execute_bplist(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string_view> &params)
{
u64 address, length;
address_space *space;
// param 1 is the address/CPU
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
device_execute_interface const *execute;
@@ -1896,31 +1516,35 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
device_debug *const debug = space->device().debug();
// param 2 is the length
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// param 3 is the type
read_or_write type;
- if (!core_stricmp(params[2].c_str(), "r"))
- type = read_or_write::READ;
- else if (!core_stricmp(params[2].c_str(), "w"))
- type = read_or_write::WRITE;
- else if (!core_stricmp(params[2].c_str(), "rw") || !core_stricmp(params[2].c_str(), "wr"))
- type = read_or_write::READWRITE;
- else
{
- m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[2], "r"sv))
+ type = read_or_write::READ;
+ else if (streqlower(params[2], "w"sv))
+ type = read_or_write::WRITE;
+ else if (streqlower(params[2], "rw"sv) || streqlower(params[2], "wr"sv))
+ type = read_or_write::READWRITE;
+ else
+ {
+ m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
+ return;
+ }
}
// param 4 is the condition
parsed_expression condition(debug->symtable());
- if (params.size() > 3 && !debug_command_parameter_expression(params[3], condition))
+ if (params.size() > 3 && !m_console.validate_expression_parameter(params[3], condition))
return;
// param 5 is the action
- const char *action = nullptr;
- if (params.size() > 4 && !debug_command_parameter_command(action = params[4].c_str()))
+ std::string_view action;
+ if (params.size() > 4 && !m_console.validate_command_parameter(action = params[4]))
return;
// set the watchpoint
@@ -1934,7 +1558,7 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
clear command
-------------------------------------------------*/
-void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_wpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -1963,7 +1587,7 @@ void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -1992,7 +1616,7 @@ void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::
command
-------------------------------------------------*/
-void debugger_commands::execute_wplist(const std::vector<std::string> &params)
+void debugger_commands::execute_wplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -2033,7 +1657,7 @@ void debugger_commands::execute_wplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -2055,21 +1679,21 @@ void debugger_commands::execute_wplist(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_rpset(const std::vector<std::string> &params)
+void debugger_commands::execute_rpset(const std::vector<std::string_view> &params)
{
// CPU is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// param 1 is the condition
parsed_expression condition(cpu->debug()->symtable());
- if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
+ if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition))
return;
// param 2 is the action
- const char *action = nullptr;
- if (params.size() > 1 && !debug_command_parameter_command(action = params[1].c_str()))
+ std::string_view action;
+ if (params.size() > 1 && !m_console.validate_command_parameter(action = params[1]))
return;
// set the registerpoint
@@ -2083,7 +1707,7 @@ void debugger_commands::execute_rpset(const std::vector<std::string> &params)
clear command
-------------------------------------------------*/
-void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_rpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -2112,7 +1736,7 @@ void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -2136,12 +1760,154 @@ void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::
}
+//-------------------------------------------------
+// execute_epset - execute the exception point
+// set command
+//-------------------------------------------------
+
+void debugger_commands::execute_epset(const std::vector<std::string_view> &params)
+{
+ // CPU is implicit
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
+ return;
+
+ // param 1 is the exception type
+ u64 type;
+ if (!m_console.validate_number_parameter(params[0], type))
+ return;
+
+ // param 2 is the condition
+ parsed_expression condition(cpu->debug()->symtable());
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
+ return;
+
+ // param 3 is the action
+ std::string_view action;
+ if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2]))
+ return;
+
+ // set the exception point
+ int epnum = cpu->debug()->exceptionpoint_set(type, (condition.is_empty()) ? nullptr : condition.original_string(), action);
+ m_console.printf("Exception point %X set\n", epnum);
+}
+
+
+//-------------------------------------------------
+// execute_epclear - execute the exception point
+// clear command
+//-------------------------------------------------
+
+void debugger_commands::execute_epclear(const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, clear all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_clear_all();
+ m_console.printf("Cleared all exception points\n");
+ }
+ else // otherwise, clear the specific ones
+ {
+ execute_index_command(
+ params,
+ [this] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_clear(param))
+ return false;
+ m_console.printf("Exception point %X cleared\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_epdisenable - execute the exception
+// point disable/enable commands
+//-------------------------------------------------
+
+void debugger_commands::execute_epdisenable(bool enable, const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, disable/enable all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_enable_all(enable);
+ m_console.printf(enable ? "Enabled all exception points\n" : "Disabled all exception points\n");
+ }
+ else // otherwise, disable/enable the specific ones
+ {
+ execute_index_command(
+ params,
+ [this, enable] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_enable(param, enable))
+ return false;
+ m_console.printf(enable ? "Exception point %X enabled\n" : "Exception point %X disabled\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_eplist - execute the exception point
+// list command
+//-------------------------------------------------
+
+void debugger_commands::execute_eplist(const std::vector<std::string_view> &params)
+{
+ int printed = 0;
+ std::string buffer;
+ auto const apply =
+ [this, &printed, &buffer] (device_t &device)
+ {
+ if (!device.debug()->exceptionpoint_list().empty())
+ {
+ m_console.printf("Device '%s' exception points:\n", device.tag());
+
+ // loop over the exception points
+ for (const auto &epp : device.debug()->exceptionpoint_list())
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ buffer = string_format("%c%4X : %X", ep.enabled() ? ' ' : 'D', ep.index(), ep.type());
+ if (std::string(ep.condition()).compare("1") != 0)
+ buffer.append(string_format(" if %s", ep.condition()));
+ if (!ep.action().empty())
+ buffer.append(string_format(" do %s", ep.action()));
+ m_console.printf("%s\n", buffer);
+ printed++;
+ }
+ }
+ };
+
+ if (!params.empty())
+ {
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
+ return;
+ apply(*cpu);
+ if (!printed)
+ m_console.printf("No exception points currently installed for CPU %s\n", cpu->tag());
+ }
+ else
+ {
+ // loop over all CPUs
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ apply(device);
+ if (!printed)
+ m_console.printf("No exception points currently installed\n");
+ }
+}
+
+
/*-------------------------------------------------
execute_rplist - execute the registerpoint list
command
-------------------------------------------------*/
-void debugger_commands::execute_rplist(const std::vector<std::string> &params)
+void debugger_commands::execute_rplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -2156,7 +1922,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
for (const auto &rp : device.debug()->registerpoint_list())
{
buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition());
- if (rp.action() && *rp.action())
+ if (!rp.action().empty())
buffer.append(string_format(" do %s", rp.action()));
m_console.printf("%s\n", buffer);
printed++;
@@ -2167,7 +1933,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -2188,10 +1954,9 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
execute_statesave - execute the statesave command
-------------------------------------------------*/
-void debugger_commands::execute_statesave(const std::vector<std::string> &params)
+void debugger_commands::execute_statesave(const std::vector<std::string_view> &params)
{
- const std::string &filename(params[0]);
- m_machine.immediate_save(filename.c_str());
+ m_machine.immediate_save(params[0]);
m_console.printf("State save attempted. Please refer to window message popup for results.\n");
}
@@ -2200,10 +1965,9 @@ void debugger_commands::execute_statesave(const std::vector<std::string> &params
execute_stateload - execute the stateload command
-------------------------------------------------*/
-void debugger_commands::execute_stateload(const std::vector<std::string> &params)
+void debugger_commands::execute_stateload(const std::vector<std::string_view> &params)
{
- const std::string &filename(params[0]);
- m_machine.immediate_load(filename.c_str());
+ m_machine.immediate_load(params[0]);
// clear all PC & memory tracks
for (device_t &device : device_enumerator(m_machine.root_device()))
@@ -2219,7 +1983,7 @@ void debugger_commands::execute_stateload(const std::vector<std::string> &params
execute_rewind - execute the rewind command
-------------------------------------------------*/
-void debugger_commands::execute_rewind(const std::vector<std::string> &params)
+void debugger_commands::execute_rewind(const std::vector<std::string_view> &params)
{
bool success = m_machine.rewind_step();
if (success)
@@ -2238,15 +2002,15 @@ void debugger_commands::execute_rewind(const std::vector<std::string> &params)
execute_save - execute the save command
-------------------------------------------------*/
-void debugger_commands::execute_save(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, endoffset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
// determine the addresses to write
@@ -2255,7 +2019,8 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
endoffset++;
// open the file
- FILE *const f = fopen(params[0].c_str(), "wb");
+ std::string const filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "wb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2270,8 +2035,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u64 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_qword(curaddr) : space->unmap();
+ address_space *tspace;
+ u64 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_qword(curaddr) : space->unmap();
fwrite(&data, 8, 1, f);
}
break;
@@ -2279,8 +2045,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u32 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_dword(curaddr) : space->unmap();
+ address_space *tspace;
+ u32 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_dword(curaddr) : space->unmap();
fwrite(&data, 4, 1, f);
}
break;
@@ -2288,8 +2055,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_word(curaddr) : space->unmap();
+ address_space *tspace;
+ u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_word(curaddr) : space->unmap();
fwrite(&data, 2, 1, f);
}
break;
@@ -2297,8 +2065,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u8 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_byte(curaddr) : space->unmap();
+ address_space *tspace;
+ u8 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_byte(curaddr) : space->unmap();
fwrite(&data, 1, 1, f);
}
break;
@@ -2308,8 +2077,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i+=16)
{
offs_t curaddr = i;
- u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_word(curaddr) : space->unmap();
+ address_space *tspace;
+ u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_word(curaddr) : space->unmap();
fwrite(&data, 2, 1, f);
}
break;
@@ -2325,17 +2095,17 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
execute_saveregion - execute the save command on region memory
-------------------------------------------------*/
-void debugger_commands::execute_saveregion(const std::vector<std::string> &params)
+void debugger_commands::execute_saveregion(const std::vector<std::string_view> &params)
{
u64 offset, length;
memory_region *region;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (!validate_memory_region_parameter(params[3], region))
+ if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes())
@@ -2347,7 +2117,8 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> &param
length = region->bytes() - offset;
/* open the file */
- FILE *f = fopen(params[0].c_str(), "wb");
+ std::string const filename(params[0]);
+ FILE *f = fopen(filename.c_str(), "wb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2364,20 +2135,21 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> &param
execute_load - execute the load command
-------------------------------------------------*/
-void debugger_commands::execute_load(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, endoffset, length = 0;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
- if (params.size() > 2 && !validate_number_parameter(params[2], length))
+ if (params.size() > 2 && !m_console.validate_number_parameter(params[2], length))
return;
// open the file
std::ifstream f;
- f.open(params[0], std::ifstream::in | std::ifstream::binary);
+ std::string const fname(params[0]);
+ f.open(fname, std::ifstream::in | std::ifstream::binary);
if (f.fail())
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2411,8 +2183,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u64 data;
f.read((char *)&data, 8);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_qword(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_qword(curaddr, data);
}
break;
case -2:
@@ -2421,8 +2194,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u32 data;
f.read((char *)&data, 4);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_dword(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_dword(curaddr, data);
}
break;
case -1:
@@ -2431,8 +2205,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u16 data;
f.read((char *)&data, 2);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_word(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_word(curaddr, data);
}
break;
case 0:
@@ -2441,8 +2216,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u8 data;
f.read((char *)&data, 1);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_byte(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_byte(curaddr, data);
}
break;
case 3:
@@ -2453,8 +2229,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u16 data;
f.read((char *)&data, 2);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_word(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_word(curaddr, data);
}
break;
}
@@ -2472,17 +2249,17 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
execute_loadregion - execute the load command on region memory
-------------------------------------------------*/
-void debugger_commands::execute_loadregion(const std::vector<std::string> &params)
+void debugger_commands::execute_loadregion(const std::vector<std::string_view> &params)
{
u64 offset, length;
memory_region *region;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (!validate_memory_region_parameter(params[3], region))
+ if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes())
@@ -2494,7 +2271,8 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> &param
length = region->bytes() - offset;
// open the file
- FILE *const f = fopen(params[0].c_str(), "rb");
+ std::string filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "rb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2520,28 +2298,28 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> &param
execute_dump - execute the dump command
-------------------------------------------------*/
-void debugger_commands::execute_dump(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
address_space *space;
u64 offset;
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
u64 length;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
u64 width = 0;
- if (params.size() > 3 && !validate_number_parameter(params[3], width))
+ if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width))
return;
bool ascii = true;
- if (params.size() > 4 && !validate_boolean_parameter(params[4], ascii))
+ if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii))
return;
u64 rowsize = space->byte_to_address(16);
- if (params.size() > 5 && !validate_number_parameter(params[5], rowsize))
+ if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize))
return;
int shift = space->addr_shift();
@@ -2572,7 +2350,8 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
offset = offset & space->addrmask();
// open the file
- FILE *const f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2602,21 +2381,22 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
if (i + j <= endoffset)
{
offs_t curaddr = i + j;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
switch (width)
{
case 8:
- util::stream_format(output, " %016X", space->read_qword_unaligned(i+j));
+ util::stream_format(output, " %016X", tspace->read_qword_unaligned(i+j));
break;
case 4:
- util::stream_format(output, " %08X", space->read_dword_unaligned(i+j));
+ util::stream_format(output, " %08X", tspace->read_dword_unaligned(i+j));
break;
case 2:
- util::stream_format(output, " %04X", space->read_word_unaligned(i+j));
+ util::stream_format(output, " %04X", tspace->read_word_unaligned(i+j));
break;
case 1:
- util::stream_format(output, " %02X", space->read_byte(i+j));
+ util::stream_format(output, " %02X", tspace->read_byte(i+j));
break;
}
}
@@ -2636,22 +2416,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
for (u64 j = 0; j < rowsize && (i + j) <= endoffset; j += delta)
{
offs_t curaddr = i + j;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
u64 data = 0;
switch (width)
{
case 8:
- data = space->read_qword_unaligned(i+j);
+ data = tspace->read_qword_unaligned(i+j);
break;
case 4:
- data = space->read_dword_unaligned(i+j);
+ data = tspace->read_dword_unaligned(i+j);
break;
case 2:
- data = space->read_word_unaligned(i+j);
+ data = tspace->read_word_unaligned(i+j);
break;
case 1:
- data = space->read_byte(i+j);
+ data = tspace->read_byte(i+j);
break;
}
for (unsigned int b = 0; b != width; b++) {
@@ -2681,23 +2462,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
// execute_strdump - execute the strdump command
//-------------------------------------------------
-void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
u64 offset;
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
u64 length;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
u64 term = 0;
- if (params.size() > 3 && !validate_number_parameter(params[3], term))
+ if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term))
return;
address_space *space;
- if (!validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space))
+ if (!m_console.validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space))
return;
// further validation
@@ -2708,7 +2489,8 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
}
// open the file
- FILE *f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ FILE *f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2746,28 +2528,29 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
// get the character data
u64 data = 0;
offs_t curaddr = offset;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
switch (width)
{
case 1:
- data = space->read_byte(curaddr);
+ data = tspace->read_byte(curaddr);
break;
case 2:
- data = space->read_word(curaddr);
+ data = tspace->read_word(curaddr);
if (be)
data = swapendian_int16(data);
break;
case 4:
- data = space->read_dword(curaddr);
+ data = tspace->read_dword(curaddr);
if (be)
data = swapendian_int32(data);
break;
case 8:
- data = space->read_qword(curaddr);
+ data = tspace->read_qword(curaddr);
if (be)
data = swapendian_int64(data);
break;
@@ -2857,7 +2640,7 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
cheats
-------------------------------------------------*/
-void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string> &params)
+void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string_view> &params)
{
address_space *space = m_cheat.space;
if (!space && !init)
@@ -2874,7 +2657,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
// first argument is sign/size/swap flags
if (!params.empty())
{
- std::string const &srtpnt = params[0];
+ std::string_view const &srtpnt = params[0];
if (!srtpnt.empty())
{
width = 1;
@@ -2927,7 +2710,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
}
// fourth argument is device/space
- if (!validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
+ if (!m_console.validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
return;
}
@@ -2937,9 +2720,9 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
{
// validate parameters
u64 offset, length;
- if (!validate_number_parameter(params[init ? 1 : 0], offset))
+ if (!m_console.validate_number_parameter(params[init ? 1 : 0], offset))
return;
- if (!validate_number_parameter(params[init ? 2 : 1], length))
+ if (!m_console.validate_number_parameter(params[init ? 2 : 1], length))
return;
// force region to the specified range
@@ -3026,7 +2809,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
execute_cheatnext - execute the search
-------------------------------------------------*/
-void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string> &params)
+void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string_view> &params)
{
enum
{
@@ -3054,36 +2837,40 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
}
u64 comp_value = 0;
- if (params.size() > 1 && !validate_number_parameter(params[1], comp_value))
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], comp_value))
return;
comp_value = m_cheat.sign_extend(comp_value);
// decode condition
u8 condition;
- if (!core_stricmp(params[0].c_str(), "all"))
- condition = CHEAT_ALL;
- else if (!core_stricmp(params[0].c_str(), "equal") || !core_stricmp(params[0].c_str(), "eq"))
- condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "notequal") || !core_stricmp(params[0].c_str(), "ne"))
- condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
- else if (!core_stricmp(params[0].c_str(), "decrease") || !core_stricmp(params[0].c_str(), "de") || params[0] == "-")
- condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
- else if (!core_stricmp(params[0].c_str(), "increase") || !core_stricmp(params[0].c_str(), "in") || params[0] == "+")
- condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
- else if (!core_stricmp(params[0].c_str(), "decreaseorequal") || !core_stricmp(params[0].c_str(), "deeq"))
- condition = CHEAT_DECREASE_OR_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "increaseorequal") || !core_stricmp(params[0].c_str(), "ineq"))
- condition = CHEAT_INCREASE_OR_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "smallerof") || !core_stricmp(params[0].c_str(), "lt") || params[0] == "<")
- condition = CHEAT_SMALLEROF;
- else if (!core_stricmp(params[0].c_str(), "greaterof") || !core_stricmp(params[0].c_str(), "gt") || params[0] == ">")
- condition = CHEAT_GREATEROF;
- else if (!core_stricmp(params[0].c_str(), "changedby") || !core_stricmp(params[0].c_str(), "ch") || params[0] == "~")
- condition = CHEAT_CHANGEDBY;
- else
{
- m_console.printf("Invalid condition type\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[0], "all"sv))
+ condition = CHEAT_ALL;
+ else if (streqlower(params[0], "equal"sv) || streqlower(params[0], "eq"sv))
+ condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
+ else if (streqlower(params[0], "notequal"sv) || streqlower(params[0], "ne"sv))
+ condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
+ else if (streqlower(params[0], "decrease"sv) || streqlower(params[0], "de"sv) || params[0] == "-"sv)
+ condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
+ else if (streqlower(params[0], "increase"sv) || streqlower(params[0], "in"sv) || params[0] == "+"sv)
+ condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
+ else if (streqlower(params[0], "decreaseorequal"sv) || streqlower(params[0], "deeq"sv))
+ condition = CHEAT_DECREASE_OR_EQUAL;
+ else if (streqlower(params[0], "increaseorequal"sv) || streqlower(params[0], "ineq"sv))
+ condition = CHEAT_INCREASE_OR_EQUAL;
+ else if (streqlower(params[0], "smallerof"sv) || streqlower(params[0], "lt"sv) || params[0] == "<"sv)
+ condition = CHEAT_SMALLEROF;
+ else if (streqlower(params[0], "greaterof"sv) || streqlower(params[0], "gt"sv) || params[0] == ">"sv)
+ condition = CHEAT_GREATEROF;
+ else if (streqlower(params[0], "changedby"sv) || streqlower(params[0], "ch"sv) || params[0] == "~"sv)
+ condition = CHEAT_CHANGEDBY;
+ else
+ {
+ m_console.printf("Invalid condition type\n");
+ return;
+ }
}
m_cheat.undo++;
@@ -3190,7 +2977,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
}
if (active_cheat <= 5)
- execute_cheatlist(std::vector<std::string>());
+ execute_cheatlist(std::vector<std::string_view>());
m_console.printf("%u cheats found\n", active_cheat);
}
@@ -3200,7 +2987,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
execute_cheatlist - show a list of active cheat
-------------------------------------------------*/
-void debugger_commands::execute_cheatlist(const std::vector<std::string> &params)
+void debugger_commands::execute_cheatlist(const std::vector<std::string_view> &params)
{
address_space *const space = m_cheat.space;
if (!space)
@@ -3212,7 +2999,8 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> &params
FILE *f = nullptr;
if (params.size() > 0)
{
- f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -3317,7 +3105,7 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> &params
execute_cheatundo - undo the last search
-------------------------------------------------*/
-void debugger_commands::execute_cheatundo(const std::vector<std::string> &params)
+void debugger_commands::execute_cheatundo(const std::vector<std::string_view> &params)
{
if (m_cheat.undo > 0)
{
@@ -3346,15 +3134,15 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string> &params
execute_find - execute the find command
-------------------------------------------------*/
-void debugger_commands::execute_find(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[0], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// further validation
@@ -3370,11 +3158,11 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
- char const *pdata = params[i].c_str();
- auto const pdatalen = params[i].length() - 1;
+ std::string_view pdata = params[i];
- if (pdata[0] == '"' && pdata[pdatalen] == '"') // check for a string
+ if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') // check for a string
{
+ auto const pdatalen = params[i].length() - 1;
for (int j = 1; j < pdatalen; j++)
{
data_to_find[data_count] = pdata[j];
@@ -3385,17 +3173,20 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
{
// check for a 'b','w','d',or 'q' prefix
data_size[data_count] = cur_data_size;
- if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata += 2; }
+ if (pdata.length() >= 2)
+ {
+ if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
+ }
// look for a wildcard
- if (!strcmp(pdata, "?"))
+ if (pdata == "?")
data_size[data_count++] |= 0x10;
// otherwise, validate as a number
- else if (!validate_number_parameter(params[i], data_to_find[data_count++]))
+ else if (!m_console.validate_number_parameter(pdata, data_to_find[data_count++]))
return;
}
}
@@ -3413,36 +3204,37 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
for (int j = 0; j < data_count && match; j++)
{
offs_t address = space->byte_to_address(i + suboffset);
+ address_space *tspace;
switch (data_size[j])
{
case 1:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_byte(address) == u8(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_byte(address) == u8(data_to_find[j]);
else
match = false;
break;
case 2:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_word_unaligned(address) == u16(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_word_unaligned(address) == u16(data_to_find[j]);
else
match = false;
break;
case 4:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_dword_unaligned(address) == u32(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_dword_unaligned(address) == u32(data_to_find[j]);
else
match = false;
break;
case 8:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_qword_unaligned(address) == u64(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_qword_unaligned(address) == u64(data_to_find[j]);
else
match = false;
break;
@@ -3472,15 +3264,15 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
// execute_fill - execute the fill command
//-------------------------------------------------
-void debugger_commands::execute_fill(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[0], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// further validation
@@ -3495,12 +3287,12 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
- const char *pdata = params[i].c_str();
- size_t pdatalen = strlen(pdata) - 1;
+ std::string_view pdata = params[i];
// check for a string
- if (pdata[0] == '"' && pdata[pdatalen] == '"')
+ if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"')
{
+ auto const pdatalen = pdata.length() - 1;
for (int j = 1; j < pdatalen; j++)
{
fill_data[data_count] = pdata[j];
@@ -3513,13 +3305,16 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
{
// check for a 'b','w','d',or 'q' prefix
fill_data_size[data_count] = cur_data_size;
- if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata += 2; }
+ if (pdata.length() >= 2)
+ {
+ if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
+ }
// validate as a number
- if (!validate_number_parameter(pdata, fill_data[data_count++]))
+ if (!m_console.validate_number_parameter(pdata, fill_data[data_count++]))
return;
}
}
@@ -3536,7 +3331,8 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
for (int j = 0; j < data_count; j++)
{
offs_t address = space->byte_to_address(offset) & space->logaddrmask();
- if (!memory.translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, address))
+ address_space *tspace;
+ if (!memory.translate(space->spacenum(), device_memory_interface::TR_WRITE, address, tspace))
{
m_console.printf("Fill aborted due to page fault at %0*X\n", space->logaddrchars(), space->byte_to_address(offset) & space->logaddrmask());
length = 0;
@@ -3545,19 +3341,19 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
switch (fill_data_size[j])
{
case 1:
- space->write_byte(address, fill_data[j]);
+ tspace->write_byte(address, fill_data[j]);
break;
case 2:
- space->write_word_unaligned(address, fill_data[j]);
+ tspace->write_word_unaligned(address, fill_data[j]);
break;
case 4:
- space->write_dword_unaligned(address, fill_data[j]);
+ tspace->write_dword_unaligned(address, fill_data[j]);
break;
case 8:
- space->read_qword_unaligned(address, fill_data[j]);
+ tspace->read_qword_unaligned(address, fill_data[j]);
break;
}
offset += fill_data_size[j];
@@ -3577,20 +3373,20 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
execute_dasm - execute the dasm command
-------------------------------------------------*/
-void debugger_commands::execute_dasm(const std::vector<std::string> &params)
+void debugger_commands::execute_dasm(const std::vector<std::string_view> &params)
{
u64 offset, length;
bool bytes = true;
address_space *space;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (params.size() > 3 && !validate_boolean_parameter(params[3], bytes))
+ if (params.size() > 3 && !m_console.validate_boolean_parameter(params[3], bytes))
return;
- if (!validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space))
+ if (!m_console.validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space))
return;
// determine the width of the bytes
@@ -3636,7 +3432,8 @@ void debugger_commands::execute_dasm(const std::vector<std::string> &params)
}
/* write the data */
- std::ofstream f(params[0]);
+ std::string fname(params[0]);
+ std::ofstream f(fname);
if (!f.good())
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -3675,32 +3472,32 @@ void debugger_commands::execute_dasm(const std::vector<std::string> &params)
trace over and trace info
-------------------------------------------------*/
-void debugger_commands::execute_trace(const std::vector<std::string> &params, bool trace_over)
+void debugger_commands::execute_trace(const std::vector<std::string_view> &params, bool trace_over)
{
- const char *action = nullptr;
+ std::string_view action;
bool detect_loops = true;
bool logerror = false;
- device_t *cpu;
- const char *mode;
- std::string filename = params[0];
+ std::string filename(params[0]);
// replace macros
strreplace(filename, "{game}", m_machine.basename());
// validate parameters
- if (!validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu))
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu))
return;
if (params.size() > 2)
{
std::stringstream stream;
- stream.str(params[2]);
+ stream.str(std::string(params[2]));
std::string flag;
while (std::getline(stream, flag, '|'))
{
- if (!core_stricmp(flag.c_str(), "noloop"))
+ using namespace std::literals;
+ if (util::streqlower(flag, "noloop"sv))
detect_loops = false;
- else if (!core_stricmp(flag.c_str(), "logerror"))
+ else if (util::streqlower(flag, "logerror"sv))
logerror = true;
else
{
@@ -3709,24 +3506,27 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
}
}
}
- if (!debug_command_parameter_command(action = (params.size() > 3) ? params[3].c_str() : nullptr))
+ if (params.size() > 3 && !m_console.validate_command_parameter(action = params[3]))
return;
// open the file
- FILE *f = nullptr;
- if (core_stricmp(filename.c_str(), "off") != 0)
+ std::unique_ptr<std::ofstream> f;
+ using namespace std::literals;
+ if (!util::streqlower(filename, "off"sv))
{
- mode = "w";
+ std::ios_base::openmode mode = std::ios_base::out;
// opening for append?
if ((filename[0] == '>') && (filename[1] == '>'))
{
- mode = "a";
+ mode |= std::ios_base::ate;
filename = filename.substr(2);
}
+ else
+ mode |= std::ios_base::trunc;
- f = fopen(filename.c_str(), mode);
- if (!f)
+ f = std::make_unique<std::ofstream>(filename.c_str(), mode);
+ if (f->fail())
{
m_console.printf("Error opening file '%s'\n", params[0]);
return;
@@ -3734,8 +3534,9 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
}
// do it
- cpu->debug()->trace(f, trace_over, detect_loops, logerror, action);
- if (f)
+ bool const on(f);
+ cpu->debug()->trace(std::move(f), trace_over, detect_loops, logerror, action);
+ if (on)
m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename);
else
m_console.printf("Stopped tracing on CPU '%s'\n", cpu->tag());
@@ -3746,7 +3547,7 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
execute_traceflush - execute the trace flush command
-------------------------------------------------*/
-void debugger_commands::execute_traceflush(const std::vector<std::string> &params)
+void debugger_commands::execute_traceflush(const std::vector<std::string_view> &params)
{
m_machine.debugger().cpu().flush_traces();
}
@@ -3756,15 +3557,15 @@ void debugger_commands::execute_traceflush(const std::vector<std::string> &param
execute_history - execute the history command
-------------------------------------------------*/
-void debugger_commands::execute_history(const std::vector<std::string> &params)
+void debugger_commands::execute_history(const std::vector<std::string_view> &params)
{
// validate parameters
device_t *device;
- if (!validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device))
+ if (!m_console.validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device))
return;
u64 count = device_debug::HISTORY_SIZE;
- if (params.size() > 1 && !validate_number_parameter(params[1], count))
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], count))
return;
// further validation
@@ -3781,13 +3582,13 @@ void debugger_commands::execute_history(const std::vector<std::string> &params)
}
// loop over lines
- debug_disasm_buffer buffer(*device);
std::string instruction;
for (int index = int(unsigned(count)); index > 0; index--)
{
auto const pc = debug->history_pc(1 - index);
if (pc.second)
{
+ debug_disasm_buffer buffer(*device);
offs_t next_offset;
offs_t size;
u32 info;
@@ -3804,16 +3605,16 @@ void debugger_commands::execute_history(const std::vector<std::string> &params)
execute_trackpc - execute the trackpc command
-------------------------------------------------*/
-void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
+void debugger_commands::execute_trackpc(const std::vector<std::string_view> &params)
{
// Gather the on/off switch (if present)
bool turnOn = true;
- if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn))
+ if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn))
return;
// Gather the cpu id (if present)
device_t *cpu = nullptr;
- if (!validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu))
return;
const device_state_interface *state;
@@ -3825,7 +3626,7 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
// Should we clear the existing data?
bool clear = false;
- if (params.size() > 2 && !validate_boolean_parameter(params[2], clear))
+ if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear))
return;
cpu->debug()->set_track_pc((bool)turnOn);
@@ -3853,11 +3654,11 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
execute_trackmem - execute the trackmem command
-------------------------------------------------*/
-void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
+void debugger_commands::execute_trackmem(const std::vector<std::string_view> &params)
{
// Gather the on/off switch (if present)
bool turnOn = true;
- if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn))
+ if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn))
return;
// Gather the cpu id (if present)
@@ -3865,17 +3666,17 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
if (params.size() > 1)
cpuparam = params[1];
device_t *cpu = nullptr;
- if (!validate_cpu_parameter(cpuparam, cpu))
+ if (!m_console.validate_cpu_parameter(cpuparam, cpu))
return;
// Should we clear the existing data?
bool clear = false;
- if (params.size() > 2 && !validate_boolean_parameter(params[2], clear))
+ if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear))
return;
// Get the address space for the given cpu
address_space *space;
- if (!validate_device_space_parameter(cpuparam, AS_PROGRAM, space))
+ if (!m_console.validate_device_space_parameter(cpuparam, AS_PROGRAM, space))
return;
// Inform the CPU it's time to start tracking memory writes
@@ -3891,17 +3692,18 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
execute_pcatmem - execute the pcatmem command
-------------------------------------------------*/
-void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string_view> &params)
{
// Gather the required target address/space parameter
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
// Translate the address
offs_t a = address & space->logaddrmask();
- if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a))
+ address_space *tspace;
+ if (!space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, a, tspace))
{
m_console.printf("Address translation failed\n");
return;
@@ -3913,19 +3715,19 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str
switch (space->data_width())
{
case 8:
- data = space->read_byte(a);
+ data = tspace->read_byte(a);
break;
case 16:
- data = space->read_word_unaligned(a);
+ data = tspace->read_word_unaligned(a);
break;
case 32:
- data = space->read_dword_unaligned(a);
+ data = tspace->read_dword_unaligned(a);
break;
case 64:
- data = space->read_qword_unaligned(a);
+ data = tspace->read_qword_unaligned(a);
break;
}
@@ -3942,7 +3744,7 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str
execute_snap - execute the snapshot command
-------------------------------------------------*/
-void debugger_commands::execute_snap(const std::vector<std::string> &params)
+void debugger_commands::execute_snap(const std::vector<std::string_view> &params)
{
/* if no params, use the default behavior */
if (params.empty())
@@ -3954,8 +3756,9 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
/* otherwise, we have to open the file ourselves */
else
{
- const char *filename = params[0].c_str();
- int scrnum = (params.size() > 1) ? atoi(params[1].c_str()) : 0;
+ u64 scrnum = 0;
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], scrnum))
+ return;
screen_device_enumerator iter(m_machine.root_device());
screen_device *screen = iter.byindex(scrnum);
@@ -3966,7 +3769,7 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
return;
}
- std::string fname(filename);
+ std::string fname(params[0]);
if (fname.find(".png") == -1)
fname.append(".png");
emu_file file(m_machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
@@ -3974,12 +3777,12 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
if (filerr)
{
- m_console.printf("Error creating file '%s' (%s:%d %s)\n", filename, filerr.category().name(), filerr.value(), filerr.message());
+ m_console.printf("Error creating file '%s' (%s:%d %s)\n", params[0], filerr.category().name(), filerr.value(), filerr.message());
return;
}
screen->machine().video().save_snapshot(screen, file);
- m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, filename);
+ m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, params[0]);
}
}
@@ -3988,9 +3791,10 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
execute_source - execute the source command
-------------------------------------------------*/
-void debugger_commands::execute_source(const std::vector<std::string> &params)
+void debugger_commands::execute_source(const std::vector<std::string_view> &params)
{
- m_console.source_script(params[0].c_str());
+ std::string filename(params[0]);
+ m_console.source_script(filename.c_str());
}
@@ -3998,27 +3802,29 @@ void debugger_commands::execute_source(const std::vector<std::string> &params)
execute_map - execute the map command
-------------------------------------------------*/
-void debugger_commands::execute_map(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_map(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
+ address &= space->logaddrmask();
// do the translation first
- for (int intention = TRANSLATE_READ_DEBUG; intention <= TRANSLATE_FETCH_DEBUG; intention++)
+ for (int intention = device_memory_interface::TR_READ; intention <= device_memory_interface::TR_FETCH; intention++)
{
static const char *const intnames[] = { "Read", "Write", "Fetch" };
- offs_t taddress = address & space->addrmask();
- if (space->device().memory().translate(space->spacenum(), intention, taddress))
+ offs_t taddress = address;
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), intention, taddress, tspace))
{
- std::string mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress);
+ std::string mapname = tspace->get_handler_string((intention == device_memory_interface::TR_WRITE) ? read_or_write::WRITE : read_or_write::READ, taddress);
m_console.printf(
- "%7s: %0*X logical == %0*X physical -> %s\n",
+ "%7s: %0*X logical %s == %0*X physical %s -> %s\n",
intnames[intention & 3],
- space->logaddrchars(), address,
- space->addrchars(), taddress,
+ space->logaddrchars(), address, space->name(),
+ tspace->addrchars(), taddress, tspace->name(),
mapname);
}
else
@@ -4031,14 +3837,15 @@ void debugger_commands::execute_map(int spacenum, const std::vector<std::string>
execute_memdump - execute the memdump command
-------------------------------------------------*/
-void debugger_commands::execute_memdump(const std::vector<std::string> &params)
+void debugger_commands::execute_memdump(const std::vector<std::string_view> &params)
{
device_t *root = &m_machine.root_device();
- if ((params.size() >= 2) && !validate_device_parameter(params[1], root))
+ if ((params.size() >= 2) && !m_console.validate_device_parameter(params[1], root))
return;
- char const *const filename = params.empty() ? "memdump.log" : params[0].c_str();
- FILE *const file = fopen(filename, "w");
+ using namespace std::literals;
+ std::string filename = params.empty() ? "memdump.log"s : std::string(params[0]);
+ FILE *const file = fopen(filename.c_str(), "w");
if (!file)
{
m_console.printf("Error opening file %s\n", filename);
@@ -4097,7 +3904,7 @@ void debugger_commands::execute_memdump(const std::vector<std::string> &params)
execute_symlist - execute the symlist command
-------------------------------------------------*/
-void debugger_commands::execute_symlist(const std::vector<std::string> &params)
+void debugger_commands::execute_symlist(const std::vector<std::string_view> &params)
{
const char *namelist[1000];
symbol_table *symtable;
@@ -4107,7 +3914,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> &params)
{
// validate parameters
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
symtable = &cpu->debug()->symtable();
m_console.printf("CPU '%s' symbols:\n", cpu->tag());
@@ -4159,7 +3966,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> &params)
execute_softreset - execute the softreset command
-------------------------------------------------*/
-void debugger_commands::execute_softreset(const std::vector<std::string> &params)
+void debugger_commands::execute_softreset(const std::vector<std::string_view> &params)
{
m_machine.schedule_soft_reset();
}
@@ -4169,7 +3976,7 @@ void debugger_commands::execute_softreset(const std::vector<std::string> &params
execute_hardreset - execute the hardreset command
-------------------------------------------------*/
-void debugger_commands::execute_hardreset(const std::vector<std::string> &params)
+void debugger_commands::execute_hardreset(const std::vector<std::string_view> &params)
{
m_machine.schedule_hard_reset();
}
@@ -4179,7 +3986,7 @@ void debugger_commands::execute_hardreset(const std::vector<std::string> &params
mounted files
-------------------------------------------------*/
-void debugger_commands::execute_images(const std::vector<std::string> &params)
+void debugger_commands::execute_images(const std::vector<std::string_view> &params)
{
image_interface_enumerator iter(m_machine.root_device());
for (device_image_interface &img : iter)
@@ -4209,16 +4016,25 @@ void debugger_commands::execute_images(const std::vector<std::string> &params)
execute_mount - execute the image mount command
-------------------------------------------------*/
-void debugger_commands::execute_mount(const std::vector<std::string> &params)
+void debugger_commands::execute_mount(const std::vector<std::string_view> &params)
{
for (device_image_interface &img : image_interface_enumerator(m_machine.root_device()))
{
if ((img.instance_name() == params[0]) || (img.brief_instance_name() == params[0]))
{
- if (img.load(params[1]) != image_init_result::PASS)
- m_console.printf("Unable to mount file %s on %s\n", params[1], params[0]);
- else
+ auto [err, msg] = img.load(params[1]);
+ if (!err)
+ {
m_console.printf("File %s mounted on %s\n", params[1], params[0]);
+ }
+ else
+ {
+ m_console.printf(
+ "Unable to mount file %s on %s: %s\n",
+ params[1],
+ params[0],
+ !msg.empty() ? msg : err.message());
+ }
return;
}
}
@@ -4229,7 +4045,7 @@ void debugger_commands::execute_mount(const std::vector<std::string> &params)
execute_unmount - execute the image unmount command
-------------------------------------------------*/
-void debugger_commands::execute_unmount(const std::vector<std::string> &params)
+void debugger_commands::execute_unmount(const std::vector<std::string_view> &params)
{
for (device_image_interface &img : image_interface_enumerator(m_machine.root_device()))
{
@@ -4256,9 +4072,9 @@ void debugger_commands::execute_unmount(const std::vector<std::string> &params)
natural keyboard input
-------------------------------------------------*/
-void debugger_commands::execute_input(const std::vector<std::string> &params)
+void debugger_commands::execute_input(const std::vector<std::string_view> &params)
{
- m_machine.natkeyboard().post_coded(params[0].c_str());
+ m_machine.natkeyboard().post_coded(params[0]);
}
@@ -4267,15 +4083,15 @@ void debugger_commands::execute_input(const std::vector<std::string> &params)
keyboard codes
-------------------------------------------------*/
-void debugger_commands::execute_dumpkbd(const std::vector<std::string> &params)
+void debugger_commands::execute_dumpkbd(const std::vector<std::string_view> &params)
{
// was there a file specified?
- const char *filename = !params.empty() ? params[0].c_str() : nullptr;
+ std::string filename = !params.empty() ? std::string(params[0]) : std::string();
FILE *file = nullptr;
- if (filename != nullptr)
+ if (!filename.empty())
{
// if so, open it
- file = fopen(filename, "w");
+ file = fopen(filename.c_str(), "w");
if (file == nullptr)
{
m_console.printf("Cannot open \"%s\"\n", filename);
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index fd0bcea673a..134f838f8a7 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -24,27 +24,6 @@ class debugger_commands
public:
debugger_commands(running_machine &machine, debugger_cpu &cpu, debugger_console &console);
- // validates a parameter as a boolean value
- bool validate_boolean_parameter(const std::string &param, bool &result);
-
- // validates a parameter as a numeric value
- bool validate_number_parameter(std::string_view param, u64 &result);
-
- // validates a parameter as a device
- bool validate_device_parameter(std::string_view param, device_t *&result);
-
- // validates a parameter as a CPU
- bool validate_cpu_parameter(std::string_view param, device_t *&result);
-
- // validates a parameter as an address space identifier
- bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result);
-
- // validates a parameter as a target address and retrieves the given address space and address
- bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr);
-
- // validates a parameter as a memory region name and retrieves the given region
- bool validate_memory_region_parameter(std::string_view param, memory_region *&result);
-
private:
struct global_entry
{
@@ -87,11 +66,6 @@ private:
u8 disabled = 0U;
};
- device_t &get_device_search_base(std::string_view &param);
- device_t *get_cpu_by_index(u64 cpunum);
- bool debug_command_parameter_expression(std::string_view param, parsed_expression &result);
- bool debug_command_parameter_command(const char *param);
-
bool cheat_address_is_valid(address_space &space, offs_t address);
u64 get_cpunum();
@@ -99,86 +73,93 @@ private:
u64 global_get(global_entry *global);
void global_set(global_entry *global, u64 value);
- int mini_printf(char *buffer, const char *format, int params, u64 *param);
+ bool mini_printf(std::ostream &stream, const std::vector<std::string_view> &params);
template <typename T>
- void execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message);
-
- void execute_help(const std::vector<std::string> &params);
- void execute_print(const std::vector<std::string> &params);
- void execute_printf(const std::vector<std::string> &params);
- void execute_logerror(const std::vector<std::string> &params);
- void execute_tracelog(const std::vector<std::string> &params);
- void execute_tracesym(const std::vector<std::string> &params);
- void execute_cls(const std::vector<std::string> &params);
- void execute_quit(const std::vector<std::string> &params);
- void execute_do(const std::vector<std::string> &params);
- void execute_step(const std::vector<std::string> &params);
- void execute_over(const std::vector<std::string> &params);
- void execute_out(const std::vector<std::string> &params);
- void execute_go(const std::vector<std::string> &params);
- void execute_go_vblank(const std::vector<std::string> &params);
- void execute_go_interrupt(const std::vector<std::string> &params);
- void execute_go_exception(const std::vector<std::string> &params);
- void execute_go_time(const std::vector<std::string> &params);
- void execute_go_privilege(const std::vector<std::string> &params);
- void execute_focus(const std::vector<std::string> &params);
- void execute_ignore(const std::vector<std::string> &params);
- void execute_observe(const std::vector<std::string> &params);
- void execute_suspend(const std::vector<std::string> &params);
- void execute_resume(const std::vector<std::string> &params);
- void execute_next(const std::vector<std::string> &params);
- void execute_cpulist(const std::vector<std::string> &params);
- void execute_comment_add(const std::vector<std::string> &params);
- void execute_comment_del(const std::vector<std::string> &params);
- void execute_comment_save(const std::vector<std::string> &params);
- void execute_comment_list(const std::vector<std::string> &params);
- void execute_comment_commit(const std::vector<std::string> &params);
- void execute_bpset(const std::vector<std::string> &params);
- void execute_bpclear(const std::vector<std::string> &params);
- void execute_bpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_bplist(const std::vector<std::string> &params);
- void execute_wpset(int spacenum, const std::vector<std::string> &params);
- void execute_wpclear(const std::vector<std::string> &params);
- void execute_wpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_wplist(const std::vector<std::string> &params);
- void execute_rpset(const std::vector<std::string> &params);
- void execute_rpclear(const std::vector<std::string> &params);
- void execute_rpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_rplist(const std::vector<std::string> &params);
- void execute_statesave(const std::vector<std::string> &params);
- void execute_stateload(const std::vector<std::string> &params);
- void execute_rewind(const std::vector<std::string> &params);
- void execute_save(int spacenum, const std::vector<std::string> &params);
- void execute_saveregion(const std::vector<std::string> &params);
- void execute_load(int spacenum, const std::vector<std::string> &params);
- void execute_loadregion(const std::vector<std::string> &params);
- void execute_dump(int spacenum, const std::vector<std::string> &params);
- void execute_strdump(int spacenum, const std::vector<std::string> &params);
- void execute_cheatrange(bool init, const std::vector<std::string> &params);
- void execute_cheatnext(bool initial, const std::vector<std::string> &params);
- void execute_cheatlist(const std::vector<std::string> &params);
- void execute_cheatundo(const std::vector<std::string> &params);
- void execute_dasm(const std::vector<std::string> &params);
- void execute_find(int spacenum, const std::vector<std::string> &params);
- void execute_fill(int spacenum, const std::vector<std::string> &params);
- void execute_trace(const std::vector<std::string> &params, bool trace_over);
- void execute_traceflush(const std::vector<std::string> &params);
- void execute_history(const std::vector<std::string> &params);
- void execute_trackpc(const std::vector<std::string> &params);
- void execute_trackmem(const std::vector<std::string> &params);
- void execute_pcatmem(int spacenum, const std::vector<std::string> &params);
- void execute_snap(const std::vector<std::string> &params);
- void execute_source(const std::vector<std::string> &params);
- void execute_map(int spacenum, const std::vector<std::string> &params);
- void execute_memdump(const std::vector<std::string> &params);
- void execute_symlist(const std::vector<std::string> &params);
- void execute_softreset(const std::vector<std::string> &params);
- void execute_hardreset(const std::vector<std::string> &params);
- void execute_images(const std::vector<std::string> &params);
- void execute_mount(const std::vector<std::string> &params);
- void execute_unmount(const std::vector<std::string> &params);
- void execute_input(const std::vector<std::string> &params);
- void execute_dumpkbd(const std::vector<std::string> &params);
+ void execute_index_command(std::vector<std::string_view> const &params, T &&apply, char const *unused_message);
+
+ void execute_help(const std::vector<std::string_view> &params);
+ void execute_print(const std::vector<std::string_view> &params);
+ void execute_printf(const std::vector<std::string_view> &params);
+ void execute_logerror(const std::vector<std::string_view> &params);
+ void execute_tracelog(const std::vector<std::string_view> &params);
+ void execute_tracesym(const std::vector<std::string_view> &params);
+ void execute_cls(const std::vector<std::string_view> &params);
+ void execute_quit(const std::vector<std::string_view> &params);
+ void execute_do(const std::vector<std::string_view> &params);
+ void execute_step(const std::vector<std::string_view> &params);
+ void execute_over(const std::vector<std::string_view> &params);
+ void execute_out(const std::vector<std::string_view> &params);
+ void execute_go(const std::vector<std::string_view> &params);
+ void execute_go_vblank(const std::vector<std::string_view> &params);
+ void execute_go_interrupt(const std::vector<std::string_view> &params);
+ void execute_go_exception(const std::vector<std::string_view> &params);
+ void execute_go_time(const std::vector<std::string_view> &params);
+ void execute_go_privilege(const std::vector<std::string_view> &params);
+ void execute_go_branch(bool sense, const std::vector<std::string_view> &params);
+ void execute_go_next_instruction(const std::vector<std::string_view> &params);
+ void execute_focus(const std::vector<std::string_view> &params);
+ void execute_ignore(const std::vector<std::string_view> &params);
+ void execute_observe(const std::vector<std::string_view> &params);
+ void execute_suspend(const std::vector<std::string_view> &params);
+ void execute_resume(const std::vector<std::string_view> &params);
+ void execute_next(const std::vector<std::string_view> &params);
+ void execute_cpulist(const std::vector<std::string_view> &params);
+ void execute_time(const std::vector<std::string_view> &params);
+ void execute_comment_add(const std::vector<std::string_view> &params);
+ void execute_comment_del(const std::vector<std::string_view> &params);
+ void execute_comment_save(const std::vector<std::string_view> &params);
+ void execute_comment_list(const std::vector<std::string_view> &params);
+ void execute_comment_commit(const std::vector<std::string_view> &params);
+ void execute_bpset(const std::vector<std::string_view> &params);
+ void execute_bpclear(const std::vector<std::string_view> &params);
+ void execute_bpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_bplist(const std::vector<std::string_view> &params);
+ void execute_wpset(int spacenum, const std::vector<std::string_view> &params);
+ void execute_wpclear(const std::vector<std::string_view> &params);
+ void execute_wpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_wplist(const std::vector<std::string_view> &params);
+ void execute_rpset(const std::vector<std::string_view> &params);
+ void execute_rpclear(const std::vector<std::string_view> &params);
+ void execute_rpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_rplist(const std::vector<std::string_view> &params);
+ void execute_epset(const std::vector<std::string_view> &params);
+ void execute_epclear(const std::vector<std::string_view> &params);
+ void execute_epdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_eplist(const std::vector<std::string_view> &params);
+ void execute_statesave(const std::vector<std::string_view> &params);
+ void execute_stateload(const std::vector<std::string_view> &params);
+ void execute_rewind(const std::vector<std::string_view> &params);
+ void execute_save(int spacenum, const std::vector<std::string_view> &params);
+ void execute_saveregion(const std::vector<std::string_view> &params);
+ void execute_load(int spacenum, const std::vector<std::string_view> &params);
+ void execute_loadregion(const std::vector<std::string_view> &params);
+ void execute_dump(int spacenum, const std::vector<std::string_view> &params);
+ void execute_strdump(int spacenum, const std::vector<std::string_view> &params);
+ void execute_cheatrange(bool init, const std::vector<std::string_view> &params);
+ void execute_cheatnext(bool initial, const std::vector<std::string_view> &params);
+ void execute_cheatlist(const std::vector<std::string_view> &params);
+ void execute_cheatundo(const std::vector<std::string_view> &params);
+ void execute_dasm(const std::vector<std::string_view> &params);
+ void execute_find(int spacenum, const std::vector<std::string_view> &params);
+ void execute_fill(int spacenum, const std::vector<std::string_view> &params);
+ void execute_trace(const std::vector<std::string_view> &params, bool trace_over);
+ void execute_traceflush(const std::vector<std::string_view> &params);
+ void execute_history(const std::vector<std::string_view> &params);
+ void execute_trackpc(const std::vector<std::string_view> &params);
+ void execute_trackmem(const std::vector<std::string_view> &params);
+ void execute_pcatmem(int spacenum, const std::vector<std::string_view> &params);
+ void execute_snap(const std::vector<std::string_view> &params);
+ void execute_source(const std::vector<std::string_view> &params);
+ void execute_map(int spacenum, const std::vector<std::string_view> &params);
+ void execute_memdump(const std::vector<std::string_view> &params);
+ void execute_symlist(const std::vector<std::string_view> &params);
+ void execute_softreset(const std::vector<std::string_view> &params);
+ void execute_hardreset(const std::vector<std::string_view> &params);
+ void execute_images(const std::vector<std::string_view> &params);
+ void execute_mount(const std::vector<std::string_view> &params);
+ void execute_unmount(const std::vector<std::string_view> &params);
+ void execute_input(const std::vector<std::string_view> &params);
+ void execute_dumpkbd(const std::vector<std::string_view> &params);
running_machine& m_machine;
debugger_console& m_console;
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index 32a4888c285..ec5bc154751 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/*********************************************************************
debugcon.cpp
@@ -16,6 +16,8 @@
#include "textbuf.h"
#include "debugger.h"
+#include "fileio.h"
+#include "main.h"
#include "corestr.h"
@@ -86,10 +88,14 @@ debugger_console::debugger_console(running_machine &machine)
}
}
+debugger_console::~debugger_console()
+{
+}
-/*-------------------------------------------------
- exit - frees the console system
--------------------------------------------------*/
+
+//-------------------------------------------------
+// exit - frees the console system
+//-------------------------------------------------
void debugger_console::exit()
{
@@ -114,41 +120,39 @@ void debugger_console::exit()
inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const debug_command &b) const
{
- return core_stricmp(a.command.c_str(), b.command.c_str()) < 0;
+ return a.command < b.command;
}
inline bool debugger_console::debug_command::compare::operator()(const char *a, const debug_command &b) const
{
- return core_stricmp(a, b.command.c_str()) < 0;
+ return strcmp(a, b.command.c_str()) < 0;
}
inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const char *b) const
{
- return core_stricmp(a.command.c_str(), b) < 0;
+ return strcmp(a.command.c_str(), b) < 0;
}
-debugger_console::debug_command::debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler)
+debugger_console::debug_command::debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string_view> &)> &&_handler)
: command(_command), params(nullptr), help(nullptr), handler(std::move(_handler)), flags(_flags), minparams(_minparams), maxparams(_maxparams)
{
}
-/*------------------------------------------------------------
- execute_help_custom - execute the helpcustom command
-------------------------------------------------------------*/
+//------------------------------------------------------------
+// execute_help_custom - execute the helpcustom command
+//------------------------------------------------------------
-void debugger_console::execute_help_custom(const std::vector<std::string> &params)
+void debugger_console::execute_help_custom(const std::vector<std::string_view> &params)
{
- char buf[64];
for (const debug_command &cmd : m_commandlist)
{
if (cmd.flags & CMDFLAG_CUSTOM_HELP)
{
- snprintf(buf, 63, "%s help", cmd.command.c_str());
- buf[63] = 0;
- char *temp_params[1] = { buf };
- internal_execute_command(true, 1, &temp_params[0]);
+ std::string buf = cmd.command + " help";
+ std::vector<std::string_view> temp_params = { buf };
+ internal_execute_command(true, temp_params);
}
}
}
@@ -157,9 +161,9 @@ void debugger_console::execute_help_custom(const std::vector<std::string> &param
execute_condump - execute the condump command
------------------------------------------------------------*/
-void debugger_console::execute_condump(const std::vector<std::string>& params)
+void debugger_console::execute_condump(const std::vector<std::string_view>& params)
{
- std::string filename = params[0];
+ std::string filename(params[0]);
const char* mode;
/* replace macros */
@@ -195,166 +199,149 @@ void debugger_console::execute_condump(const std::vector<std::string>& params)
// symbol table
//-------------------------------------------------
-symbol_table &debugger_console::visible_symtable()
+symbol_table &debugger_console::visible_symtable() const
{
return m_visiblecpu->debug()->symtable();
}
-/*-------------------------------------------------
- trim_parameter - executes a
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// trim_parameter - trim spaces and quotes around
+// a command parameter
+//-------------------------------------------------
-void debugger_console::trim_parameter(char **paramptr, bool keep_quotes)
+std::string_view debugger_console::trim_parameter(std::string_view param, bool keep_quotes)
{
- char *param = *paramptr;
- size_t len = strlen(param);
+ std::string_view::size_type len = param.length();
bool repeat;
- /* loop until all adornments are gone */
+ // loop until all adornments are gone
do
{
repeat = false;
- /* check for begin/end quotes */
+ // check for begin/end quotes
if (len >= 2 && param[0] == '"' && param[len - 1] == '"')
{
if (!keep_quotes)
{
- param[len - 1] = 0;
- param++;
+ param = param.substr(1, len - 2);
len -= 2;
}
}
- /* check for start/end braces */
+ // check for start/end braces
else if (len >= 2 && param[0] == '{' && param[len - 1] == '}')
{
- param[len - 1] = 0;
- param++;
+ param = param.substr(1, len - 2);
len -= 2;
repeat = true;
}
- /* check for leading spaces */
+ // check for leading spaces
else if (len >= 1 && param[0] == ' ')
{
- param++;
+ param.remove_prefix(1);
len--;
repeat = true;
}
- /* check for trailing spaces */
+ // check for trailing spaces
else if (len >= 1 && param[len - 1] == ' ')
{
- param[len - 1] = 0;
+ param.remove_suffix(1);
len--;
repeat = true;
}
} while (repeat);
- *paramptr = param;
+ return param;
}
-/*-------------------------------------------------
- internal_execute_command - executes a
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// internal_execute_command - executes a
+// command
+//-------------------------------------------------
-CMDERR debugger_console::internal_execute_command(bool execute, int params, char **param)
+CMDERR debugger_console::internal_execute_command(bool execute, std::vector<std::string_view> &params)
{
// no params is an error
- if (params == 0)
+ if (params.empty())
return CMDERR::none();
// the first parameter has the command and the real first parameter; separate them
- char *p, *command;
- for (p = param[0]; *p && isspace(u8(*p)); p++) { }
- for (command = p; *p && !isspace(u8(*p)); p++) { }
- if (*p != 0)
- {
- *p++ = 0;
- for ( ; *p && isspace(u8(*p)); p++) { }
- if (*p != 0)
- param[0] = p;
- else
- params = 0;
- }
+ std::string_view command_param = params[0];
+ std::string_view::size_type pos = 0;
+ while (pos < command_param.length() && !isspace(u8(command_param[pos])))
+ pos++;
+ const std::string command(strmakelower(command_param.substr(0, pos)));
+ while (pos < command_param.length() && isspace(u8(command_param[pos])))
+ pos++;
+ if (pos == command_param.length() && params.size() == 1)
+ params.clear();
else
- {
- params = 0;
- param[0] = nullptr;
- }
+ params[0].remove_prefix(pos);
// search the command list
- size_t const len = strlen(command);
- auto const found = m_commandlist.lower_bound(command);
+ auto const found = m_commandlist.lower_bound(command.c_str());
// error if not found
- if ((m_commandlist.end() == found) || core_strnicmp(command, found->command.c_str(), len))
+ if (m_commandlist.end() == found || std::string_view(command) != std::string_view(found->command).substr(0, command.length()))
return CMDERR::unknown_command(0);
- if (found->command.length() > len)
+ if (found->command.length() > command.length())
{
auto const next = std::next(found);
- if ((m_commandlist.end() != next) && !core_strnicmp(command, next->command.c_str(), len))
+ if (m_commandlist.end() != next && std::string_view(command) == std::string_view(next->command).substr(0, command.length()))
return CMDERR::ambiguous_command(0);
}
- // NUL-terminate and trim space around all the parameters
- for (int i = 1; i < params; i++)
- *param[i]++ = 0;
-
// now go back and trim quotes and braces and any spaces they reveal
- for (int i = 0; i < params; i++)
- trim_parameter(&param[i], found->flags & CMDFLAG_KEEP_QUOTES);
+ for (std::string_view &param : params)
+ param = trim_parameter(param, found->flags & CMDFLAG_KEEP_QUOTES);
// see if we have the right number of parameters
- if (params < found->minparams)
+ if (params.size() < found->minparams)
return CMDERR::not_enough_params(0);
- if (params > found->maxparams)
+ if (params.size() > found->maxparams)
return CMDERR::too_many_params(0);
// execute the handler
if (execute)
- {
- std::vector<std::string> params_vec(param, param + params);
- found->handler(params_vec);
- }
+ found->handler(params);
return CMDERR::none();
}
-/*-------------------------------------------------
- internal_parse_command - parses a command
- and either executes or just validates it
--------------------------------------------------*/
+//-------------------------------------------------
+// internal_parse_command - parses a command
+// and either executes or just validates it
+//-------------------------------------------------
-CMDERR debugger_console::internal_parse_command(const std::string &original_command, bool execute)
+CMDERR debugger_console::internal_parse_command(std::string_view command, bool execute)
{
- char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH];
- char *params[MAX_COMMAND_PARAMS] = { nullptr };
- char *command_start;
- char *p, c = 0;
-
- /* make a copy of the command */
- strcpy(command, original_command.c_str());
+ std::string_view::size_type pos = 0;
+ std::string_view::size_type len = command.length();
- /* loop over all semicolon-separated stuff */
- for (p = command; *p != 0; )
+ while (pos < len)
{
- int paramcount = 0, parendex = 0;
+ std::string parens;
+ std::vector<std::string_view> params;
bool foundend = false, instring = false, isexpr = false;
- /* find a semicolon or the end */
- for (params[paramcount++] = p; !foundend; p++)
+ // skip leading spaces
+ while (pos < len && isspace(u8(command[pos])))
+ pos++;
+ std::string_view::size_type startpos = pos;
+
+ // find a semicolon or the end
+ for (params.push_back(command.substr(pos)); !foundend && pos < len; pos++)
{
- c = *p;
+ char c = command[pos];
if (instring)
{
- if (c == '"' && p[-1] != '\\')
+ if (c == '"' && command[pos - 1] != '\\')
instring = false;
}
else
@@ -364,47 +351,44 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
case '"': instring = true; break;
case '(':
case '[':
- case '{': parens[parendex++] = c; break;
- case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break;
- case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break;
- case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break;
- case ',': if (parendex == 0) params[paramcount++] = p; break;
- case ';': if (parendex == 0) foundend = true; break;
- case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break;
- case '+': if (parendex == 0 && paramcount == 1 && p[1] == '+') isexpr = true; *p = c; break;
- case '=': if (parendex == 0 && paramcount == 1) isexpr = true; *p = c; break;
- case 0: foundend = true; break;
- default: *p = c; break;
+ case '{': parens.push_back(c); break;
+ case ')': if (parens.empty() || parens.back() != '(') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case ']': if (parens.empty() || parens.back() != '[') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case '}': if (parens.empty() || parens.back() != '{') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case ',': if (parens.empty()) { params.back().remove_suffix(len - pos); params.push_back(command.substr(pos + 1)); } break;
+ case ';': if (parens.empty()) { params.back().remove_suffix(len - pos); foundend = true; } break;
+ case '-': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '-') isexpr = true; break;
+ case '+': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '+') isexpr = true; break;
+ case '=': if (parens.empty() && params.size() == 1) isexpr = true; break;
+ default: break;
}
}
}
- /* check for unbalanced parentheses or quotes */
+ // check for unbalanced parentheses or quotes
if (instring)
- return CMDERR::unbalanced_quotes(p - command);
- if (parendex != 0)
- return CMDERR::unbalanced_parens(p - command);
-
- /* NULL-terminate if we ended in a semicolon */
- p--;
- if (c == ';') *p++ = 0;
+ return CMDERR::unbalanced_quotes(pos);
+ if (!parens.empty())
+ return CMDERR::unbalanced_parens(pos);
- /* process the command */
- command_start = params[0];
+ // process the command
+ std::string_view command_or_expr = params[0];
- /* allow for "do" commands */
- if (tolower(u8(command_start[0])) == 'd' && tolower(u8(command_start[1])) == 'o' && isspace(u8(command_start[2])))
+ // allow for "do" commands
+ if (command_or_expr.length() > 3 && tolower(u8(command_or_expr[0])) == 'd' && tolower(u8(command_or_expr[1])) == 'o' && isspace(u8(command_or_expr[2])))
{
isexpr = true;
- command_start += 3;
+ command_or_expr.remove_prefix(3);
}
- /* if it smells like an assignment expression, treat it as such */
- if (isexpr && paramcount == 1)
+ // if it smells like an assignment expression, treat it as such
+ if (isexpr && params.size() == 1)
{
try
{
- parsed_expression(visible_symtable(), command_start).execute();
+ parsed_expression expr(visible_symtable(), command_or_expr);
+ if (execute)
+ expr.execute();
}
catch (expression_error &err)
{
@@ -413,29 +397,29 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
}
else
{
- const CMDERR result = internal_execute_command(execute, paramcount, &params[0]);
+ const CMDERR result = internal_execute_command(execute, params);
if (result.error_class() != CMDERR::NONE)
- return CMDERR(result.error_class(), command_start - command);
+ return CMDERR(result.error_class(), startpos);
}
}
return CMDERR::none();
}
-/*-------------------------------------------------
- execute_command - execute a command string
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_command - execute a command string
+//-------------------------------------------------
-CMDERR debugger_console::execute_command(const std::string &command, bool echo)
+CMDERR debugger_console::execute_command(std::string_view command, bool echo)
{
- /* echo if requested */
+ // echo if requested
if (echo)
printf(">%s\n", command);
- /* parse and execute */
+ // parse and execute
const CMDERR result = internal_parse_command(command, true);
- /* display errors */
+ // display errors
if (result.error_class() != CMDERR::NONE)
{
if (!echo)
@@ -444,7 +428,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
printf("%s\n", cmderr_to_string(result));
}
- /* update all views */
+ // update all views
if (echo)
{
m_machine.debug_view().update_all();
@@ -454,11 +438,11 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
}
-/*-------------------------------------------------
- validate_command - validate a command string
--------------------------------------------------*/
+//-------------------------------------------------
+// validate_command - validate a command string
+//-------------------------------------------------
-CMDERR debugger_console::validate_command(const char *command)
+CMDERR debugger_console::validate_command(std::string_view command)
{
return internal_parse_command(command, false);
}
@@ -468,7 +452,7 @@ CMDERR debugger_console::validate_command(const char *command)
register_command - register a command handler
-------------------------------------------------*/
-void debugger_console::register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler)
+void debugger_console::register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string_view> &)> &&handler)
{
if (m_machine.phase() != machine_phase::INIT)
throw emu_fatalerror("Can only call debugger_console::register_command() at init time!");
@@ -576,6 +560,494 @@ std::string debugger_console::cmderr_to_string(CMDERR error)
}
+//**************************************************************************
+// PARAMETER VALIDATION HELPERS
+//**************************************************************************
+
+namespace {
+
+template <typename T>
+inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim)
+{
+ unsigned parens = 0;
+ for (std::string_view::size_type i = 0; str.length() > i; ++i)
+ {
+ if (str[i] == '(')
+ {
+ ++parens;
+ }
+ else if (parens)
+ {
+ if (str[i] == ')')
+ --parens;
+ }
+ else if (is_delim(str[i]))
+ {
+ return i;
+ }
+ }
+ return std::string_view::npos;
+}
+
+} // anonymous namespace
+
+
+/// \brief Validate parameter as a Boolean value
+///
+/// Validates a parameter as a Boolean value. Fixed strings and
+/// expressions evaluating to numeric values are recognised. The result
+/// is unchanged for an empty string.
+/// \param [in] param The parameter string.
+/// \param [in,out] result The default value on entry, and the value of
+/// the parameter interpreted as a Boolean on success. Unchanged if
+/// the parameter is an empty string.
+/// \return true if the parameter is a valid Boolean value or an empty
+/// string, or false otherwise.
+bool debugger_console::validate_boolean_parameter(std::string_view param, bool &result)
+{
+ // nullptr parameter does nothing and returns no error
+ if (param.empty())
+ return true;
+
+ // evaluate the expression; success if no error
+ using namespace std::literals;
+ bool const is_true = util::streqlower(param, "true"sv);
+ bool const is_false = util::streqlower(param, "false"sv);
+
+ if (is_true || is_false)
+ {
+ result = is_true;
+ return true;
+ }
+
+ // try to evaluate as a number
+ u64 val;
+ if (!validate_number_parameter(param, val))
+ return false;
+
+ result = val != 0;
+ return true;
+}
+
+
+/// \brief Validate parameter as a numeric value
+///
+/// Parses the parameter as an expression and evaluates it as a number.
+/// \param [in] param The parameter string.
+/// \param [out] result The numeric value of the expression on success.
+/// Unchanged on failure.
+/// \return true if the parameter is a valid expression that evaluates
+/// to a numeric value, or false otherwise.
+bool debugger_console::validate_number_parameter(std::string_view param, u64 &result)
+{
+ // evaluate the expression; success if no error
+ try
+ {
+ result = parsed_expression(visible_symtable(), param).execute();
+ return true;
+ }
+ catch (expression_error const &error)
+ {
+ // print an error pointing to the character that caused it
+ printf("Error in expression: %s\n", param);
+ printf(" %*s^", error.offset(), "");
+ printf("%s\n", error.code_string());
+ return false;
+ }
+}
+
+
+/// \brief Validate parameter as a device
+///
+/// Validates a parameter as a device identifier and retrieves the
+/// device on success. A string corresponding to the tag of a device
+/// refers to that device; an empty string refers to the current CPU
+/// with debugger focus; any other string is parsed as an expression
+/// and treated as an index of a device implementing
+/// #device_execute_interface and #device_state_interface, and exposing
+/// a generic PC base value.
+/// \param [in] param The parameter string.
+/// \param [out] result A pointer to the device on success, or unchanged
+/// on failure.
+/// \return true if the parameter refers to a device in the current
+/// system, or false otherwise.
+bool debugger_console::validate_device_parameter(std::string_view param, device_t *&result)
+{
+ // if no parameter, use the visible CPU
+ if (param.empty())
+ {
+ device_t *const current = m_visiblecpu;
+ if (current)
+ {
+ result = current;
+ return true;
+ }
+ else
+ {
+ printf("No valid CPU is currently selected\n");
+ return false;
+ }
+ }
+
+ // next look for a tag match
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ device_t *device = base.subdevice(strmakelower(relative));
+ if (device)
+ {
+ result = device;
+ return true;
+ }
+
+ // then evaluate as an expression; on an error assume it was a tag
+ u64 cpunum;
+ try
+ {
+ cpunum = parsed_expression(visible_symtable(), param).execute();
+ }
+ catch (expression_error &)
+ {
+ printf("Unable to find device '%s'\n", param);
+ return false;
+ }
+
+ // attempt to find by numerical index
+ device = get_cpu_by_index(cpunum);
+ if (device)
+ {
+ result = device;
+ return true;
+ }
+ else
+ {
+ // if out of range, complain
+ printf("Invalid CPU index %u\n", cpunum);
+ return false;
+ }
+}
+
+
+/// \brief Validate a parameter as a CPU
+///
+/// Validates a parameter as a CPU identifier. Uses the same rules as
+/// #validate_device_parameter to identify devices, but additionally
+/// checks that the device is a "CPU" for the debugger's purposes.
+/// \param [in] The parameter string.
+/// \param [out] result The device on success, or unchanged on failure.
+/// \return true if the parameter refers to a CPU-like device in the
+/// current system, or false otherwise.
+bool debugger_console::validate_cpu_parameter(std::string_view param, device_t *&result)
+{
+ // first do the standard device thing
+ device_t *device;
+ if (!validate_device_parameter(param, device))
+ return false;
+
+ // check that it's a "CPU" for the debugger's purposes
+ device_execute_interface const *execute;
+ if (device->interface(execute))
+ {
+ result = device;
+ return true;
+ }
+
+ printf("Device %s is not a CPU\n", device->name());
+ return false;
+}
+
+
+/// \brief Validate a parameter as an address space identifier
+///
+/// Validates a parameter as an address space identifier. Uses the same
+/// rules as #validate_device_parameter to identify devices. If the
+/// default address space number is negative, the first address space
+/// exposed by the device will be used as the default.
+/// \param [in] The parameter string.
+/// \param [in] spacenum The default address space index. If negative,
+/// the first address space exposed by the device (i.e. the address
+/// space with the lowest index) will be used as the default.
+/// \param [out] result The addresfs space on success, or unchanged on
+/// failure.
+/// \return true if the parameter refers to an address space in the
+/// current system, or false otherwise.
+bool debugger_console::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result)
+{
+ device_t *device;
+ std::string spacename;
+ if (param.empty())
+ {
+ // if no parameter, use the visible CPU
+ device = m_visiblecpu;
+ if (!device)
+ {
+ printf("No valid CPU is currently selected\n");
+ return false;
+ }
+ }
+ else
+ {
+ // look for a tag match on the whole parameter value
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ device = base.subdevice(strmakelower(relative));
+
+ // if that failed, treat the last component as an address space
+ if (!device)
+ {
+ auto const delimiter = relative.find_last_of(":^");
+ bool const found = std::string_view::npos != delimiter;
+ if (!found || (':' == relative[delimiter]))
+ {
+ spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0));
+ relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
+ if (!relative.empty())
+ device = base.subdevice(strmakelower(relative));
+ else if (m_visiblecpu)
+ device = m_visiblecpu;
+ else
+ device = &m_machine.root_device();
+ }
+ }
+ }
+
+ // if still no device found, evaluate as an expression
+ if (!device)
+ {
+ u64 cpunum;
+ try
+ {
+ cpunum = parsed_expression(visible_symtable(), param).execute();
+ }
+ catch (expression_error const &)
+ {
+ // parsing failed - assume it was a tag
+ printf("Unable to find device '%s'\n", param);
+ return false;
+ }
+
+ // attempt to find by numerical index
+ device = get_cpu_by_index(cpunum);
+ if (!device)
+ {
+ // if out of range, complain
+ printf("Invalid CPU index %u\n", cpunum);
+ return false;
+ }
+ }
+
+ // ensure the device implements the memory interface
+ device_memory_interface *memory;
+ if (!device->interface(memory))
+ {
+ printf("No memory interface found for device %s\n", device->name());
+ return false;
+ }
+
+ // fall back to supplied default space if appropriate
+ if (spacename.empty() && (0 <= spacenum))
+ {
+ if (memory->has_space(spacenum))
+ {
+ result = &memory->space(spacenum);
+ return true;
+ }
+ else
+ {
+ printf("No matching memory space found for device '%s'\n", device->tag());
+ return false;
+ }
+ }
+
+ // otherwise find the specified space or fall back to the first populated space
+ for (int i = 0; memory->max_space_count() > i; ++i)
+ {
+ if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename)))
+ {
+ result = &memory->space(i);
+ return true;
+ }
+ }
+
+ // report appropriate error message
+ if (spacename.empty())
+ printf("No memory spaces found for device '%s'\n", device->tag());
+ else
+ printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag());
+ return false;
+}
+
+
+/// \brief Validate a parameter as a target address
+///
+/// Validates a parameter as an numeric expression to use as an address
+/// optionally followed by a colon and a device identifier. If the
+/// device identifier is not presnt, the current CPU with debugger focus
+/// is assumed. See #validate_device_parameter for information on how
+/// device parametersare interpreted.
+/// \param [in] The parameter string.
+/// \param [in] spacenum The default address space index. If negative,
+/// the first address space exposed by the device (i.e. the address
+/// space with the lowest index) will be used as the default.
+/// \param [out] space The address space on success, or unchanged on
+/// failure.
+/// \param [out] addr The address on success, or unchanged on failure.
+/// \return true if the address is a valid expression evaluating to a
+/// number and the address space is found, or false otherwise.
+bool debugger_console::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr)
+{
+ // check for the device delimiter
+ std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; });
+ std::string_view device;
+ if (devdelim != std::string::npos)
+ device = param.substr(devdelim + 1);
+
+ // parse the address first
+ u64 addrval;
+ if (!validate_number_parameter(param.substr(0, devdelim), addrval))
+ return false;
+
+ // find the address space
+ if (!validate_device_space_parameter(device, spacenum, space))
+ return false;
+
+ // set the address now that we have the space
+ addr = addrval;
+ return true;
+}
+
+
+/// \brief Validate a parameter as a memory region
+///
+/// Validates a parameter as a memory region tag and retrieves the
+/// specified memory region.
+/// \param [in] The parameter string.
+/// \param [out] result The memory region on success, or unchanged on
+/// failure.
+/// \return true if the parameter refers to a memory region in the
+/// current system, or false otherwise.
+bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result)
+{
+ auto const &regions = m_machine.memory().regions();
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ auto const iter = regions.find(base.subtag(strmakelower(relative)));
+ if (regions.end() != iter)
+ {
+ result = iter->second.get();
+ return true;
+ }
+ else
+ {
+ printf("No matching memory region found for '%s'\n", param);
+ return false;
+ }
+}
+
+
+/// \brief Get search base for device or address space parameter
+///
+/// Handles prefix prefixes used to indicate that a device tag should be
+/// interpreted relative to the selected CPU. Removes the recognised
+/// prefixes from the parameter value.
+/// \param [in,out] param The parameter string. Recognised prefixes
+/// affecting the search base are removed, leaving a tag relative to
+/// the base device.
+/// \return A reference to the base device that the tag should be
+/// interpreted relative to.
+device_t &debugger_console::get_device_search_base(std::string_view &param) const
+{
+ if (!param.empty())
+ {
+ // handle ".:" or ".^" prefix for tag relative to current CPU if any
+ if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1])))
+ {
+ param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1);
+ device_t *const current = m_visiblecpu;
+ return current ? *current : m_machine.root_device();
+ }
+
+ // a sibling path makes most sense relative to current CPU
+ if ('^' == param[0])
+ {
+ device_t *const current = m_visiblecpu;
+ return current ? *current : m_machine.root_device();
+ }
+ }
+
+ // default to root device
+ return m_machine.root_device();
+}
+
+
+/// \brief Get CPU by index
+///
+/// Looks up a CPU by the number the debugger assigns it based on its
+/// position in the device tree relative to other CPUs.
+/// \param [in] cpunum Zero-based index of the CPU to find.
+/// \return A pointer to the CPU if found, or \c nullptr if no CPU has
+/// the specified index.
+device_t *debugger_console::get_cpu_by_index(u64 cpunum) const
+{
+ unsigned index = 0;
+ for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
+ {
+ // real CPUs should have pcbase
+ device_state_interface const *state;
+ if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE))
+ {
+ if (index++ == cpunum)
+ {
+ return &exec.device();
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+//-------------------------------------------------
+// validate_expression_parameter - validates
+// an expression parameter
+//-----------------------------------------------*/
+
+bool debugger_console::validate_expression_parameter(std::string_view param, parsed_expression &result)
+{
+ try
+ {
+ // parse the expression; success if no error
+ result.parse(param);
+ return true;
+ }
+ catch (expression_error const &err)
+ {
+ // output an error
+ printf("Error in expression: %s\n", param);
+ printf(" %*s^", err.offset(), "");
+ printf("%s\n", err.code_string());
+ return false;
+ }
+}
+
+
+//-------------------------------------------------
+// validate_command_parameter - validates a
+// command parameter
+//-------------------------------------------------
+
+bool debugger_console::validate_command_parameter(std::string_view param)
+{
+ // validate the comment; success if no error
+ CMDERR err = validate_command(param);
+ if (err.error_class() == CMDERR::NONE)
+ return true;
+
+ // output an error
+ printf("Error in command: %s\n", param);
+ printf(" %*s^", err.error_offset(), "");
+ printf("%s\n", cmderr_to_string(err));
+ return false;
+}
+
/***************************************************************************
@@ -614,7 +1086,7 @@ void debugger_console::print_core_wrap(std::string_view text, int wrapcol)
// the format to the debug console
//-------------------------------------------------
-void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &args)
+void debugger_console::vprintf(util::format_argument_pack<char> const &args)
{
print_core(util::string_format(args));
@@ -622,7 +1094,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &a
m_machine.debug_view().update_all(DVT_CONSOLE);
}
-void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args)
+void debugger_console::vprintf(util::format_argument_pack<char> &&args)
{
print_core(util::string_format(std::move(args)));
@@ -636,7 +1108,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args)
// using the format to the debug console
//-------------------------------------------------
-void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args)
+void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args)
{
print_core_wrap(util::string_format(args), wrapcol);
@@ -644,7 +1116,7 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std:
m_machine.debug_view().update_all(DVT_CONSOLE);
}
-void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args)
+void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args)
{
print_core_wrap(util::string_format(std::move(args)), wrapcol);
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 5271b0e5ae5..37b2e235348 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -23,18 +23,13 @@
CONSTANTS
***************************************************************************/
-#define MAX_COMMAND_LENGTH 4096
-#define MAX_COMMAND_PARAMS 128
+constexpr int MAX_COMMAND_PARAMS = 128;
// flags for command parsing
constexpr u32 CMDFLAG_NONE = 0x0000;
constexpr u32 CMDFLAG_KEEP_QUOTES = 0x0001;
constexpr u32 CMDFLAG_CUSTOM_HELP = 0x0002;
-// parameter separator macros
-#define CMDPARAM_SEPARATOR "\0"
-#define CMDPARAM_TERMINATOR "\0\0"
-
/***************************************************************************
@@ -79,19 +74,20 @@ class debugger_console
{
public:
debugger_console(running_machine &machine);
+ ~debugger_console();
// command handling
- CMDERR execute_command(const std::string &command, bool echo);
- CMDERR validate_command(const char *command);
- void register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler);
+ CMDERR execute_command(std::string_view command, bool echo);
+ CMDERR validate_command(std::string_view command);
+ void register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string_view> &)> &&handler);
void source_script(const char *file);
void process_source_file();
// console management
- void vprintf(util::format_argument_pack<std::ostream> const &args);
- void vprintf(util::format_argument_pack<std::ostream> &&args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args);
+ void vprintf(util::format_argument_pack<char> const &args);
+ void vprintf(util::format_argument_pack<char> &&args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args);
text_buffer &get_console_textbuf() const { return *m_console_textbuf; }
// errorlog management
@@ -110,28 +106,58 @@ public:
vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
- device_t *get_visible_cpu() { return m_visiblecpu; }
+ device_t *get_visible_cpu() const { return m_visiblecpu; }
void set_visible_cpu(device_t *visiblecpu) { m_visiblecpu = visiblecpu; }
- symbol_table &visible_symtable();
+ symbol_table &visible_symtable() const;
static std::string cmderr_to_string(CMDERR error);
+ // validates a parameter as a boolean value
+ bool validate_boolean_parameter(std::string_view param, bool &result);
+
+ // validates a parameter as a numeric value
+ bool validate_number_parameter(std::string_view param, u64 &result);
+
+ // validates a parameter as a device
+ bool validate_device_parameter(std::string_view param, device_t *&result);
+
+ // validates a parameter as a CPU
+ bool validate_cpu_parameter(std::string_view param, device_t *&result);
+
+ // validates a parameter as an address space identifier
+ bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result);
+
+ // validates a parameter as a target address and retrieves the given address space and address
+ bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr);
+
+ // validates a parameter as a memory region name and retrieves the given region
+ bool validate_memory_region_parameter(std::string_view param, memory_region *&result);
+
+ // validates a parameter as a debugger expression
+ bool validate_expression_parameter(std::string_view param, parsed_expression &result);
+
+ // validates a parameter as a debugger command
+ bool validate_command_parameter(std::string_view param);
+
private:
void exit();
- void execute_help_custom(const std::vector<std::string> &params);
- void execute_condump(const std::vector<std::string>& params);
+ void execute_help_custom(const std::vector<std::string_view> &params);
+ void execute_condump(const std::vector<std::string_view>& params);
- void trim_parameter(char **paramptr, bool keep_quotes);
- CMDERR internal_execute_command(bool execute, int params, char **param);
- CMDERR internal_parse_command(const std::string &original_command, bool execute);
+ [[nodiscard]] static std::string_view trim_parameter(std::string_view param, bool keep_quotes);
+ CMDERR internal_execute_command(bool execute, std::vector<std::string_view> &params);
+ CMDERR internal_parse_command(std::string_view command, bool execute);
void print_core(std::string_view text); // core text output
void print_core_wrap(std::string_view text, int wrapcol); // core text output
+ device_t &get_device_search_base(std::string_view &param) const;
+ device_t *get_cpu_by_index(u64 cpunum) const;
+
struct debug_command
{
- debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler);
+ debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string_view> &)> &&_handler);
struct compare
{
@@ -144,7 +170,7 @@ private:
std::string command;
const char * params;
const char * help;
- std::function<void (const std::vector<std::string> &)> handler;
+ std::function<void (const std::vector<std::string_view> &)> handler;
u32 flags;
int minparams;
int maxparams;
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 403d0b104ee..fd0093bd283 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -19,11 +19,12 @@
#include "debugger.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "screen.h"
#include "uiinput.h"
#include "corestr.h"
-#include "coreutil.h"
#include "osdepend.h"
#include "xmlfile.h"
@@ -46,6 +47,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
, m_bpindex(1)
, m_wpindex(1)
, m_rpindex(1)
+ , m_epindex(1)
, m_wpdata(0)
, m_wpaddr(0)
, m_wpsize(0)
@@ -91,7 +93,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
for (int regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++)
{
char symname[10];
- sprintf(symname, "temp%d", regnum);
+ snprintf(symname, 10, "temp%d", regnum);
m_symtable->add(symname, symbol_table::READ_WRITE, &m_tempvar[regnum]);
}
}
@@ -385,7 +387,7 @@ void debugger_cpu::go_vblank()
m_execution_state = exec_state::RUNNING;
}
-void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args)
+void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args)
{
// if something is pending on this CPU already, ignore this request
if (device == m_breakcpu)
@@ -423,9 +425,9 @@ device_debug::device_debug(device_t &device)
, m_disasm(nullptr)
, m_flags(0)
, m_symtable(std::make_unique<symbol_table>(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device))
- , m_instrhook(nullptr)
, m_stepaddr(0)
, m_stepsleft(0)
+ , m_delay_steps(0)
, m_stopaddr(0)
, m_stoptime(attotime::zero)
, m_stopirq(0)
@@ -436,7 +438,8 @@ device_debug::device_debug(device_t &device)
, m_pc_history_index(0)
, m_pc_history_valid(0)
, m_bplist()
- , m_rplist(std::make_unique<std::forward_list<debug_registerpoint>>())
+ , m_rplist()
+ , m_eplist()
, m_triggered_breakpoint(nullptr)
, m_triggered_watchpoint(nullptr)
, m_trace(nullptr)
@@ -458,14 +461,14 @@ device_debug::device_debug(device_t &device)
// set up notifiers and clear the passthrough handlers
if (m_memory) {
int count = m_memory->max_space_count();
- m_phw.resize(count, nullptr);
+ m_phw.resize(count);
for (int i=0; i != count; i++)
if (m_memory->has_space(i)) {
address_space &space = m_memory->space(i);
- m_notifiers.push_back(space.add_change_notifier([this, &space](read_or_write mode) { reinstall(space, mode); }));
+ m_notifiers.emplace_back(space.add_change_notifier([this, &space] (read_or_write mode) { reinstall(space, mode); }));
}
else
- m_notifiers.push_back(-1);
+ m_notifiers.emplace_back();
}
// set up state-related stuff
@@ -547,6 +550,7 @@ device_debug::~device_debug()
breakpoint_clear_all();
watchpoint_clear_all();
registerpoint_clear_all();
+ exceptionpoint_clear_all();
}
void device_debug::write_tracking(address_space &space, offs_t address, u64 data)
@@ -562,15 +566,14 @@ void device_debug::reinstall(address_space &space, read_or_write mode)
int id = space.spacenum();
if (u32(mode) & u32(read_or_write::WRITE))
{
- if (m_phw[id])
- m_phw[id]->remove();
+ m_phw[id].remove();
if (m_track_mem)
switch (space.data_width())
{
- case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, m_phw[id]); break;
+ case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, &m_phw[id]); break;
}
}
}
@@ -633,15 +636,46 @@ void device_debug::stop_hook()
// acknowledged
//-------------------------------------------------
-void device_debug::interrupt_hook(int irqline)
+void device_debug::interrupt_hook(int irqline, offs_t pc)
{
// see if this matches a pending interrupt request
if ((m_flags & DEBUG_FLAG_STOP_INTERRUPT) != 0 && (m_stopirq == -1 || m_stopirq == irqline))
{
m_device.machine().debugger().cpu().set_execution_stopped();
- m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d)\n", m_device.tag(), irqline);
+ const address_space &space = m_memory->space(AS_PROGRAM);
+ if (space.is_octal())
+ m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*o)\n", m_device.tag(), irqline, (space.logaddr_width() + 2) / 3, pc);
+ else
+ m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*X)\n", m_device.tag(), irqline, space.logaddrchars(), pc);
compute_debug_flags();
}
+
+ if (m_trace != nullptr)
+ m_trace->interrupt_update(irqline, pc);
+
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0)
+ {
+ if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) == 0)
+ {
+ if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0)
+ {
+ if ((m_stepaddr == pc && (m_flags & DEBUG_FLAG_STEPPING_BRANCH_FALSE) != 0) ||
+ (m_stepaddr != pc && m_delay_steps == 1 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0))
+ {
+ // step over the interrupt and then call it finished
+ m_flags = (m_flags & ~(DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_ANY)) | DEBUG_FLAG_STEPPING_OVER;
+ m_stepsleft = 1;
+ }
+ }
+
+ // remember the interrupt return address
+ m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS;
+ m_stepaddr = pc;
+ }
+
+ m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS;
+ m_delay_steps = 0;
+ }
}
@@ -671,10 +705,39 @@ void device_debug::exception_hook(int exception)
if (matched)
{
m_device.machine().debugger().cpu().set_execution_stopped();
- m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %d, PC=%X)\n", m_device.tag(), exception, m_state->pcbase());
+ m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %X, PC=%s)\n", m_device.tag(), exception, m_state->state_string(STATE_GENPC));
compute_debug_flags();
}
}
+
+ // see if any exception points match
+ if (!m_eplist.empty())
+ {
+ auto epitp = m_eplist.equal_range(exception);
+ for (auto epit = epitp.first; epit != epitp.second; ++epit)
+ {
+ debug_exceptionpoint &ep = *epit->second;
+ if (ep.hit(exception))
+ {
+ // halt in the debugger by default
+ debugger_cpu &debugcpu = m_device.machine().debugger().cpu();
+ debugcpu.set_execution_stopped();
+
+ // if we hit, evaluate the action
+ if (!ep.m_action.empty())
+ m_device.machine().debugger().console().execute_command(ep.m_action, false);
+
+ // print a notification, unless the action made us go again
+ if (debugcpu.is_stopped())
+ {
+ debugcpu.set_execution_stopped();
+ m_device.machine().debugger().console().printf("Stopped at exception point %X (CPU '%s', PC=%s)\n", ep.m_index, m_device.tag(), m_state->state_string(STATE_GENPC));
+ compute_debug_flags();
+ }
+ break;
+ }
+ }
+ }
}
@@ -688,11 +751,11 @@ void device_debug::privilege_hook()
if ((m_flags & DEBUG_FLAG_STOP_PRIVILEGE) != 0)
{
bool matched = true;
- if (m_privilege_condition && !m_privilege_condition->is_empty())
+ if (m_stop_condition && !m_stop_condition->is_empty())
{
try
{
- matched = m_privilege_condition->execute();
+ matched = m_stop_condition->execute();
}
catch (expression_error &)
{
@@ -743,26 +806,56 @@ void device_debug::instruction_hook(offs_t curpc)
if (m_trace != nullptr)
m_trace->update(curpc);
- // per-instruction hook?
- if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_HOOKED) != 0 && (*m_instrhook)(m_device, curpc))
- debugcpu.set_execution_stopped();
-
// handle single stepping
if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_STEPPING_ANY) != 0)
{
+ bool do_step = true;
+ if ((m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) != 0)
+ {
+ if (curpc == m_stepaddr)
+ {
+ if ((~m_flags & (DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0)
+ {
+ debugcpu.set_execution_stopped();
+ do_step = false;
+ }
+
+ // reset the breakpoint
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
+ m_delay_steps = 0;
+ }
+ else if (m_delay_steps != 0)
+ {
+ m_delay_steps--;
+ if (m_delay_steps == 0)
+ {
+ // branch taken or subroutine entered (TODO: interleaved multithreading can falsely trigger this)
+ if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0)
+ {
+ debugcpu.set_execution_stopped();
+ do_step = false;
+ }
+ if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) != 0)
+ do_step = false;
+ m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS;
+ }
+ }
+ else
+ do_step = false;
+ }
+
// is this an actual step?
- if (m_stepaddr == ~0 || curpc == m_stepaddr)
+ if (do_step)
{
- // decrement the count and reset the breakpoint
+ // decrement the count
m_stepsleft--;
- m_stepaddr = ~0;
// if we hit 0, stop
if (m_stepsleft == 0)
debugcpu.set_execution_stopped();
// update every 100 steps until we are within 200 of the end
- else if ((m_flags & DEBUG_FLAG_STEPPING_OUT) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0))
+ else if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0))
{
machine.debug_view().update_all();
machine.debug_view().flush_osd_updates();
@@ -784,7 +877,10 @@ void device_debug::instruction_hook(offs_t curpc)
// check the temp running breakpoint and break if we hit it
else if ((m_flags & DEBUG_FLAG_STOP_PC) != 0 && m_stopaddr == curpc)
{
- machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag());
+ if (is_octal())
+ machine.debugger().console().printf("Stopped at temporary breakpoint %o on CPU '%s'\n", m_stopaddr, m_device.tag());
+ else
+ machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag());
debugcpu.set_execution_stopped();
}
@@ -849,7 +945,7 @@ void device_debug::instruction_hook(offs_t curpc)
}
// handle step out/over on the instruction we are about to execute
- if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT)) != 0 && m_stepaddr == ~0)
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0 && (m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) == 0)
prepare_for_step_overout(m_state->pcbase());
// no longer in debugger code
@@ -858,22 +954,6 @@ void device_debug::instruction_hook(offs_t curpc)
//-------------------------------------------------
-// set_instruction_hook - set a hook to be
-// called on each instruction for a given device
-//-------------------------------------------------
-
-void device_debug::set_instruction_hook(debug_instruction_hook_func hook)
-{
- // set the hook and also the CPU's flag for fast knowledge of the hook
- m_instrhook = hook;
- if (hook != nullptr)
- m_flags |= DEBUG_FLAG_HOOKED;
- else
- m_flags &= ~DEBUG_FLAG_HOOKED;
-}
-
-
-//-------------------------------------------------
// ignore - ignore/observe a given device
//-------------------------------------------------
@@ -928,8 +1008,9 @@ void device_debug::single_step(int numsteps)
m_device.machine().rewind_capture();
m_stepsleft = numsteps;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING;
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -945,8 +1026,9 @@ void device_debug::single_step_over(int numsteps)
m_device.machine().rewind_capture();
m_stepsleft = numsteps;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING_OVER;
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -961,9 +1043,11 @@ void device_debug::single_step_out()
assert(m_exec != nullptr);
m_device.machine().rewind_capture();
+ m_stop_condition.reset();
m_stepsleft = 100;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING_OUT;
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -1060,20 +1144,38 @@ void device_debug::go_privilege(const char *condition)
{
assert(m_exec != nullptr);
m_device.machine().rewind_invalidate();
- m_privilege_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
+ m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
m_flags |= DEBUG_FLAG_STOP_PRIVILEGE;
m_device.machine().debugger().cpu().set_execution_running();
}
//-------------------------------------------------
+// go_branch - execute until branch taken or
+// not taken
+//-------------------------------------------------
+
+void device_debug::go_branch(bool sense, const char *condition)
+{
+ assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
+ m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
+ m_stepsleft = 100;
+ m_delay_steps = 0;
+ m_flags |= sense ? DEBUG_FLAG_STEPPING_BRANCH_TRUE : DEBUG_FLAG_STEPPING_BRANCH_FALSE;
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
+ m_device.machine().debugger().cpu().set_execution_running();
+}
+
+
+//-------------------------------------------------
// halt_on_next_instruction_impl - halt in the
// debugger on the next instruction, internal
// implementation which is necessary solely due
// to templates in C++ being janky as all get out
//-------------------------------------------------
-void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args)
+void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<char> &&args)
{
assert(m_exec != nullptr);
m_device.machine().debugger().cpu().halt_on_next_instruction(&m_device, std::move(args));
@@ -1098,7 +1200,7 @@ const debug_breakpoint *device_debug::breakpoint_find(offs_t address) const
// returning its index
//-------------------------------------------------
-int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action)
+int device_debug::breakpoint_set(offs_t address, const char *condition, std::string_view action)
{
// allocate a new one and hook it into our list
u32 id = m_device.machine().debugger().cpu().get_breakpoint_index();
@@ -1185,7 +1287,7 @@ void device_debug::breakpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action)
+int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, std::string_view action)
{
if (space.spacenum() >= int(m_wplist.size()))
m_wplist.resize(space.spacenum()+1);
@@ -1272,15 +1374,15 @@ void device_debug::watchpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::registerpoint_set(const char *condition, const char *action)
+int device_debug::registerpoint_set(const char *condition, std::string_view action)
{
// allocate a new one
u32 id = m_device.machine().debugger().cpu().get_registerpoint_index();
- m_rplist->emplace_front(*m_symtable, id, condition, action);
+ m_rplist.emplace_front(*m_symtable, id, condition, action);
// update the flags and return the index
breakpoint_update_flags();
- return m_rplist->front().m_index;
+ return m_rplist.front().m_index;
}
@@ -1292,10 +1394,10 @@ int device_debug::registerpoint_set(const char *condition, const char *action)
bool device_debug::registerpoint_clear(int index)
{
// scan the list to see if we own this registerpoint
- for (auto brp = m_rplist->before_begin(); std::next(brp) != m_rplist->end(); ++brp)
+ for (auto brp = m_rplist.before_begin(); std::next(brp) != m_rplist.end(); ++brp)
if (std::next(brp)->m_index == index)
{
- m_rplist->erase_after(brp);
+ m_rplist.erase_after(brp);
breakpoint_update_flags();
return true;
}
@@ -1312,7 +1414,7 @@ bool device_debug::registerpoint_clear(int index)
void device_debug::registerpoint_clear_all()
{
// clear the list
- m_rplist->clear();
+ m_rplist.clear();
breakpoint_update_flags();
}
@@ -1325,7 +1427,7 @@ void device_debug::registerpoint_clear_all()
bool device_debug::registerpoint_enable(int index, bool enable)
{
// scan the list to see if we own this conditionpoint
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
if (rp.m_index == index)
{
rp.m_enabled = enable;
@@ -1346,12 +1448,97 @@ bool device_debug::registerpoint_enable(int index, bool enable)
void device_debug::registerpoint_enable_all(bool enable)
{
// apply the enable to all registerpoints we own
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
registerpoint_enable(rp.index(), enable);
}
//-------------------------------------------------
+// exceptionpoint_set - set a new exception
+// point, returning its index
+//-------------------------------------------------
+
+int device_debug::exceptionpoint_set(int exception, const char *condition, std::string_view action)
+{
+ // allocate a new one and hook it into our list
+ u32 id = m_device.machine().debugger().cpu().get_exceptionpoint_index();
+ m_eplist.emplace(exception, std::make_unique<debug_exceptionpoint>(this, *m_symtable, id, exception, condition, action));
+
+ // return the index
+ return id;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear - clear an exception
+// point by index, returning true if we found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_clear(int index)
+{
+ // scan the list to see if we own this breakpoint
+ for (auto epit = m_eplist.begin(); epit != m_eplist.end(); ++epit)
+ if (epit->second->m_index == index)
+ {
+ m_eplist.erase(epit);
+ return true;
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear_all - clear all exception
+// points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_clear_all()
+{
+ // clear the list
+ m_eplist.clear();
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable - enable/disable an
+// exception point by index, returning true if we
+// found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_enable(int index, bool enable)
+{
+ // scan the list to see if we own this exception point
+ for (auto &epp : m_eplist)
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ if (ep.m_index == index)
+ {
+ ep.m_enabled = enable;
+ return true;
+ }
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable_all - enable/disable all
+// exception points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_enable_all(bool enable)
+{
+ // apply the enable to all exception points we own
+ for (auto &epp : m_eplist)
+ exceptionpoint_enable(epp.second->index(), enable);
+}
+
+
+//-------------------------------------------------
// history_pc - return an entry from the PC
// history
//-------------------------------------------------
@@ -1385,7 +1572,6 @@ void device_debug::set_track_pc(bool value)
// track_pc_visited - returns a boolean stating
// if this PC has been visited or not. CRC32 is
// done in this function on currently active CPU.
-// TODO: Take a CPU context as input
//-------------------------------------------------
bool device_debug::track_pc_visited(offs_t pc) const
@@ -1399,7 +1585,6 @@ bool device_debug::track_pc_visited(offs_t pc) const
//-------------------------------------------------
// set_track_pc_visited - set this pc as visited.
-// TODO: Take a CPU context as input
//-------------------------------------------------
void device_debug::set_track_pc_visited(offs_t pc)
@@ -1541,7 +1726,7 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const
buffer.data_get(pc, dasmresult & util::disasm_interface::LENGTHMASK, true, opbuf);
// return a CRC of the exact count of opcode bytes
- return core_crc32(0, &opbuf[0], opbuf.size());
+ return util::crc32_creator::simple(&opbuf[0], opbuf.size());
}
@@ -1549,31 +1734,14 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const
// trace - trace execution of a given device
//-------------------------------------------------
-void device_debug::trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+void device_debug::trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
{
// delete any existing tracers
m_trace = nullptr;
// if we have a new file, make a new tracer
if (file != nullptr)
- m_trace = std::make_unique<tracer>(*this, *file, trace_over, detect_loops, logerror, action);
-}
-
-
-//-------------------------------------------------
-// trace_printf - output data into the given
-// device's tracefile, if tracing
-//-------------------------------------------------
-
-void device_debug::trace_printf(const char *fmt, ...)
-{
- if (m_trace != nullptr)
- {
- va_list va;
- va_start(va, fmt);
- m_trace->vprintf(fmt, va);
- va_end(va);
- }
+ m_trace = std::make_unique<tracer>(*this, std::move(file), trace_over, detect_loops, logerror, action);
}
@@ -1601,7 +1769,7 @@ void device_debug::compute_debug_flags()
// if we're tracking history, or we're hooked, or stepping, or stopping at a breakpoint
// make sure we call the hook
- if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_HOOKED | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
+ if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
// also call if we are tracing
@@ -1625,12 +1793,32 @@ void device_debug::prepare_for_step_overout(offs_t pc)
// disassemble the current instruction and get the flags
u32 dasmresult = buffer.disassemble_info(pc);
+ if ((dasmresult & util::disasm_interface::SUPPORTED) == 0)
+ return;
+
+ bool step_out = (m_flags & DEBUG_FLAG_STEPPING_OUT) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) != 0;
+ bool test_cond = (dasmresult & util::disasm_interface::STEP_COND) != 0 && ((m_flags & (DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0 || step_out);
+ if (test_cond && m_stop_condition && !m_stop_condition->is_empty())
+ {
+ try
+ {
+ test_cond = m_stop_condition->execute();
+ }
+ catch (expression_error &)
+ {
+ test_cond = false;
+ }
+ }
// if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction
- if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
+ // (TODO: this completely fails for subroutines that consume inline operands or use alternate returns)
+ if ((dasmresult & util::disasm_interface::STEP_OVER) != 0 || test_cond)
{
int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT;
pc = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK);
+ m_delay_steps = extraskip + 1;
+ if (m_stepsleft < m_delay_steps)
+ m_stepsleft = m_delay_steps;
// if we need to skip additional instructions, advance as requested
while (extraskip-- > 0) {
@@ -1638,13 +1826,17 @@ void device_debug::prepare_for_step_overout(offs_t pc)
pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK);
}
m_stepaddr = pc;
+ if ((dasmresult & util::disasm_interface::STEP_OVER) != 0)
+ m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS;
+ if (test_cond)
+ m_flags |= DEBUG_FLAG_TEST_IN_PROGRESS;
}
// if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number
- // (TODO: this doesn't work with conditional return instructions)
- if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0)
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0)
{
- if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) == 0)
+ // make sure to also reset the number of steps for conditionals that may be single-instruction loops
+ if (test_cond || !step_out)
m_stepsleft = 100;
else
{
@@ -1678,7 +1870,7 @@ void device_debug::breakpoint_update_flags()
if (!(m_flags & DEBUG_FLAG_LIVE_BP))
{
// see if there are any enabled registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.m_enabled)
{
@@ -1728,7 +1920,7 @@ void device_debug::breakpoint_check(offs_t pc)
}
// see if we have any matching registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.hit())
{
@@ -1761,10 +1953,10 @@ void device_debug::breakpoint_check(offs_t pc)
// tracer - constructor
//-------------------------------------------------
-device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+device_debug::tracer::tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
: m_debug(debug)
- , m_file(file)
- , m_action((action != nullptr) ? action : "")
+ , m_file(std::move(file))
+ , m_action(action)
, m_detect_loops(detect_loops)
, m_logerror(logerror)
, m_loops(0)
@@ -1783,7 +1975,7 @@ device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, b
device_debug::tracer::~tracer()
{
// make sure we close the file if we can
- fclose(&m_file);
+ m_file.reset();
}
@@ -1819,7 +2011,7 @@ void device_debug::tracer::update(offs_t pc)
// if we just finished looping, indicate as much
if (m_loops != 0)
- fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops);
+ util::stream_format(*m_file, "\n (loops for %d instructions)\n\n", m_loops);
m_loops = 0;
}
@@ -1834,7 +2026,7 @@ void device_debug::tracer::update(offs_t pc)
buffer.disassemble(pc, instruction, next_pc, size, dasmresult);
// output the result
- fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str());
+ util::stream_format(*m_file, "%s: %s\n", buffer.pc_to_string(pc), instruction);
// do we need to step the trace over this instruction?
if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
@@ -1852,7 +2044,33 @@ void device_debug::tracer::update(offs_t pc)
// log this PC
m_nextdex = (m_nextdex + 1) % TRACE_LOOPS;
m_history[m_nextdex] = pc;
- fflush(&m_file);
+ m_file->flush();
+}
+
+
+//-------------------------------------------------
+// interrupt_update - log interrupt to tracefile
+//-------------------------------------------------
+
+void device_debug::tracer::interrupt_update(int irqline, offs_t pc)
+{
+ if (m_trace_over)
+ {
+ if (m_trace_over_target != ~0)
+ return;
+ m_trace_over_target = pc;
+ }
+
+ // if we just finished looping, indicate as much
+ *m_file << "\n";
+ if (m_detect_loops && m_loops != 0)
+ {
+ util::stream_format(*m_file, " (loops for %d instructions)\n", m_loops);
+ m_loops = 0;
+ }
+
+ util::stream_format(*m_file, " (interrupted at %s, IRQ %d)\n\n", debug_disasm_buffer(m_debug.device()).pc_to_string(pc), irqline);
+ m_file->flush();
}
@@ -1860,11 +2078,11 @@ void device_debug::tracer::update(offs_t pc)
// vprintf - generic print to the trace file
//-------------------------------------------------
-void device_debug::tracer::vprintf(const char *format, va_list va)
+void device_debug::tracer::vprintf(util::format_argument_pack<char> const &args)
{
// pass through to the file
- vfprintf(&m_file, format, va);
- fflush(&m_file);
+ util::stream_format(*m_file, args);
+ m_file->flush();
}
@@ -1875,7 +2093,7 @@ void device_debug::tracer::vprintf(const char *format, va_list va)
void device_debug::tracer::flush()
{
- fflush(&m_file);
+ m_file->flush();
}
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 9e3d23d8d7f..9a9f6e69f70 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -29,9 +29,6 @@ constexpr int COMMENT_VERSION = 1;
// TYPE DEFINITIONS
//**************************************************************************
-typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc);
-
-
// ======================> device_debug
// [TODO] This whole thing is terrible.
@@ -54,14 +51,11 @@ public:
// hooks used by the rest of the system
void start_hook(const attotime &endtime);
void stop_hook();
- void interrupt_hook(int irqline);
+ void interrupt_hook(int irqline, offs_t pc);
void exception_hook(int exception);
void privilege_hook();
void instruction_hook(offs_t curpc);
- // hooks into our operations
- void set_instruction_hook(debug_instruction_hook_func hook);
-
// debugger focus
void ignore(bool ignore = true);
bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); }
@@ -82,6 +76,7 @@ public:
void go_exception(int exception, const char *condition);
void go_milliseconds(u64 milliseconds);
void go_privilege(const char *condition);
+ void go_branch(bool sense, const char *condition);
void go_next_device();
template <typename Format, typename... Params>
@@ -93,7 +88,7 @@ public:
// breakpoints
const auto &breakpoint_list() const { return m_bplist; }
const debug_breakpoint *breakpoint_find(offs_t address) const;
- int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr);
+ int breakpoint_set(offs_t address, const char *condition = nullptr, std::string_view action = {});
bool breakpoint_clear(int index);
void breakpoint_clear_all();
bool breakpoint_enable(int index, bool enable = true);
@@ -103,7 +98,7 @@ public:
// watchpoints
int watchpoint_space_count() const { return m_wplist.size(); }
const std::vector<std::unique_ptr<debug_watchpoint>> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; }
- int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action);
+ int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition = nullptr, std::string_view action = {});
bool watchpoint_clear(int wpnum);
void watchpoint_clear_all();
bool watchpoint_enable(int index, bool enable = true);
@@ -112,12 +107,20 @@ public:
debug_watchpoint *triggered_watchpoint() { debug_watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; }
// registerpoints
- const std::forward_list<debug_registerpoint> &registerpoint_list() const { return *m_rplist; }
- int registerpoint_set(const char *condition, const char *action = nullptr);
+ const std::forward_list<debug_registerpoint> &registerpoint_list() const { return m_rplist; }
+ int registerpoint_set(const char *condition, std::string_view action = {});
bool registerpoint_clear(int index);
void registerpoint_clear_all();
bool registerpoint_enable(int index, bool enable = true);
- void registerpoint_enable_all(bool enable = true );
+ void registerpoint_enable_all(bool enable = true);
+
+ // exception points
+ const auto &exceptionpoint_list() const { return m_eplist; }
+ int exceptionpoint_set(int exception, const char *condition = nullptr, std::string_view action = {});
+ bool exceptionpoint_clear(int index);
+ void exceptionpoint_clear_all();
+ bool exceptionpoint_enable(int index, bool enable = true);
+ void exceptionpoint_enable_all(bool enable = true);
// comments
void comment_add(offs_t address, const char *comment, rgb_t color);
@@ -146,8 +149,12 @@ public:
void track_mem_data_clear() { m_track_mem_set.clear(); }
// tracing
- void trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action);
- void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3);
+ void trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
+ template <typename Format, typename... Params> void trace_printf(Format &&fmt, Params &&...args)
+ {
+ if (m_trace != nullptr)
+ m_trace->vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
void trace_flush() { if (m_trace != nullptr) m_trace->flush(); }
void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; }
@@ -158,7 +165,7 @@ public:
void compute_debug_flags();
private:
- void halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args);
+ void halt_on_next_instruction_impl(util::format_argument_pack<char> &&args);
// internal helpers
void prepare_for_step_overout(offs_t pc);
@@ -181,18 +188,18 @@ private:
// global state
u32 m_flags; // debugging flags for this CPU
std::unique_ptr<symbol_table> m_symtable; // symbol table for expression evaluation
- debug_instruction_hook_func m_instrhook; // per-instruction callback hook
// stepping information
- offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER
+ offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER or DEBUG_FLAG_STEPPING_BRANCH
int m_stepsleft; // number of steps left until done
+ int m_delay_steps; // number of steps until target address check
// execution information
offs_t m_stopaddr; // stop address for DEBUG_FLAG_STOP_PC
attotime m_stoptime; // stop time for DEBUG_FLAG_STOP_TIME
int m_stopirq; // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT
int m_stopexception; // stop exception number for DEBUG_FLAG_STOP_EXCEPTION
- std::unique_ptr<parsed_expression> m_privilege_condition; // expression to evaluate on privilege change
+ std::unique_ptr<parsed_expression> m_stop_condition; // expression to evaluate on privilege change
std::unique_ptr<parsed_expression> m_exception_condition; // expression to evaluate on exception hit
attotime m_endexectime; // ending time of the current execution
u64 m_total_cycles; // current total cycles
@@ -206,7 +213,8 @@ private:
// breakpoints and watchpoints
std::multimap<offs_t, std::unique_ptr<debug_breakpoint>> m_bplist; // list of breakpoints
std::vector<std::vector<std::unique_ptr<debug_watchpoint>>> m_wplist; // watchpoint lists for each address space
- std::unique_ptr<std::forward_list<debug_registerpoint>> m_rplist; // list of registerpoints
+ std::forward_list<debug_registerpoint> m_rplist; // list of registerpoints
+ std::multimap<offs_t, std::unique_ptr<debug_exceptionpoint>> m_eplist; // list of exception points
debug_breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered
debug_watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered
@@ -215,11 +223,12 @@ private:
class tracer
{
public:
- tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action);
+ tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
~tracer();
void update(offs_t pc);
- void vprintf(const char *format, va_list va);
+ void interrupt_update(int irqline, offs_t pc);
+ void vprintf(util::format_argument_pack<char> const &args);
void flush();
bool logerror() const { return m_logerror; }
@@ -227,7 +236,7 @@ private:
static const int TRACE_LOOPS = 64;
device_debug & m_debug; // reference to our owner
- FILE & m_file; // tracing file for this CPU
+ std::unique_ptr<std::ostream> m_file; // tracing file for this CPU
std::string m_action; // action to perform during a trace
offs_t m_history[TRACE_LOOPS]; // history of recent PCs
bool m_detect_loops; // whether or not we should detect loops
@@ -239,10 +248,10 @@ private:
// (0 = not tracing over,
// ~0 = not currently tracing over)
};
- std::unique_ptr<tracer> m_trace; // tracer state
+ std::unique_ptr<tracer> m_trace; // tracer state
- std::vector<memory_passthrough_handler *> m_phw; // passthrough handler reference for each space, write mode
- std::vector<int> m_notifiers; // notifiers for each space
+ std::vector<memory_passthrough_handler> m_phw; // passthrough handler reference for each space, write mode
+ std::vector<util::notifier_subscription> m_notifiers; // notifiers for each space
// pc tracking
class dasm_pc_tag
@@ -310,7 +319,6 @@ private:
static constexpr u32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history
static constexpr u32 DEBUG_FLAG_TRACING = 0x00000004; // tracing this CPU
static constexpr u32 DEBUG_FLAG_TRACING_OVER = 0x00000008; // tracing this CPU with step over behavior
- static constexpr u32 DEBUG_FLAG_HOOKED = 0x00000010; // per-instruction callback hook
static constexpr u32 DEBUG_FLAG_STEPPING = 0x00000020; // CPU is single stepping
static constexpr u32 DEBUG_FLAG_STEPPING_OVER = 0x00000040; // CPU is stepping over a function
static constexpr u32 DEBUG_FLAG_STEPPING_OUT = 0x00000080; // CPU is stepping out of a function
@@ -322,12 +330,17 @@ private:
static constexpr u32 DEBUG_FLAG_SUSPENDED = 0x00004000; // CPU currently suspended
static constexpr u32 DEBUG_FLAG_LIVE_BP = 0x00010000; // there are live breakpoints for this CPU
static constexpr u32 DEBUG_FLAG_STOP_PRIVILEGE = 0x00020000; // run until execution level changes
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_TRUE = 0x0040000; // run until true branch
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_FALSE = 0x0080000; // run until false branch
+ static constexpr u32 DEBUG_FLAG_CALL_IN_PROGRESS = 0x01000000; // CPU is in the middle of a subroutine call
+ static constexpr u32 DEBUG_FLAG_TEST_IN_PROGRESS = 0x02000000; // CPU is performing a conditional test and branch
- static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT;
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH = DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE;
+ static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH;
static constexpr u32 DEBUG_FLAG_TRACING_ANY = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER;
static constexpr u32 DEBUG_FLAG_TRANSIENT = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC |
DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK |
- DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE;
+ DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE | DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS;
};
//**************************************************************************
@@ -377,6 +390,7 @@ public:
u32 get_breakpoint_index() { return m_bpindex++; }
u32 get_watchpoint_index() { return m_wpindex++; }
u32 get_registerpoint_index() { return m_rpindex++; }
+ u32 get_exceptionpoint_index() { return m_epindex++; }
// setters
void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; }
@@ -392,7 +406,7 @@ public:
void stop_hook(device_t *device);
void go_next_device(device_t *device);
void go_vblank();
- void halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args);
+ void halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args);
void ensure_comments_loaded();
void reset_transient_flags();
@@ -419,6 +433,7 @@ private:
u32 m_bpindex;
u32 m_wpindex;
u32 m_rpindex;
+ u32 m_epindex;
u64 m_wpdata;
u64 m_wpaddr;
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index 87bf8f0f18f..76102402bcb 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -46,6 +46,7 @@ const help_item f_static_help_list[] =
" Breakpoints\n"
" Watchpoints\n"
" Registerpoints\n"
+ " Exception Points\n"
" Expressions\n"
" Comments\n"
" Cheats\n"
@@ -81,6 +82,7 @@ const help_item f_static_help_list[] =
" stateload[sl] <filename> -- load a state file for the current driver\n"
" snap [<filename>] -- save a screen snapshot.\n"
" source <filename> -- reads commands from <filename> and executes them one by one\n"
+ " time -- prints current machine time to the console\n"
" cls -- clears the console text buffer\n"
" quit -- exits MAME and the debugger\n"
},
@@ -132,8 +134,12 @@ const help_item f_static_help_list[] =
" o[ver] [<count>=1] -- single steps over <count> instructions (F10)\n"
" out -- single steps until the current subroutine/exception handler is exited (Shift-F11)\n"
" g[o] [<address>] -- resumes execution, sets temp breakpoint at <address> (F5)\n"
+ " gbf [<condition>] -- resumes execution until next false branch\n"
+ " gbt [<condition>] -- resumes execution until next true branch\n"
+ " gn[i] [<count>] -- resumes execution, sets temp breakpoint <count> instructions ahead\n"
" ge[x] [<exception>[,<condition>]] -- resumes execution, setting temp breakpoint if <exception> is raised\n"
" gi[nt] [<irqline>] -- resumes execution, setting temp breakpoint if <irqline> is taken (F7)\n"
+ " gp [<condition>] -- resumes execution, setting temp breakpoint if privilege level changes\n"
" gt[ime] <milliseconds> -- resumes execution until the given delay has elapsed\n"
" gv[blank] -- resumes execution, setting temp breakpoint on the next VBLANK (F8)\n"
" n[ext] -- executes until the next CPU switch (F6)\n"
@@ -187,6 +193,18 @@ const help_item f_static_help_list[] =
" rplist [<CPU>] -- lists all the registerpoints\n"
},
{
+ "exceptionpoints",
+ "\n"
+ "Exception Point Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]] -- sets exception point on <type>\n"
+ " epclear [<epnum>] -- clears a given exception point or all if no <epnum> specified\n"
+ " epdisable [<epnum>] -- disabled a given exception point or all if no <epnum> specified\n"
+ " epenable [<epnum>] -- enables a given exception point or all if no <epnum> specified\n"
+ " eplist -- lists all the exception points\n"
+ },
+ {
"expressions",
"\n"
"Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is "
@@ -341,16 +359,20 @@ const help_item f_static_help_list[] =
"The printf command performs a C-style printf to the debugger console. Only a very limited set of "
"formatting options are available:\n"
"\n"
- " %[0][<n>]d -- prints <item> as a decimal value with optional digit count and zero-fill\n"
- " %[0][<n>]x -- prints <item> as a hexadecimal value with optional digit count and zero-fill\n"
+ " %c -- 8-bit character\n"
+ " %[-][0][<n>]d -- decimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]o -- octal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]x -- lowercase hexadecimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]X -- uppercase hexadecimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][<n>][.[<n>]]s -- null-terminated string of 8-bit characters with optional left justification, minimum and maximum width\n"
"\n"
- "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
- "lines can be printed by embedding a \\n in the text.\n"
+ "All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
+ "printed by embedding a \\n in the text.\n"
"\n"
"Examples:\n"
"\n"
"printf \"PC=%04X\",pc\n"
- " Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ " Prints PC=<pcval> where <pcval> is displayed in uppercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
@@ -361,18 +383,12 @@ const help_item f_static_help_list[] =
" logerror <format>[,<item>[,...]]\n"
"\n"
"The logerror command performs a C-style printf to the error log. Only a very limited set of "
- "formatting options are available:\n"
- "\n"
- " %[0][<n>]d -- logs <item> as a decimal value with optional digit count and zero-fill\n"
- " %[0][<n>]x -- logs <item> as a hexadecimal value with optional digit count and zero-fill\n"
- "\n"
- "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
- "lines can be printed by embedding a \\n in the text.\n"
+ "formatting options are available. See the 'printf' help for details.\n"
"\n"
"Examples:\n"
"\n"
- "logerror \"PC=%04X\",pc\n"
- " Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ "logerror \"PC=%04x\",pc\n"
+ " Logs PC=<pcval> where <pcval> is displayed in lowercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
@@ -578,6 +594,13 @@ const help_item f_static_help_list[] =
" Reads in debugger commands from break_and_trace.cmd and executes them.\n"
},
{
+ "time",
+ "\n"
+ " time\n"
+ "\n"
+ "The time command prints the current machine time to the console.\n"
+ },
+ {
"quit",
"\n"
" quit\n"
@@ -920,6 +943,66 @@ const help_item f_static_help_list[] =
" Resume execution, stopping at address 1234 unless something else stops us first.\n"
},
{
+ "gbf",
+ "\n"
+ " gbf [<condition>]\n"
+ "\n"
+ "The gbf command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a conditional branch or skip instruction tests false and falls through to the "
+ "next instruction, or the instruction that follows its delay slot. The optional conditional "
+ "expression, if provided, will be evaluated at (not after) each conditional branch; execution "
+ "will not halt regardless of consequent program flow unless its result is true (non-zero).\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gbf\n"
+ " Resume execution until the next break/watchpoint or until the next false branch.\n"
+ "\n"
+ "gbf {pc != 1234}\n"
+ " Resume execution until the next false branch, disregarding the instruction at address 1234.\n"
+ },
+ {
+ "gbt",
+ "\n"
+ " gbt [<condition>]\n"
+ "\n"
+ "The gbt command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a conditional branch or skip instruction tests true and program flow transfers "
+ "to any instruction other than the next one following the delay slot (if any). The optional "
+ "conditional expression, if provided, will be evaluated at (not after) each conditional "
+ "branch; execution will not halt regardless of consequent program flow unless its result is "
+ "true (non-zero).\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gbt\n"
+ " Resume execution until the next break/watchpoint or until the next true branch.\n"
+ "\n"
+ "gbt {pc != 1234}\n"
+ " Resume execution until the next true branch, disregarding the instruction at address 1234.\n"
+ },
+ {
+ "gni",
+ "\n"
+ " gn[i] [<count>]\n"
+ "\n"
+ "The gni command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a breakpoint or watchpoint is hit, or until you manually break in using the "
+ "assigned key. Before executing, the gni command sets a temporary unconditional breakpoint "
+ "<count> instructions sequentially past the current one, which is automatically removed when "
+ "hit. If <count> is omitted, its default value is 1. If <count> is specified as zero, the "
+ "command does nothing. <count> is not permitted to exceed 512 decimal."
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gni\n"
+ " Resume execution, stopping at the address of the next instruction unless something else "
+ "stops us first.\n"
+ "\n"
+ "gni 2\n"
+ " Resume execution, stopping at two instructions past the current one.\n"
+ },
+ {
"gex",
"\n"
" ge[x] [<exception>,[<condition>]]\n"
@@ -965,6 +1048,27 @@ const help_item f_static_help_list[] =
"acknowledged on the current CPU.\n"
},
{
+ "gp",
+ "\n"
+ " gp [<condition>]\n"
+ "\n"
+ "The gp command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or the privilege level of the current "
+ "CPU changes. The optional <condition> parameter lets you specify an expression that will "
+ "be evaluated each time the privilege level changes. If the expression evaluates to true "
+ "(non-zero), execution will halt; otherwise, execution will continue with no notification.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gp\n"
+ " Resume execution until the next break/watchpoint or the privilege level of the current "
+ "CPU changes.\n"
+ "\n"
+ "gp {pc != 1234}\n"
+ " Resume execution until the next break/watchpoint or the privilege level of the current "
+ "CPU changes, disregarding the instruction at address 1234.\n"
+ },
+ {
"gtime",
"\n"
" gt[ime] <milliseconds>\n"
@@ -1484,6 +1588,92 @@ const help_item f_static_help_list[] =
"actions attached to them.\n"
},
{
+ "epset",
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]]\n"
+ "\n"
+ "Sets a new exception point for exceptions of type <type> on the currently visible CPU. "
+ "The optional <condition> parameter lets you specify an expression that will be evaluated "
+ "each time the exception point is hit. If the result of the expression is true (non-zero), "
+ "the exception point will actually halt execution at the start of the exception handler; "
+ "otherwise, execution will continue with no notification. The optional <action> parameter "
+ "provides a command that is executed whenever the exception point is hit and the "
+ "<condition> is true. Note that you may need to embed the action within braces { } in order "
+ "to prevent commas and semicolons from being interpreted as applying to the epset command "
+ "itself.\n"
+ "\n"
+ "The numbering of exceptions depends upon the CPU type. Causes of exceptions may include "
+ "internally or externally vectored interrupts, errors occurring within instructions and "
+ "system calls.\n"
+ "\n"
+ "Each exception point that is set is assigned an index which can be used in other "
+ "exception point commands to reference this exception point.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "ep 2\n"
+ " Set an exception that will halt execution whenever the visible CPU raises exception "
+ "number 2.\n"
+ },
+ {
+ "epclear",
+ "\n"
+ " epclear [<epnum>[,...]]\n"
+ "\n"
+ "The epclear command clears exception points. If <epnum> is specified, only the requested "
+ "exception points are cleared, otherwise all exception points are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epclear 3\n"
+ " Clear exception point index 3.\n"
+ "\n"
+ "epclear\n"
+ " Clear all exception points.\n"
+ },
+ {
+ "epdisable",
+ "\n"
+ " epdisable [<epnum>[,...]]\n"
+ "\n"
+ "The epdisable command disables exception points. If <epnum> is specified, only the requested "
+ "exception points are disabled, otherwise all exception points are disabled. Note that "
+ "disabling an exception point does not delete it, it just temporarily marks the exception "
+ "point as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epdisable 3\n"
+ " Disable exception point index 3.\n"
+ "\n"
+ "epdisable\n"
+ " Disable all exception points.\n"
+ },
+ {
+ "epenable",
+ "\n"
+ " epenable [<epnum>[,...]]\n"
+ "\n"
+ "The epenable command enables exception points. If <epnum> is specified, only the "
+ "requested exception points are enabled, otherwise all exception points are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epenable 3\n"
+ " Enable exception point index 3.\n"
+ "\n"
+ "epenable\n"
+ " Enable all exception points.\n"
+ },
+ {
+ "eplist",
+ "\n"
+ " eplist\n"
+ "\n"
+ "The eplist command lists all the current exception points, along with their index and "
+ "any conditions or actions attached to them.\n"
+ },
+ {
"map",
"\n"
" map[{d|i|o}] <address>[:<space>]\n"
@@ -1853,10 +2043,12 @@ private:
help_map m_help_list;
help_item const *m_uncached_help = std::begin(f_static_help_list);
+ util::ovectorstream m_message_buffer;
+
help_manager() = default;
public:
- char const *find(std::string_view tag)
+ std::string_view find(std::string_view tag)
{
// find a cached exact match if possible
std::string const lower = strmakelower(tag);
@@ -1892,16 +2084,17 @@ public:
if ((m_help_list.end() == next) || (next->first.substr(0, lower.length()) != lower))
return candidate->second;
- // TODO: pointers to static strings are bad, mmmkay?
- static char ambig_message[1024];
- int msglen = std::sprintf(ambig_message, "Ambiguous help request, did you mean:\n");
+ m_message_buffer.clear();
+ m_message_buffer.reserve(1024);
+ m_message_buffer.seekp(0, util::ovectorstream::beg);
+ m_message_buffer << "Ambiguous help request, did you mean:\n";
do
{
- msglen += std::sprintf(&ambig_message[msglen], " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]);
+ util::stream_format(m_message_buffer, " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]);
++candidate;
}
while ((m_help_list.end() != candidate) && (candidate->first.substr(0, lower.length()) == lower));
- return ambig_message;
+ return util::buf_to_string_view(m_message_buffer);
}
// take the first help entry if no matches at all
@@ -1923,7 +2116,7 @@ public:
PUBLIC INTERFACE
***************************************************************************/
-const char *debug_get_help(std::string_view tag)
+std::string_view debug_get_help(std::string_view tag)
{
return help_manager::instance().find(tag);
}
diff --git a/src/emu/debug/debughlp.h b/src/emu/debug/debughlp.h
index 495d674eb0d..9efe12acaca 100644
--- a/src/emu/debug/debughlp.h
+++ b/src/emu/debug/debughlp.h
@@ -21,6 +21,6 @@
***************************************************************************/
// help management
-const char *debug_get_help(std::string_view tag);
+std::string_view debug_get_help(std::string_view tag);
#endif // MAME_EMU_DEBUG_DEBUGHLP_H
diff --git a/src/emu/debug/debugvw.cpp b/src/emu/debug/debugvw.cpp
index 5bcc3d057b8..54fe57ecf5a 100644
--- a/src/emu/debug/debugvw.cpp
+++ b/src/emu/debug/debugvw.cpp
@@ -503,11 +503,11 @@ bool debug_view_expression::recompute()
std::string oldstring(m_parsed.original_string());
try
{
- m_parsed.parse(m_string.c_str());
+ m_parsed.parse(m_string);
}
catch (expression_error &)
{
- m_parsed.parse(oldstring.c_str());
+ m_parsed.parse(oldstring);
}
}
diff --git a/src/emu/debug/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp
index b42b86a0e90..d7be62c1eaa 100644
--- a/src/emu/debug/dvbpoints.cpp
+++ b/src/emu/debug/dvbpoints.cpp
@@ -71,7 +71,7 @@ static bool cConditionDescending(const debug_breakpoint *a, const debug_breakpoi
static bool cActionAscending(const debug_breakpoint *a, const debug_breakpoint *b)
{
- return strcmp(a->action(), b->action()) < 0;
+ return a->action() < b->action();
}
static bool cActionDescending(const debug_breakpoint *a, const debug_breakpoint *b)
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index 02fcde9cbc3..da792305c0d 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -20,6 +20,20 @@
//**************************************************************************
+// HELPER FUNCTIONS
+//**************************************************************************
+
+namespace {
+
+constexpr u8 sanitise_character(u8 ch)
+{
+ // assume ISO-8859-1 (low 256 Unicode codepoints) - tab, soft hyphen, C0 and C1 cause problems
+ return ('\t' == ch) ? ' ' : (0xadU == ch) ? '-' : ((' ' > ch) || (('~' < ch) && (0xa0U > ch))) ? '.' : ch;
+}
+
+} // anonymous namespace
+
+//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -295,13 +309,13 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
// generate the address
char addrtext[20];
- sprintf(addrtext, m_addrformat.c_str(), address);
+ snprintf(addrtext, 20, m_addrformat.c_str(), address);
debug_view_char *dest = destrow + m_section[0].m_pos + 1;
for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++)
if (dest >= destmin && dest < destmax)
dest->byte = addrtext[ch];
- // generate the data and the ascii string
+ // generate the data and the ASCII string
std::string chunkascii;
if (m_shift_bits != 0)
{
@@ -323,7 +337,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
for (int i = 0; i < m_bytes_per_chunk; i++)
{
u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
- chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ chunkascii += char(ismapped ? sanitise_character(chval) : '.');
}
}
}
@@ -345,15 +359,15 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
switch (m_data_format)
{
case data_format::FLOAT_32BIT:
- sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata)));
+ snprintf(valuetext, 64, "%.8g", u32_to_float(u32(chunkdata)));
break;
case data_format::FLOAT_64BIT:
- sprintf(valuetext, "%.24g", u64_to_double(chunkdata));
+ snprintf(valuetext, 64, "%.24g", u64_to_double(chunkdata));
break;
case data_format::FLOAT_80BIT:
{
float64_t f64 = extF80M_to_f64(&chunkdata80);
- sprintf(valuetext, "%.24g", u64_to_double(f64.v));
+ snprintf(valuetext, 64, "%.24g", u64_to_double(f64.v));
break;
}
default:
@@ -380,7 +394,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
for (int i = 0; i < m_bytes_per_chunk; i++)
{
u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
- chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ chunkascii += char(ismapped ? sanitise_character(chval) : '.');
}
}
}
@@ -526,16 +540,8 @@ void debug_view_memory::view_char(int chval)
if (hexchar == nullptr || (m_shift_bits == 3 && chval >= '8'))
break;
- const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
- offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(pos.m_address) : pos.m_address;
- u64 data;
- bool ismapped = read(m_bytes_per_chunk, address, data);
- if (!ismapped)
- break;
-
- data &= ~(util::make_bitmask<u64>(m_shift_bits) << pos.m_shift);
- data |= u64(hexchar - hexvals) << pos.m_shift;
- write(m_bytes_per_chunk, address, data);
+ if (!write_digit(pos.m_address, pos.m_shift, hexchar - hexvals))
+ break; // TODO: alert OSD?
}
// fall through to the right-arrow press
[[fallthrough]];
@@ -856,14 +862,17 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data)
auto dis = machine().disable_side_effects();
bool ismapped = offs <= m_maxaddr;
+ address_space *tspace;
if (ismapped && !m_no_translation)
{
offs_t dummyaddr = offs;
- ismapped = source.m_memintf->translate(source.m_space->spacenum(), TRANSLATE_READ_DEBUG, dummyaddr);
+ ismapped = source.m_memintf->translate(source.m_space->spacenum(), device_memory_interface::TR_READ, dummyaddr, tspace);
}
+ else
+ tspace = source.m_space;
data = ~u64(0);
if (ismapped)
- data = m_expression.context().read_memory(*source.m_space, offs, size, !m_no_translation);
+ data = m_expression.context().read_memory(*tspace, offs, size, !m_no_translation);
return ismapped;
}
@@ -984,6 +993,41 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data)
//-------------------------------------------------
+// write_digit - write one hex or octal digit
+// at the given address and bit position
+//-------------------------------------------------
+
+bool debug_view_memory::write_digit(offs_t offs, u8 pos, u8 digit)
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+ offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(offs) : offs;
+ u64 data;
+ bool ismapped = read(m_bytes_per_chunk, address, data);
+ if (!ismapped)
+ return false;
+
+ // clamp to chunk size
+ if (m_bytes_per_chunk * 8 < pos + m_shift_bits)
+ {
+ assert(m_bytes_per_chunk * 8 > pos);
+ digit &= util::make_bitmask<u8>(m_bytes_per_chunk * 8 - pos);
+ }
+
+ u64 write_data = (data & ~(util::make_bitmask<u64>(m_shift_bits) << pos)) | (u64(digit) << pos);
+ write(m_bytes_per_chunk, address, write_data);
+
+ // verify that data reads back as it was written
+ if (source.m_space != nullptr)
+ {
+ read(m_bytes_per_chunk, address, data);
+ return data == write_data;
+ }
+ else
+ return true;
+}
+
+
+//-------------------------------------------------
// set_expression - set the expression string
// describing the home address
//-------------------------------------------------
diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h
index f2c738a6ff4..6f1ffab4e9e 100644
--- a/src/emu/debug/dvmemory.h
+++ b/src/emu/debug/dvmemory.h
@@ -127,6 +127,7 @@ private:
// memory access
bool read(u8 size, offs_t offs, u64 &data);
void write(u8 size, offs_t offs, u64 data);
+ bool write_digit(offs_t offs, u8 pos, u8 digit);
bool read(u8 size, offs_t offs, extFloat80_t &data);
bool read_chunk(offs_t address, int chunknum, u64 &chunkdata);
void generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address);
diff --git a/src/emu/debug/dvrpoints.cpp b/src/emu/debug/dvrpoints.cpp
index 3ecadaec8e5..7295a1b2170 100644
--- a/src/emu/debug/dvrpoints.cpp
+++ b/src/emu/debug/dvrpoints.cpp
@@ -62,7 +62,7 @@ bool cConditionDescending(std::pair<device_t *, debug_registerpoint const *> con
bool cActionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
- return strcmp(a.second->action(), b.second->action()) < 0;
+ return a.second->action() < b.second->action();
}
bool cActionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index 8363928e5cb..9ab75b7b655 100644
--- a/src/emu/debug/express.cpp
+++ b/src/emu/debug/express.cpp
@@ -387,10 +387,10 @@ void symbol_table::set_memory_modified_func(memory_modified_func modified)
// add - add a new u64 pointer symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, read_write rw, u64 *ptr)
+symbol_entry &symbol_table::add(const char *name, read_write rw, u64 *ptr)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr)).first->second;
}
@@ -398,10 +398,10 @@ void symbol_table::add(const char *name, read_write rw, u64 *ptr)
// add - add a new value symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, u64 value)
+symbol_entry &symbol_table::add(const char *name, u64 value)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value)).first->second;
}
@@ -409,10 +409,10 @@ void symbol_table::add(const char *name, u64 value)
// add - add a new register symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
+symbol_entry &symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)).first->second;
}
@@ -420,10 +420,10 @@ void symbol_table::add(const char *name, getter_func getter, setter_func setter,
// add - add a new function symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
+symbol_entry &symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute));
+ return *m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)).first->second;
}
@@ -482,23 +482,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo
{
u64 result = ~u64(0) >> (64 - 8*size);
+ address_space *tspace = &space;
+
if (apply_translation)
{
// mask against the logical byte mask
address &= space.logaddrmask();
// translate if necessary; if not mapped, return 0xffffffffffffffff
- if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace))
return result;
}
// otherwise, call the reading function for the translated address
switch (size)
{
- case 1: result = space.read_byte(address); break;
- case 2: result = space.read_word_unaligned(address); break;
- case 4: result = space.read_dword_unaligned(address); break;
- case 8: result = space.read_qword_unaligned(address); break;
+ case 1: result = tspace->read_byte(address); break;
+ case 2: result = tspace->read_word_unaligned(address); break;
+ case 4: result = tspace->read_dword_unaligned(address); break;
+ case 8: result = tspace->read_qword_unaligned(address); break;
}
return result;
}
@@ -511,23 +513,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo
void symbol_table::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation)
{
+ address_space *tspace = &space;
+
if (apply_translation)
{
// mask against the logical byte mask
address &= space.logaddrmask();
// translate if necessary; if not mapped, we're done
- if (!space.device().memory().translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address))
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_WRITE, address, tspace))
return;
}
// otherwise, call the writing function for the translated address
switch (size)
{
- case 1: space.write_byte(address, data); break;
- case 2: space.write_word_unaligned(address, data); break;
- case 4: space.write_dword_unaligned(address, data); break;
- case 8: space.write_qword_unaligned(address, data); break;
+ case 1: tspace->write_byte(address, data); break;
+ case 2: tspace->write_word_unaligned(address, data); break;
+ case 4: tspace->write_dword_unaligned(address, data); break;
+ case 8: tspace->write_qword_unaligned(address, data); break;
}
notify_memory_modified();
@@ -1736,7 +1740,7 @@ void parsed_expression::infix_to_postfix()
else if (token->is_operator())
{
// normalize the operator based on neighbors
- normalize_operator(*token, prev, next != m_tokenlist.end() ? &*next : nullptr, stack, was_rparen);
+ normalize_operator(*token, prev, next != origlist.end() ? &*next : nullptr, stack, was_rparen);
was_rparen = false;
// if the token is an opening parenthesis, push it onto the stack.
diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h
index 23284193f47..251d8b4365c 100644
--- a/src/emu/debug/express.h
+++ b/src/emu/debug/express.h
@@ -86,17 +86,19 @@ public:
};
// construction/destruction
- expression_error(error_code code, int offset = 0, int num = 0)
- : m_code(code),
- m_offset(offset),
- m_num(num) { }
+ constexpr expression_error(error_code code, int offset = 0, int num = 0)
+ : m_code(code)
+ , m_offset(offset)
+ , m_num(num)
+ {
+ }
// operators
- operator error_code() const { return m_code; }
+ constexpr operator error_code() const { return m_code; }
// getters
- error_code code() const { return m_code; }
- int offset() const { return m_offset; }
+ constexpr error_code code() const { return m_code; }
+ constexpr int offset() const { return m_offset; }
std::string code_string() const;
private:
@@ -175,15 +177,16 @@ public:
// getters
const std::unordered_map<std::string, std::unique_ptr<symbol_entry>> &entries() const { return m_symlist; }
symbol_table *parent() const { return m_parent; }
+ running_machine &machine() { return m_machine; }
// setters
void set_memory_modified_func(memory_modified_func modified);
// symbol access
- void add(const char *name, read_write rw, u64 *ptr = nullptr);
- void add(const char *name, u64 constvalue);
- void add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = "");
- void add(const char *name, int minparams, int maxparams, execute_func execute);
+ symbol_entry &add(const char *name, read_write rw, u64 *ptr = nullptr);
+ symbol_entry &add(const char *name, u64 constvalue);
+ symbol_entry &add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = "");
+ symbol_entry &add(const char *name, int minparams, int maxparams, execute_func execute);
symbol_entry *find(const char *name) const { if (name) { auto search = m_symlist.find(name); if (search != m_symlist.end()) return search->second.get(); else return nullptr; } else return nullptr; }
symbol_entry *find_deep(const char *name);
diff --git a/src/emu/debug/points.cpp b/src/emu/debug/points.cpp
index c44bc3f7563..961488eebb2 100644
--- a/src/emu/debug/points.cpp
+++ b/src/emu/debug/points.cpp
@@ -22,18 +22,19 @@
// debug_breakpoint - constructor
//-------------------------------------------------
-debug_breakpoint::debug_breakpoint(device_debug* debugInterface,
- symbol_table &symbols,
- int index,
- offs_t address,
- const char *condition,
- const char *action)
- : m_debugInterface(debugInterface),
- m_index(index),
- m_enabled(true),
- m_address(address),
- m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : "")
+debug_breakpoint::debug_breakpoint(
+ device_debug *debugInterface,
+ symbol_table &symbols,
+ int index,
+ offs_t address,
+ const char *condition,
+ std::string_view action) :
+ m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_address(address),
+ m_condition(symbols, condition ? condition : "1"),
+ m_action(action)
{
}
@@ -59,7 +60,7 @@ bool debug_breakpoint::hit(offs_t pc)
{
return (m_condition.execute() != 0);
}
- catch (expression_error &)
+ catch (expression_error const &)
{
return false;
}
@@ -78,27 +79,28 @@ bool debug_breakpoint::hit(offs_t pc)
// debug_watchpoint - constructor
//-------------------------------------------------
-debug_watchpoint::debug_watchpoint(device_debug* debugInterface,
- symbol_table &symbols,
- int index,
- address_space &space,
- read_or_write type,
- offs_t address,
- offs_t length,
- const char *condition,
- const char *action)
- : m_debugInterface(debugInterface),
- m_phr(nullptr),
- m_phw(nullptr),
- m_space(space),
- m_index(index),
- m_enabled(true),
- m_type(type),
- m_address(address & space.addrmask()),
- m_length(length),
- m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : ""),
- m_installing(false)
+debug_watchpoint::debug_watchpoint(
+ device_debug* debugInterface,
+ symbol_table &symbols,
+ int index,
+ address_space &space,
+ read_or_write type,
+ offs_t address,
+ offs_t length,
+ const char *condition,
+ std::string_view action) :
+ m_debugInterface(debugInterface),
+ m_phr(nullptr),
+ m_phw(nullptr),
+ m_space(space),
+ m_index(index),
+ m_enabled(true),
+ m_type(type),
+ m_address(address & space.addrmask()),
+ m_length(length),
+ m_condition(symbols, condition ? condition : "1"),
+ m_action(action),
+ m_installing(false)
{
std::fill(std::begin(m_start_address), std::end(m_start_address), 0);
std::fill(std::begin(m_end_address), std::end(m_end_address), 0);
@@ -170,21 +172,21 @@ debug_watchpoint::debug_watchpoint(device_debug* debugInterface,
}
install(read_or_write::READWRITE);
- m_notifier = m_space.add_change_notifier([this](read_or_write mode) {
- if (m_enabled)
- {
- install(mode);
- }
- });
+ m_notifier = m_space.add_change_notifier(
+ [this] (read_or_write mode)
+ {
+ if (m_enabled)
+ {
+ install(mode);
+ }
+ });
}
debug_watchpoint::~debug_watchpoint()
{
- m_space.remove_change_notifier(m_notifier);
- if (m_phr)
- m_phr->remove();
- if (m_phw)
- m_phw->remove();
+ m_notifier.reset();
+ m_phr.remove();
+ m_phw.remove();
}
void debug_watchpoint::setEnabled(bool value)
@@ -197,10 +199,8 @@ void debug_watchpoint::setEnabled(bool value)
else
{
m_installing = true;
- if(m_phr)
- m_phr->remove();
- if(m_phw)
- m_phw->remove();
+ m_phr.remove();
+ m_phw.remove();
m_installing = false;
}
}
@@ -211,24 +211,28 @@ void debug_watchpoint::install(read_or_write mode)
if (m_installing)
return;
m_installing = true;
- if ((u32(mode) & u32(read_or_write::READ)) && m_phr)
- m_phr->remove();
- if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw)
- m_phw->remove();
+ if (u32(mode) & u32(read_or_write::READ))
+ m_phr.remove();
+ if (u32(mode) & u32(read_or_write::WRITE))
+ m_phw.remove();
std::string name = util::string_format("wp@%x", m_address);
switch (m_space.data_width())
{
case 8:
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name,
- [this](offs_t offset, u8 &data, u8 mem_mask) {
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[0], m_end_address[0], name,
+ [this](offs_t offset, u8 &data, u8 mem_mask) {
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name,
- [this](offs_t offset, u8 &data, u8 mem_mask) {
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[0], m_end_address[0], name,
+ [this](offs_t offset, u8 &data, u8 mem_mask) {
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
break;
case 16:
@@ -237,17 +241,21 @@ void debug_watchpoint::install(read_or_write mode)
{
u16 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
@@ -257,17 +265,21 @@ void debug_watchpoint::install(read_or_write mode)
{
u32 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
@@ -277,17 +289,20 @@ void debug_watchpoint::install(read_or_write mode)
{
u64 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
}
@@ -416,11 +431,11 @@ void debug_watchpoint::triggered(read_or_write type, offs_t address, u64 data, u
// debug_registerpoint - constructor
//-------------------------------------------------
-debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action)
+debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action)
: m_index(index),
m_enabled(true),
m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : "")
+ m_action(action)
{
}
@@ -450,3 +465,59 @@ bool debug_registerpoint::hit()
return true;
}
+
+
+//**************************************************************************
+// DEBUG EXCEPTION POINT
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_exceptionpoint - constructor
+//-------------------------------------------------
+
+debug_exceptionpoint::debug_exceptionpoint(
+ device_debug *debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition,
+ std::string_view action)
+ : m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_type(type),
+ m_condition(symbols, (condition != nullptr) ? condition : "1"),
+ m_action(action)
+{
+}
+
+
+//-------------------------------------------------
+// hit - detect a hit
+//-------------------------------------------------
+
+bool debug_exceptionpoint::hit(int exception)
+{
+ // don't hit if disabled
+ if (!m_enabled)
+ return false;
+
+ // must match our type
+ if (m_type != exception)
+ return false;
+
+ // must satisfy the condition
+ if (!m_condition.is_empty())
+ {
+ try
+ {
+ return (m_condition.execute() != 0);
+ }
+ catch (expression_error &)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h
index 84cdad7720b..42abd46398f 100644
--- a/src/emu/debug/points.h
+++ b/src/emu/debug/points.h
@@ -36,7 +36,7 @@ public:
int index,
offs_t address,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
// getters
const device_debug *debugInterface() const { return m_debugInterface; }
@@ -44,7 +44,7 @@ public:
bool enabled() const { return m_enabled; }
offs_t address() const { return m_address; }
const char *condition() const { return m_condition.original_string(); }
- const char *action() const { return m_action.c_str(); }
+ const std::string &action() const { return m_action; }
// setters
void setEnabled(bool value) { m_enabled = value; } // FIXME: need to update breakpoint flags but it's a private method
@@ -77,7 +77,7 @@ public:
offs_t address,
offs_t length,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
~debug_watchpoint();
// getters
@@ -102,8 +102,8 @@ private:
void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask);
device_debug * m_debugInterface; // the interface we were created from
- memory_passthrough_handler *m_phr; // passthrough handler reference, read access
- memory_passthrough_handler *m_phw; // passthrough handler reference, write access
+ memory_passthrough_handler m_phr; // passthrough handler reference, read access
+ memory_passthrough_handler m_phw; // passthrough handler reference, write access
address_space & m_space; // address space
int m_index; // user reported index
bool m_enabled; // enabled?
@@ -112,7 +112,7 @@ private:
offs_t m_length; // length of watch area
parsed_expression m_condition; // condition
std::string m_action; // action
- int m_notifier; // address map change notifier id
+ util::notifier_subscription m_notifier; // address map change notifier ID
offs_t m_start_address[3]; // the start addresses of the checks to install
offs_t m_end_address[3]; // the end addresses
@@ -128,13 +128,13 @@ class debug_registerpoint
public:
// construction/destruction
- debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr);
+ debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action = {});
// getters
int index() const { return m_index; }
bool enabled() const { return m_enabled; }
const char *condition() const { return m_condition.original_string(); }
- const char *action() const { return m_action.c_str(); }
+ const std::string &action() const { return m_action; }
private:
// internals
@@ -146,4 +146,42 @@ private:
std::string m_action; // action
};
+// ======================> debug_exceptionpoint
+
+class debug_exceptionpoint
+{
+ friend class device_debug;
+
+public:
+ // construction/destruction
+ debug_exceptionpoint(
+ device_debug* debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition = nullptr,
+ std::string_view action = {});
+
+ // getters
+ const device_debug *debugInterface() const { return m_debugInterface; }
+ int index() const { return m_index; }
+ bool enabled() const { return m_enabled; }
+ int type() const { return m_type; }
+ const char *condition() const { return m_condition.original_string(); }
+ const std::string &action() const { return m_action; }
+
+ // setters
+ void setEnabled(bool value) { m_enabled = value; }
+
+private:
+ // internals
+ bool hit(int exception);
+ const device_debug * m_debugInterface; // the interface we were created from
+ int m_index; // user reported index
+ bool m_enabled; // enabled?
+ int m_type; // exception type
+ parsed_expression m_condition; // condition
+ std::string m_action; // action
+};
+
#endif // MAME_EMU_DEBUG_POINTS_H
diff --git a/src/emu/devcb.cpp b/src/emu/devcb.cpp
index 19970f45c5f..b6e08f13b45 100644
--- a/src/emu/devcb.cpp
+++ b/src/emu/devcb.cpp
@@ -257,7 +257,6 @@ template class devcb_write8::creator_impl<devcb_write8::latched_inputline_builde
template class devcb_write8::creator_impl<devcb_write8::ioport_builder>;
template class devcb_write8::creator_impl<devcb_write8::membank_builder>;
template class devcb_write8::creator_impl<devcb_write8::output_builder>;
-template class devcb_write8::creator_impl<devcb_write8::log_builder>;
template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8s_delegate> >;
template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >;
@@ -277,7 +276,6 @@ template class devcb_write16::creator_impl<devcb_write16::latched_inputline_buil
template class devcb_write16::creator_impl<devcb_write16::ioport_builder>;
template class devcb_write16::creator_impl<devcb_write16::membank_builder>;
template class devcb_write16::creator_impl<devcb_write16::output_builder>;
-template class devcb_write16::creator_impl<devcb_write16::log_builder>;
template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8s_delegate> >;
template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >;
@@ -297,7 +295,6 @@ template class devcb_write32::creator_impl<devcb_write32::latched_inputline_buil
template class devcb_write32::creator_impl<devcb_write32::ioport_builder>;
template class devcb_write32::creator_impl<devcb_write32::membank_builder>;
template class devcb_write32::creator_impl<devcb_write32::output_builder>;
-template class devcb_write32::creator_impl<devcb_write32::log_builder>;
template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8s_delegate> >;
template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >;
@@ -317,7 +314,6 @@ template class devcb_write64::creator_impl<devcb_write64::latched_inputline_buil
template class devcb_write64::creator_impl<devcb_write64::ioport_builder>;
template class devcb_write64::creator_impl<devcb_write64::membank_builder>;
template class devcb_write64::creator_impl<devcb_write64::output_builder>;
-template class devcb_write64::creator_impl<devcb_write64::log_builder>;
template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8s_delegate> >;
template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >;
@@ -337,11 +333,11 @@ template class devcb_write_line::creator_impl<devcb_write_line::latched_inputlin
template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>;
template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>;
template class devcb_write_line::creator_impl<devcb_write_line::output_builder>;
-template class devcb_write_line::creator_impl<devcb_write_line::log_builder>;
devcb_base::devcb_base(device_t &owner)
- : m_owner(owner)
+ : device_resolver_base(owner)
+ , m_owner(owner)
{
}
diff --git a/src/emu/devcb.h b/src/emu/devcb.h
index d27d3beb74d..be62d8b6365 100644
--- a/src/emu/devcb.h
+++ b/src/emu/devcb.h
@@ -64,11 +64,8 @@ template <typename T> struct rw_delegate_type<T, void_t<rw_device_class_t<write_
///
/// Provides utilities for supporting multiple read/write/transform
/// signatures, and the base exclusive-or/mask transform methods.
-class devcb_base
+class devcb_base : protected device_resolver_base
{
-public:
- virtual void validity_check(validity_checker &valid) const = 0;
-
protected:
// This is in C++17 but not C++14
template <typename... T> struct void_wrapper { using type = void; };
@@ -82,16 +79,10 @@ protected:
template <typename T, typename U> using mask_t = std::make_unsigned_t<intermediate_t<T, U> >;
// Detecting candidates for transform functions
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form1 : public std::false_type { };
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form2 : public std::false_type { };
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form3 : public std::false_type { };
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form4 : public std::false_type { };
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form5 : public std::false_type { };
- template <typename Input, typename Result, typename Func, typename Enable = void> struct is_transform_form6 : public std::false_type { };
- template <typename Input, typename Result, typename Func> struct is_transform_form3<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input, std::make_unsigned_t<Input> &>, Result>::value> > : public std::true_type { };
- template <typename Input, typename Result, typename Func> struct is_transform_form4<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t &, Input>, Result>::value> > : public std::true_type { };
- template <typename Input, typename Result, typename Func> struct is_transform_form6<Input, Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, Input>, Result>::value> > : public std::true_type { };
- template <typename Input, typename Result, typename Func> struct is_transform : public std::bool_constant<is_transform_form1<Input, Result, Func>::value || is_transform_form2<Input, Result, Func>::value || is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form5<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value> { };
+ template <typename Input, typename Result, typename Func> using is_transform_form3 = std::is_invocable_r<Result, Func, offs_t &, Input, std::make_unsigned_t<Input> &>;
+ template <typename Input, typename Result, typename Func> using is_transform_form4 = std::is_invocable_r<Result, Func, offs_t &, Input>;
+ template <typename Input, typename Result, typename Func> using is_transform_form6 = std::is_invocable_r<Result, Func, Input>;
+ template <typename Input, typename Result, typename Func> using is_transform = std::bool_constant<is_transform_form3<Input, Result, Func>::value || is_transform_form4<Input, Result, Func>::value || is_transform_form6<Input, Result, Func>::value>;
// Determining the result type of a transform function
template <typename Input, typename Result, typename Func, typename Enable = void> struct transform_result;
@@ -137,12 +128,18 @@ protected:
auto rshift(unsigned val)
{
auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask >>= val; return data >> val; }));
- return inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask >> val));
+ if (inherited_mask())
+ return trans;
+ else
+ return std::move(trans.mask(m_mask >> val));
}
auto lshift(unsigned val)
{
auto trans(static_cast<Impl &>(*this).transform([val] (offs_t offset, T data, std::make_unsigned_t<T> &mem_mask) { mem_mask <<= val; return data << val; }));
- return inherited_mask() ? std::move(trans) : std::move(trans.mask(m_mask << val));
+ if (inherited_mask())
+ return trans;
+ else
+ return std::move(trans.mask(m_mask << val));
}
auto bit(unsigned val) { return std::move(rshift(val).mask(T(1U))); }
@@ -174,9 +171,9 @@ protected:
class array : public std::array<T, Count>
{
private:
- template <unsigned... V>
- array(device_t &owner, std::integer_sequence<unsigned, V...> const &)
- : std::array<T, Count>{{ { make_one<V>(owner) }... }}
+ template <unsigned... V, typename... Params>
+ array(device_t &owner, std::integer_sequence<unsigned, V...>, Params &&... args)
+ : std::array<T, Count>{{ { make_one<V>(owner), std::forward<Params>(args)... }... }}
{
}
@@ -185,12 +182,10 @@ protected:
public:
using std::array<T, Count>::array;
- array(device_t &owner) : array(owner, std::make_integer_sequence<unsigned, Count>()) { }
-
- void resolve_all()
+ template <typename... Params>
+ array(device_t &owner, Params &&... args)
+ : array(owner, std::make_integer_sequence<unsigned, Count>(), std::forward<Params>(args)...)
{
- for (T &elem : *this)
- elem.resolve();
}
};
@@ -211,13 +206,10 @@ class devcb_read_base : public devcb_base
{
protected:
// Detecting candidates for read functions
- template <typename Result, typename Func, typename Enable = void> struct is_read_form1 : public std::false_type { };
- template <typename Result, typename Func, typename Enable = void> struct is_read_form2 : public std::false_type { };
- template <typename Result, typename Func, typename Enable = void> struct is_read_form3 : public std::false_type { };
- template <typename Result, typename Func> struct is_read_form1<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t, Result>, Result>::value> > : public std::true_type { };
- template <typename Result, typename Func> struct is_read_form2<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func, offs_t>, Result>::value> > : public std::true_type { };
- template <typename Result, typename Func> struct is_read_form3<Result, Func, std::enable_if_t<std::is_convertible<std::invoke_result_t<Func>, Result>::value> > : public std::true_type { };
- template <typename Result, typename Func> struct is_read : public std::bool_constant<is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value> { };
+ template <typename Result, typename Func> using is_read_form1 = std::is_invocable_r<Result, Func, offs_t, Result>;
+ template <typename Result, typename Func> using is_read_form2 = std::is_invocable_r<Result, Func, offs_t>;
+ template <typename Result, typename Func> using is_read_form3 = std::is_invocable_r<Result, Func>;
+ template <typename Result, typename Func> using is_read = std::bool_constant<is_read_form1<Result, Func>::value || is_read_form2<Result, Func>::value || is_read_form3<Result, Func>::value>;
// Determining the result type of a read function
template <typename Result, typename Func, typename Enable = void> struct read_result;
@@ -275,13 +267,10 @@ class devcb_write_base : public devcb_base
{
protected:
// Detecting candidates for write functions
- template <typename Input, typename Func, typename Enable = void> struct is_write_form1 : public std::false_type { };
- template <typename Input, typename Func, typename Enable = void> struct is_write_form2 : public std::false_type { };
- template <typename Input, typename Func, typename Enable = void> struct is_write_form3 : public std::false_type { };
- template <typename Input, typename Func> struct is_write_form1<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input, std::make_unsigned_t<Input>> > > : public std::true_type { };
- template <typename Input, typename Func> struct is_write_form2<Input, Func, void_t<std::invoke_result_t<Func, offs_t, Input> > > : public std::true_type { };
- template <typename Input, typename Func> struct is_write_form3<Input, Func, void_t<std::invoke_result_t<Func, Input> > > : public std::true_type { };
- template <typename Input, typename Func> struct is_write : public std::bool_constant<is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value> { };
+ template <typename Input, typename Func> using is_write_form1 = std::is_invocable<Func, offs_t, Input, std::make_unsigned_t<Input> >;
+ template <typename Input, typename Func> using is_write_form2 = std::is_invocable<Func, offs_t, Input>;
+ template <typename Input, typename Func> using is_write_form3 = std::is_invocable<Func, Input>;
+ template <typename Input, typename Func> using is_write = std::bool_constant<is_write_form1<Input, Func>::value || is_write_form2<Input, Func>::value || is_write_form3<Input, Func>::value>;
// Detecting candidates for write delegates
template <typename T, typename Enable = void> struct is_write_method : public std::false_type { };
@@ -342,7 +331,7 @@ private:
using ptr = std::unique_ptr<creator>;
virtual ~creator() { }
- virtual void validity_check(validity_checker &valid) const = 0;
+ virtual bool validity_check(validity_checker &valid) const = 0;
virtual func_t create() = 0;
std::make_unsigned_t<Result> mask() const { return m_mask; }
@@ -359,7 +348,7 @@ private:
public:
creator_impl(T &&builder) : creator(builder.mask()), m_builder(std::move(builder)) { }
- virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); }
+ virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); }
virtual func_t create() override
{
@@ -372,28 +361,6 @@ private:
T m_builder;
};
- class log_creator : public creator
- {
- public:
- log_creator(device_t &devbase, std::string &&message) : creator(0U), m_devbase(devbase), m_message(std::move(message)) { }
-
- virtual void validity_check(validity_checker &valid) const override { }
-
- virtual func_t create() override
- {
- return
- [&devbase = m_devbase, message = std::move(m_message)] (offs_t offset, std::make_unsigned_t<Result> mem_mask)
- {
- devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message);
- return Result(0);
- };
- }
-
- private:
- device_t &m_devbase;
- std::string m_message;
- };
-
template <typename Source, typename Func> class transform_builder; // workaround for MSVC
class builder_base
@@ -473,7 +440,7 @@ private:
return transform_builder<transform_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
}
- void validity_check(validity_checker &valid) const { m_src.validity_check(valid); }
+ bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); }
template <typename T>
void build(T &&chain)
@@ -494,7 +461,7 @@ private:
assert(this->m_consumed);
this->built();
chain(
- [src = std::forward<U>(f), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_mask_t &mem_mask)
+ [src = std::forward<U>(f), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_mask_t &mem_mask)
{
typename Source::input_mask_t source_mask(mem_mask);
auto const data(src(offset, source_mask));
@@ -541,7 +508,7 @@ private:
return transform_builder<functoid_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
template <typename T>
void build(T &&chain)
@@ -549,7 +516,7 @@ private:
assert(this->m_consumed);
this->built();
chain(
- [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask)
+ [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask)
{ return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; });
}
@@ -601,11 +568,15 @@ private:
return transform_builder<delegate_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
auto const target(m_delegate.finder_target());
if (target.second && !target.first.subdevice(target.second))
+ {
osd_printf_error("Read callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name());
+ return false;
+ }
+ return true;
}
template <typename T>
@@ -615,7 +586,7 @@ private:
this->built();
m_delegate.resolve();
chain(
- [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask)
+ [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_mask_t mem_mask)
{ return (devcb_read::invoke_read<Result>(cb, offset, mem_mask & mask) ^ exor) & mask; });
}
@@ -661,7 +632,7 @@ private:
return transform_builder<ioport_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, std::move(*this), std::forward<T>(cb), m);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
template <typename T>
void build(T &&chain)
@@ -722,6 +693,13 @@ private:
return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_read::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
}
+ template <typename T>
+ std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name);
+ }
+
template <typename T, typename U, bool R>
std::enable_if_t<is_read_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name)
{
@@ -775,40 +753,6 @@ private:
return set_ioport(std::forward<Params>(args)...);
}
- template <typename... Params>
- void set_log(device_t &devbase, Params &&... args)
- {
- set_used();
- if (!m_append)
- m_target.m_creators.clear();
- m_target.m_creators.emplace_back(std::make_unique<log_creator>(devbase, std::string(std::forward<Params>(args)...)));
- }
-
- template <typename T, typename... Params>
- std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args)
- {
- set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...);
- }
-
- template <typename T, typename... Params>
- std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value> set_log(T &devbase, Params &&... args)
- {
- set_log(devbase.device(), std::forward<Params>(args)...);
- }
-
- template <typename... Params>
- void set_log(Params &&... args)
- {
- set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...);
- }
-
- template <typename... Params>
- void append_log(Params &&... args)
- {
- m_append = true;
- set_log(std::forward<Params>(args)...);
- }
-
auto set_constant(Result val) { return set([val] () { return val; }); }
auto append_constant(Result val) { return append([val] () { return val; }); }
@@ -822,47 +766,46 @@ private:
std::vector<func_t> m_functions;
std::vector<typename creator::ptr> m_creators;
+ Result const m_default;
+ bool m_unset = false;
+
+protected:
+ virtual bool findit(validity_checker *valid) override;
+ virtual void end_configuration() override;
public:
template <unsigned Count>
class array : public devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>
{
public:
- using devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array;
-
- void resolve_all_safe(Result dflt)
+ array(device_t &owner, Result dflt)
+ : devcb_read_base::array<devcb_read<Result, DefaultMask>, Count>::array(owner, dflt)
{
- for (devcb_read<Result, DefaultMask> &elem : *this)
- elem.resolve_safe(dflt);
}
};
- devcb_read(device_t &owner);
+ devcb_read(device_t &owner, Result dflt);
binder bind();
void reset();
- virtual void validity_check(validity_checker &valid) const override;
-
- void resolve();
- void resolve_safe(Result dflt);
-
Result operator()(offs_t offset, std::make_unsigned_t<Result> mem_mask = DefaultMask);
Result operator()();
- bool isnull() const { return m_functions.empty() && m_creators.empty(); }
- explicit operator bool() const { return !m_functions.empty(); }
+ bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); }
};
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
-devcb_read<Result, DefaultMask>::devcb_read(device_t &owner)
+devcb_read<Result, DefaultMask>::devcb_read(device_t &owner, Result dflt)
: devcb_read_base(owner)
+ , m_default(dflt & DefaultMask)
{
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
typename devcb_read<Result, DefaultMask>::binder devcb_read<Result, DefaultMask>::bind()
{
+ assert(m_functions.empty());
return binder(*this);
}
@@ -874,38 +817,48 @@ void devcb_read<Result, DefaultMask>::reset()
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
-void devcb_read<Result, DefaultMask>::validity_check(validity_checker &valid) const
+bool devcb_read<Result, DefaultMask>::findit(validity_checker *valid)
{
assert(m_functions.empty());
- for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i)
+ if (!valid)
{
- (*i)->validity_check(valid);
- std::make_unsigned_t<Result> const m((*i)->mask());
- for (typename std::vector<typename creator::ptr>::const_iterator j = std::next(i); m_creators.end() != j; ++j)
+ // FIXME: report errors by returning false rather than throwing fatal errors
+ m_functions.reserve(m_creators.size());
+ for (typename creator::ptr const &c : m_creators)
+ m_functions.emplace_back(c->create());
+ m_creators.clear();
+ if (m_functions.empty())
{
- std::make_unsigned_t<Result> const n((*j)->mask());
- if (m & n)
- osd_printf_error("Read callback masks %lX and %lX overlap\n", static_cast<unsigned long>(m), static_cast<unsigned long>(n)); // FIXME: doesn't work with u64
+ m_functions.emplace_back([dflt = m_default] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; });
+ m_unset = true;
}
+ return true;
+ }
+ else
+ {
+ bool success(true);
+ for (typename std::vector<typename creator::ptr>::const_iterator i = m_creators.begin(); m_creators.end() != i; ++i)
+ {
+ if (!(*i)->validity_check(*valid))
+ success = false;
+ std::make_unsigned_t<Result> const m((*i)->mask());
+ for (typename std::vector<typename creator::ptr>::const_iterator j = std::next(i); m_creators.end() != j; ++j)
+ {
+ std::make_unsigned_t<Result> const n((*j)->mask());
+ if (m & n)
+ {
+ osd_printf_error("Read callback masks 0x%X and 0x%X overlap\n", m, n);
+ success = false;
+ }
+ }
+ }
+ return success;
}
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
-void devcb_read<Result, DefaultMask>::resolve()
-{
- assert(m_functions.empty());
- m_functions.reserve(m_creators.size());
- for (typename creator::ptr const &c : m_creators)
- m_functions.emplace_back(c->create());
- m_creators.clear();
-}
-
-template <typename Result, std::make_unsigned_t<Result> DefaultMask>
-void devcb_read<Result, DefaultMask>::resolve_safe(Result dflt)
+void devcb_read<Result, DefaultMask>::end_configuration()
{
- resolve();
- if (m_functions.empty())
- m_functions.emplace_back([dflt] (offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; });
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
@@ -943,7 +896,7 @@ private:
using ptr = std::unique_ptr<creator>;
virtual ~creator() { }
- virtual void validity_check(validity_checker &valid) const = 0;
+ virtual bool validity_check(validity_checker &valid) const = 0;
virtual func_t create() = 0;
};
@@ -953,7 +906,7 @@ private:
public:
creator_impl(T &&builder) : m_builder(std::move(builder)) { }
- virtual void validity_check(validity_checker &valid) const override { m_builder.validity_check(valid); }
+ virtual bool validity_check(validity_checker &valid) const override { return m_builder.validity_check(valid); }
virtual func_t create() override
{
@@ -967,7 +920,7 @@ private:
class nop_creator : public creator
{
public:
- virtual void validity_check(validity_checker &valid) const override { }
+ virtual bool validity_check(validity_checker &valid) const override { return true; }
virtual func_t create() override { return [] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { }; }
};
@@ -1066,7 +1019,7 @@ private:
});
}
- void validity_check(validity_checker &valid) const { m_src.validity_check(valid); }
+ bool validity_check(validity_checker &valid) const { return m_src.validity_check(valid); }
private:
transform_builder(transform_builder const &) = delete;
@@ -1079,7 +1032,7 @@ private:
assert(this->m_consumed);
this->built();
return m_src.build(
- [f = std::move(chain), cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask)
+ [f = std::move(chain), cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t &offset, input_t data, std::make_unsigned_t<input_t> &mem_mask)
{
auto const trans(devcb_write::invoke_transform<input_t, output_t>(cb, offset, data, mem_mask));
output_t out_mask(mem_mask & mask);
@@ -1123,7 +1076,7 @@ private:
}
~first_transform_builder() { this->template register_creator<first_transform_builder>(); }
- void validity_check(validity_checker &valid) const { m_sink.validity_check(valid); }
+ bool validity_check(validity_checker &valid) const { return m_sink.validity_check(valid); }
template <typename T>
std::enable_if_t<is_transform<output_t, output_t, T>::value, transform_builder<first_transform_builder, std::remove_reference_t<T> > > transform(T &&cb)
@@ -1139,7 +1092,7 @@ private:
assert(this->m_consumed);
this->built();
return
- [sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{
data = (data ^ in_exor) & in_mask;
mem_mask &= in_mask;
@@ -1160,7 +1113,7 @@ private:
assert(this->m_consumed);
this->built();
return
- [f = std::move(chain), sink = m_sink.build(), cb = std::move(this->m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [f = std::move(chain), sink = m_sink.build(), cb = std::move(m_cb), in_exor = m_in_exor, in_mask = m_in_mask, exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{
data = (data ^ in_exor) & in_mask;
mem_mask &= in_mask;
@@ -1190,14 +1143,14 @@ private:
wrapped_builder(functoid_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); }
wrapped_builder(wrapped_builder &&that) : builder_base(std::move(that)), m_cb(std::move(that.m_cb)) { that.consume(); that.built(); }
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
assert(this->m_consumed);
this->built();
return
- [cb = std::move(this->m_cb)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [cb = std::move(m_cb)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{ devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); };
}
@@ -1240,14 +1193,14 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
assert(this->m_consumed);
this->built();
return
- [cb = std::move(this->m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [cb = std::move(m_cb), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{ devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); };
}
};
@@ -1278,11 +1231,15 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
auto const target(m_delegate.finder_target());
if (target.second && !target.first.subdevice(target.second))
+ {
osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name());
+ return false;
+ }
+ return true;
}
auto build()
@@ -1291,7 +1248,7 @@ private:
this->built();
m_delegate.resolve();
return
- [cb = std::move(this->m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [cb = std::move(m_delegate)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{ devcb_write::invoke_write<Input>(cb, offset, data, mem_mask); };
}
@@ -1344,11 +1301,15 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), in_mask, out_mask);
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
auto const target(m_delegate.finder_target());
if (target.second && !target.first.subdevice(target.second))
+ {
osd_printf_error("Write callback bound to non-existent object tag %s (%s)\n", target.first.subtag(target.second), m_delegate.name());
+ return false;
+ }
+ return true;
}
auto build()
@@ -1357,7 +1318,7 @@ private:
this->built();
m_delegate.resolve();
return
- [cb = std::move(this->m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
+ [cb = std::move(m_delegate), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
{ devcb_write::invoke_write<Input>(cb, offset, (data ^ exor) & mask, mem_mask & mask); };
}
};
@@ -1393,16 +1354,23 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
if (!m_exec)
{
device_t *const device(m_devbase.subdevice(m_tag));
if (!device)
+ {
osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ return false;
+ }
else if (!dynamic_cast<device_execute_interface *>(device))
+ {
osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ return false;
+ }
}
+ return true;
}
auto build()
@@ -1484,16 +1452,23 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), in_mask, 1U);
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
if (!m_exec)
{
device_t *const device(m_devbase.subdevice(m_tag));
if (!device)
+ {
osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ return false;
+ }
else if (!dynamic_cast<device_execute_interface *>(device))
+ {
osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ return false;
+ }
}
+ return true;
}
auto build()
@@ -1548,16 +1523,23 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
if (!m_exec)
{
device_t *const device(m_devbase.subdevice(m_tag));
if (!device)
+ {
osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ return false;
+ }
else if (!dynamic_cast<device_execute_interface *>(device))
+ {
osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ return false;
+ }
}
+ return true;
}
auto build()
@@ -1643,16 +1625,23 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
}
- void validity_check(validity_checker &valid) const
+ bool validity_check(validity_checker &valid) const
{
if (!m_exec)
{
device_t *const device(m_devbase.subdevice(m_tag));
if (!device)
+ {
osd_printf_error("Write callback bound to non-existent object tag %s\n", m_tag);
+ return false;
+ }
else if (!dynamic_cast<device_execute_interface *>(device))
+ {
osd_printf_error("Write callback bound to device %s (%s) that does not implement device_execute_interface\n", device->tag(), device->name());
+ return false;
+ }
}
+ return true;
}
auto build()
@@ -1701,7 +1690,7 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1759,7 +1748,7 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1801,7 +1790,7 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1859,7 +1848,7 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1901,7 +1890,7 @@ private:
that.built();
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1956,7 +1945,7 @@ private:
return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
}
- void validity_check(validity_checker &valid) const { }
+ bool validity_check(validity_checker &valid) const { return true; }
auto build()
{
@@ -1968,99 +1957,6 @@ private:
}
};
- class log_builder : public builder_base, public transform_base<std::make_unsigned_t<Input>, log_builder>
- {
- private:
- class wrapped_builder : public builder_base
- {
- public:
- template <typename T, typename U> friend class first_transform_builder;
-
- using input_t = Input;
-
- wrapped_builder(log_builder &&that)
- : builder_base(std::move(that))
- , m_devbase(that.m_devbase)
- , m_message(std::move(that.m_message))
- {
- that.consume();
- that.built();
- }
- wrapped_builder(wrapped_builder &&that)
- : builder_base(std::move(that))
- , m_devbase(that.m_devbase)
- , m_message(std::move(that.m_message))
- {
- that.consume();
- that.built();
- }
-
- void validity_check(validity_checker &valid) const { }
-
- auto build()
- {
- assert(this->m_consumed);
- this->built();
- return
- [&devbase = m_devbase, message = std::move(m_message)] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
- { if (data) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); };
- }
-
- private:
- wrapped_builder(wrapped_builder const &) = delete;
- wrapped_builder operator=(wrapped_builder const &) = delete;
- wrapped_builder operator=(wrapped_builder &&that) = delete;
-
- device_t &m_devbase;
- std::string m_message;
- };
-
- friend class wrapped_builder; // workaround for MSVC
-
- log_builder(log_builder const &) = delete;
- log_builder &operator=(log_builder const &) = delete;
- log_builder &operator=(log_builder &&that) = delete;
-
- device_t &m_devbase;
- std::string m_message;
-
- public:
- using input_t = Input;
-
- log_builder(devcb_write &target, bool append, device_t &devbase, std::string &&message)
- : builder_base(target, append)
- , transform_base<std::make_unsigned_t<Input>, log_builder>(DefaultMask)
- , m_devbase(devbase)
- , m_message(std::move(message))
- { }
- log_builder(log_builder &&that)
- : builder_base(std::move(that))
- , transform_base<std::make_unsigned_t<Input>, log_builder>(std::move(that))
- , m_devbase(that.m_devbase)
- , m_message(std::move(that.m_message))
- {
- that.consume();
- that.built();
- }
- ~log_builder() { this->template register_creator<log_builder>(); }
-
- template <typename T>
- std::enable_if_t<is_transform<input_t, input_t, T>::value, first_transform_builder<wrapped_builder, std::remove_reference_t<T> > > transform(T &&cb)
- {
- return first_transform_builder<wrapped_builder, std::remove_reference_t<T> >(this->m_target, this->m_append, wrapped_builder(std::move(*this)), std::forward<T>(cb), this->exor(), this->mask(), DefaultMask);
- }
-
- void validity_check(validity_checker &valid) const { }
-
- auto build()
- {
- assert(this->m_consumed);
- this->built();
- return
- [&devbase = m_devbase, message = std::move(m_message), exor = this->exor(), mask = this->mask()] (offs_t offset, input_t data, std::make_unsigned_t<input_t> mem_mask)
- { if ((data ^ exor) & mask) devbase.logerror("%s: %s\n", devbase.machine().describe_context(), message); };
- }
- };
class binder
{
public:
@@ -2098,6 +1994,13 @@ private:
return delegate_builder<delegate_type_t<T> >(m_target, m_append, m_target.owner(), devcb_write::cast_reference<delegate_device_class_t<T> >(obj), std::forward<T>(func), name);
}
+ template <typename T>
+ std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_t &devbase, char const *tag, T &&func, char const *name)
+ {
+ set_used();
+ return delegate_builder<delegate_type_t<T> >(m_target, m_append, devbase, tag, std::forward<T>(func), name);
+ }
+
template <typename T, typename U, bool R>
std::enable_if_t<is_write_method<T>::value, delegate_builder<delegate_type_t<T> > > set(device_finder<U, R> &finder, T &&func, char const *name)
{
@@ -2242,38 +2145,6 @@ private:
return set_output(std::forward<Params>(args)...);
}
- template <typename... Params>
- log_builder set_log(device_t &devbase, Params &&... args)
- {
- set_used();
- return log_builder(m_target, m_append, devbase, std::string(std::forward<Params>(args)...));
- }
-
- template <typename T, typename... Params>
- std::enable_if_t<emu::detail::is_device_implementation<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args)
- {
- return set_log(static_cast<device_t &>(devbase), std::forward<Params>(args)...);
- }
-
- template <typename T, typename... Params>
- std::enable_if_t<emu::detail::is_device_interface<std::remove_reference_t<T> >::value, log_builder> set_log(T &devbase, Params &&... args)
- {
- return set_log(devbase.device(), std::forward<Params>(args)...);
- }
-
- template <typename... Params>
- log_builder set_log(Params &&... args)
- {
- return set_log(m_target.owner().mconfig().current_device(), std::forward<Params>(args)...);
- }
-
- template <typename... Params>
- log_builder append_log(Params &&... args)
- {
- m_append = true;
- return set_log(std::forward<Params>(args)...);
- }
-
void set_nop()
{
set_used();
@@ -2291,18 +2162,20 @@ private:
std::vector<func_t> m_functions;
std::vector<typename creator::ptr> m_creators;
+ bool m_unset = false;
+
+protected:
+ virtual bool findit(validity_checker *valid) override;
+ virtual void end_configuration() override;
public:
template <unsigned Count>
class array : public devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>
{
public:
- using devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array;
-
- void resolve_all_safe()
+ array(device_t &owner)
+ : devcb_write_base::array<devcb_write<Input, DefaultMask>, Count>::array(owner)
{
- for (devcb_write<Input, DefaultMask> &elem : *this)
- elem.resolve_safe();
}
};
@@ -2311,16 +2184,10 @@ public:
binder bind();
void reset();
- virtual void validity_check(validity_checker &valid) const override;
-
- void resolve();
- void resolve_safe();
-
void operator()(offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask = DefaultMask);
void operator()(Input data);
- bool isnull() const { return m_functions.empty() && m_creators.empty(); }
- explicit operator bool() const { return !m_functions.empty(); }
+ bool isunset() const noexcept { return m_unset || (m_functions.empty() && m_creators.empty()); }
};
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
@@ -2332,6 +2199,7 @@ devcb_write<Input, DefaultMask>::devcb_write(device_t &owner)
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
typename devcb_write<Input, DefaultMask>::binder devcb_write<Input, DefaultMask>::bind()
{
+ assert(m_functions.empty());
return binder(*this);
}
@@ -2343,29 +2211,38 @@ void devcb_write<Input, DefaultMask>::reset()
}
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
-void devcb_write<Input, DefaultMask>::validity_check(validity_checker &valid) const
-{
- assert(m_functions.empty());
- for (typename creator::ptr const &c : m_creators)
- c->validity_check(valid);
-}
-
-template <typename Input, std::make_unsigned_t<Input> DefaultMask>
-void devcb_write<Input, DefaultMask>::resolve()
+bool devcb_write<Input, DefaultMask>::findit(validity_checker *valid)
{
assert(m_functions.empty());
- m_functions.reserve(m_creators.size());
- for (typename creator::ptr const &c : m_creators)
- m_functions.emplace_back(c->create());
- m_creators.clear();
+ if (!valid)
+ {
+ // FIXME: report errors by returning false rather than throwing fatal errors
+ m_functions.reserve(m_creators.size());
+ for (typename creator::ptr const &c : m_creators)
+ m_functions.emplace_back(c->create());
+ m_creators.clear();
+ if (m_functions.empty())
+ {
+ m_functions.emplace_back([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { });
+ m_unset = true;
+ }
+ return true;
+ }
+ else
+ {
+ bool success(true);
+ for (typename creator::ptr const &c : m_creators)
+ {
+ if (!c->validity_check(*valid))
+ success = false;
+ }
+ return success;
+ }
}
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
-void devcb_write<Input, DefaultMask>::resolve_safe()
+void devcb_write<Input, DefaultMask>::end_configuration()
{
- resolve();
- if (m_functions.empty())
- m_functions.emplace_back([] (offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { });
}
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
@@ -2646,7 +2523,6 @@ extern template class devcb_write8::creator_impl<devcb_write8::latched_inputline
extern template class devcb_write8::creator_impl<devcb_write8::ioport_builder>;
extern template class devcb_write8::creator_impl<devcb_write8::membank_builder>;
extern template class devcb_write8::creator_impl<devcb_write8::output_builder>;
-extern template class devcb_write8::creator_impl<devcb_write8::log_builder>;
extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write8s_delegate> >;
extern template class devcb_write16::creator_impl<devcb_write16::delegate_builder<write16s_delegate> >;
@@ -2666,7 +2542,6 @@ extern template class devcb_write16::creator_impl<devcb_write16::latched_inputli
extern template class devcb_write16::creator_impl<devcb_write16::ioport_builder>;
extern template class devcb_write16::creator_impl<devcb_write16::membank_builder>;
extern template class devcb_write16::creator_impl<devcb_write16::output_builder>;
-extern template class devcb_write16::creator_impl<devcb_write16::log_builder>;
extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write8s_delegate> >;
extern template class devcb_write32::creator_impl<devcb_write32::delegate_builder<write16s_delegate> >;
@@ -2686,7 +2561,6 @@ extern template class devcb_write32::creator_impl<devcb_write32::latched_inputli
extern template class devcb_write32::creator_impl<devcb_write32::ioport_builder>;
extern template class devcb_write32::creator_impl<devcb_write32::membank_builder>;
extern template class devcb_write32::creator_impl<devcb_write32::output_builder>;
-extern template class devcb_write32::creator_impl<devcb_write32::log_builder>;
extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write8s_delegate> >;
extern template class devcb_write64::creator_impl<devcb_write64::delegate_builder<write16s_delegate> >;
@@ -2706,7 +2580,6 @@ extern template class devcb_write64::creator_impl<devcb_write64::latched_inputli
extern template class devcb_write64::creator_impl<devcb_write64::ioport_builder>;
extern template class devcb_write64::creator_impl<devcb_write64::membank_builder>;
extern template class devcb_write64::creator_impl<devcb_write64::output_builder>;
-extern template class devcb_write64::creator_impl<devcb_write64::log_builder>;
extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write8s_delegate> >;
extern template class devcb_write_line::creator_impl<devcb_write_line::delegate_builder<write16s_delegate> >;
@@ -2726,6 +2599,5 @@ extern template class devcb_write_line::creator_impl<devcb_write_line::latched_i
extern template class devcb_write_line::creator_impl<devcb_write_line::ioport_builder>;
extern template class devcb_write_line::creator_impl<devcb_write_line::membank_builder>;
extern template class devcb_write_line::creator_impl<devcb_write_line::output_builder>;
-extern template class devcb_write_line::creator_impl<devcb_write_line::log_builder>;
#endif // MAME_EMU_DEVCB_H
diff --git a/src/emu/devcpu.cpp b/src/emu/devcpu.cpp
index 03df7990a3d..efd12d682a9 100644
--- a/src/emu/devcpu.cpp
+++ b/src/emu/devcpu.cpp
@@ -27,7 +27,9 @@ cpu_device::cpu_device(const machine_config &mconfig, device_type type, const ch
device_memory_interface(mconfig, *this),
device_state_interface(mconfig, *this),
device_disasm_interface(mconfig, *this),
- m_force_no_drc(false)
+ m_force_no_drc(false),
+ m_access_to_be_redone(false),
+ m_access_before_delay_tag(nullptr)
{
}
@@ -49,3 +51,55 @@ bool cpu_device::allow_drc() const
{
return mconfig().options().drc() && !m_force_no_drc;
}
+
+
+
+bool cpu_device::cpu_is_interruptible() const
+{
+ return false;
+}
+
+bool cpu_device::access_before_time(u64 access_time, u64 current_time) noexcept
+{
+ s32 delta = access_time - current_time;
+ if(*m_icountptr <= delta) {
+ if(*m_icountptr > 0)
+ *m_icountptr = 0;
+ m_access_to_be_redone = true;
+ return true;
+ }
+
+ *m_icountptr -= delta;
+
+ return false;
+}
+
+bool cpu_device::access_before_delay(u32 cycles, const void *tag) noexcept
+{
+ if(tag == m_access_before_delay_tag) {
+ m_access_before_delay_tag = nullptr;
+ return false;
+ }
+
+ *m_icountptr -= cycles;
+
+ if(*m_icountptr <= 0) {
+ m_access_before_delay_tag = tag;
+ m_access_to_be_redone = true;
+ return true;
+ }
+
+ m_access_before_delay_tag = nullptr;
+ return false;
+}
+
+void cpu_device::access_after_delay(u32 cycles) noexcept
+{
+ *m_icountptr -= cycles;
+}
+
+void cpu_device::defer_access() noexcept
+{
+ m_access_to_be_redone = true;
+ *m_icountptr = 0;
+}
diff --git a/src/emu/devcpu.h b/src/emu/devcpu.h
index 6e9251ab3a9..70f7b1667a5 100644
--- a/src/emu/devcpu.h
+++ b/src/emu/devcpu.h
@@ -16,6 +16,8 @@
#include "didisasm.h"
#include "diexec.h"
+#include <utility>
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -36,6 +38,20 @@ public:
void set_force_no_drc(bool value) { m_force_no_drc = value; }
bool allow_drc() const;
+ virtual bool cpu_is_interruptible() const;
+
+ // To be used only for interruptible cpus
+ bool access_to_be_redone() noexcept { return std::exchange(m_access_to_be_redone, false); }
+ bool access_to_be_redone_noclear() noexcept { return m_access_to_be_redone; }
+
+ // Returns true if the access must be aborted
+ bool access_before_time(u64 access_time, u64 current_time) noexcept;
+ bool access_before_delay(u32 cycles, const void *tag) noexcept;
+
+ // The access has already happened, nothing to abort
+ void access_after_delay(u32 cycles) noexcept;
+ void defer_access() noexcept;
+
protected:
// construction/destruction
cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
@@ -43,6 +59,9 @@ protected:
private:
// configured state
bool m_force_no_drc; // whether or not to force DRC off
+
+ bool m_access_to_be_redone; // whether an access needs to be redone
+ const void *m_access_before_delay_tag; // if the tag matches on access_before_delay, consider the delay to have already happened
};
#endif // MAME_EMU_DEVCPU_H
diff --git a/src/emu/devdelegate.h b/src/emu/devdelegate.h
index 69381b2576b..3a63c874d92 100644
--- a/src/emu/devdelegate.h
+++ b/src/emu/devdelegate.h
@@ -21,6 +21,14 @@
#include <utility>
+// older versions of libc++ are missing deduction guides that the things using this constructor require
+#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 10000)
+namespace std { inline namespace __1 {
+template<class R, class... ArgTypes > function( R(*)(ArgTypes...) ) -> function<R(ArgTypes...)>;
+} }
+#endif
+
+
namespace emu {
//**************************************************************************
@@ -35,41 +43,6 @@ template <typename Signature, unsigned Count> class device_delegate_array;
// TYPE DEFINITIONS
//**************************************************************************
-namespace detail {
-
-// ======================> device_delegate_helper
-
-// device_delegate_helper does non-template work
-class device_delegate_helper
-{
-public:
- // accessors
- char const *finder_tag() const { return m_tag; }
- std::pair<device_t &, char const *> finder_target() const { return std::make_pair(m_base, m_tag); }
-
-protected:
- // construct/assign
- device_delegate_helper(device_t &owner, char const *tag = nullptr) : m_base(owner), m_tag(tag) { }
- template <class DeviceClass, bool Required> device_delegate_helper(device_finder<DeviceClass, Required> const &finder);
- device_delegate_helper(device_delegate_helper const &) = default;
- device_delegate_helper &operator=(device_delegate_helper const &) = default;
-
- // internal helpers
- delegate_late_bind &bound_object() const;
- void set_tag(device_t &object) { m_base = object; m_tag = nullptr; }
- void set_tag(device_t &base, char const *tag) { m_base = base; m_tag = tag; }
- void set_tag(char const *tag);
- template <class DeviceClass, bool Required> void set_tag(device_finder<DeviceClass, Required> const &finder);
-
-private:
- std::reference_wrapper<device_t> m_base;
- char const *m_tag;
-};
-
-} // namespace detail
-
-
-// ======================> named_delegate
template <typename Signature>
class named_delegate : public delegate<Signature>
{
@@ -96,8 +69,8 @@ public:
template <typename T> named_delegate(T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name) : basetype(std::forward<T>(funcptr)), m_name(name) { }
// allow assignment
- named_delegate &operator=(named_delegate const &src) = default;
- named_delegate &operator=(named_delegate &&src) = default;
+ named_delegate &operator=(named_delegate const &) = default;
+ named_delegate &operator=(named_delegate &&) = default;
named_delegate &operator=(std::nullptr_t) noexcept { reset(); return *this; }
// getters
@@ -107,14 +80,53 @@ public:
void reset() noexcept { basetype::reset(); m_name = nullptr; }
};
-// ======================> device_delegate
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (FunctionClass::*)(Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
-// device_delegate is a delegate that wraps with a device tag and can be easily
-// late bound without replicating logic everywhere
-template <typename Signature> class device_delegate;
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (FunctionClass::*)(Params...) const, char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
+
+template <class FunctionClass, typename ReturnType, typename... Params>
+named_delegate(ReturnType (*)(FunctionClass &, Params...), char const *, FunctionClass *) -> named_delegate<ReturnType (Params...)>;
+
+
+namespace detail {
+
+// device_delegate_helper does non-template work
+
+class device_delegate_helper
+{
+public:
+ // accessors
+ char const *finder_tag() const { return m_tag; }
+ std::pair<device_t &, char const *> finder_target() const { return std::make_pair(m_base, m_tag); }
+
+protected:
+ // construct/assign
+ device_delegate_helper(device_t &owner, char const *tag = nullptr) : m_base(owner), m_tag(tag) { }
+ template <class DeviceClass, bool Required> device_delegate_helper(device_finder<DeviceClass, Required> const &finder);
+ device_delegate_helper(device_delegate_helper const &) = default;
+ device_delegate_helper &operator=(device_delegate_helper const &) = default;
+
+ // internal helpers
+ delegate_late_bind &bound_object() const;
+ void set_tag(device_t &object) { m_base = object; m_tag = nullptr; }
+ void set_tag(device_t &base, char const *tag) { m_base = base; m_tag = tag; }
+ void set_tag(char const *tag);
+ template <class DeviceClass, bool Required> void set_tag(device_finder<DeviceClass, Required> const &finder);
+
+private:
+ std::reference_wrapper<device_t> m_base;
+ char const *m_tag;
+};
+
+
+// device_delegate_base doesn't need to be specialised on return type
+
+template <typename Signature> class device_delegate_base;
template <typename ReturnType, typename... Params>
-class device_delegate<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public detail::device_delegate_helper
+class device_delegate_base<ReturnType (Params...)> : protected named_delegate<ReturnType (Params...)>, public device_delegate_helper
{
private:
using basetype = named_delegate<ReturnType (Params...)>;
@@ -133,77 +145,72 @@ private:
template <class T> static std::enable_if_t<is_related_device_interface<T, T>::value, device_t &> get_device(T &object) { return object.device(); }
public:
- template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>;
-
- template <typename T>
- using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
-
// construct/assign
- explicit device_delegate(device_t &owner) : basetype(), detail::device_delegate_helper(owner) { }
- device_delegate(device_delegate const &) = default;
- device_delegate &operator=(device_delegate const &) = default;
+ explicit device_delegate_base(device_t &owner) : basetype(), device_delegate_helper(owner) { }
+ device_delegate_base(device_delegate_base const &) = default;
+ device_delegate_base &operator=(device_delegate_base const &) = default;
// construct with prototype and target
- device_delegate(basetype const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { }
- device_delegate(device_delegate const &proto, device_t &object) : basetype(proto, object), detail::device_delegate_helper(object) { }
+ device_delegate_base(basetype const &proto, device_t &object) : basetype(proto, object), device_delegate_helper(object) { }
+ device_delegate_base(device_delegate_base const &proto, device_t &object) : basetype(proto, object), device_delegate_helper(object) { }
// construct with base and tag
template <class D>
- device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name)
+ device_delegate_base(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...), char const *name)
: basetype(funcptr, name, static_cast<D *>(nullptr))
- , detail::device_delegate_helper(base, tag)
+ , device_delegate_helper(base, tag)
{ }
template <class D>
- device_delegate(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name)
+ device_delegate_base(device_t &base, char const *tag, ReturnType (D::*funcptr)(Params...) const, char const *name)
: basetype(funcptr, name, static_cast<D *>(nullptr))
- , detail::device_delegate_helper(base, tag)
+ , device_delegate_helper(base, tag)
{ }
template <class D>
- device_delegate(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name)
+ device_delegate_base(device_t &base, char const *tag, ReturnType (*funcptr)(D &, Params...), char const *name)
: basetype(funcptr, name, static_cast<D *>(nullptr))
- , detail::device_delegate_helper(base, tag)
+ , device_delegate_helper(base, tag)
{ }
// construct with device finder
template <class D, bool R, class E>
- device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...), char const *name)
+ device_delegate_base(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...), char const *name)
: basetype(funcptr, name, static_cast<E *>(nullptr))
- , detail::device_delegate_helper(finder)
+ , device_delegate_helper(finder)
{ }
template <class D, bool R, class E>
- device_delegate(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name)
+ device_delegate_base(device_finder<D, R> const &finder, ReturnType (E::*funcptr)(Params...) const, char const *name)
: basetype(funcptr, name, static_cast<E *>(nullptr))
- , detail::device_delegate_helper(finder)
+ , device_delegate_helper(finder)
{ }
template <class D, bool R, class E>
- device_delegate(device_finder<D, R> const &finder, ReturnType (*funcptr)(E &, Params...), char const *name)
+ device_delegate_base(device_finder<D, R> const &finder, ReturnType (*funcptr)(E &, Params...), char const *name)
: basetype(funcptr, name, static_cast<E *>(nullptr))
- , detail::device_delegate_helper(finder)
+ , device_delegate_helper(finder)
{ }
// construct with target object
template <class T, class D>
- device_delegate(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name)
+ device_delegate_base(T &object, ReturnType (D::*funcptr)(Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name)
: basetype(funcptr, name, static_cast<D *>(&object))
- , detail::device_delegate_helper(get_device(object))
+ , device_delegate_helper(get_device(object))
{ }
template <class T, class D>
- device_delegate(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t<is_related_device<D, T>::value, char const *> name)
+ device_delegate_base(T &object, ReturnType (D::*funcptr)(Params...) const, std::enable_if_t<is_related_device<D, T>::value, char const *> name)
: basetype(funcptr, name, static_cast<D *>(&object))
- , detail::device_delegate_helper(get_device(object))
+ , device_delegate_helper(get_device(object))
{ }
template <class T, class D>
- device_delegate(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name)
+ device_delegate_base(T &object, ReturnType (*funcptr)(D &, Params...), std::enable_if_t<is_related_device<D, T>::value, char const *> name)
: basetype(funcptr, name, static_cast<D *>(&object))
- , detail::device_delegate_helper(get_device(object))
+ , device_delegate_helper(get_device(object))
{ }
// construct with callable object
template <typename T>
- device_delegate(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name)
+ device_delegate_base(device_t &owner, T &&funcptr, std::enable_if_t<suitable_functoid<T>::value, char const *> name)
: basetype(std::forward<T>(funcptr), name)
- , detail::device_delegate_helper(owner)
- { basetype::operator=(basetype(std::forward<T>(funcptr), name)); }
+ , device_delegate_helper(owner)
+ { }
// setters that implicitly bind to the current device
template <class D> void set(ReturnType (D::*funcptr)(Params...), char const *name)
@@ -239,18 +246,117 @@ public:
void reset()
{ basetype::reset(); set_tag(finder_target().first); }
- // perform the binding
- void resolve() { if (!basetype::isnull() && !basetype::has_object()) basetype::late_bind(bound_object()); }
-
// accessors
using basetype::operator();
using basetype::isnull;
using basetype::has_object;
using basetype::name;
+
+ // perform the binding
+ void resolve()
+ {
+ if (!this->isnull() && !this->has_object())
+ this->late_bind(bound_object());
+ }
+};
+
+} // namespace detail
+
+
+// device_delegate is a delegate that can be late bound to a device specification
+
+template <typename Signature> class device_delegate;
+
+template <typename ReturnType, typename... Params>
+class device_delegate<ReturnType (Params...)> : protected detail::device_delegate_base<ReturnType (Params...)>
+{
+public:
+ template <unsigned Count> using array = device_delegate_array<ReturnType (Params...), Count>;
+
+ template <typename T>
+ using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
+
+ // constructors
+ using detail::device_delegate_base<ReturnType (Params...)>::device_delegate_base;
+ device_delegate(device_delegate const &) = default;
+ device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<ReturnType (Params...)>(proto, object) { }
+
+ // assignment
+ device_delegate &operator=(device_delegate const &) = default;
+ device_delegate &operator=(std::nullptr_t) { this->reset(); }
+
+ // setters/unsetters
+ void set(device_delegate const &src) { operator=(src); }
+ using detail::device_delegate_base<ReturnType (Params...)>::set;
+ using detail::device_delegate_base<ReturnType (Params...)>::reset;
+
+ // accessors
+ using detail::device_delegate_base<ReturnType (Params...)>::operator();
+ using detail::device_delegate_base<ReturnType (Params...)>::isnull;
+ using detail::device_delegate_base<ReturnType (Params...)>::has_object;
+ using detail::device_delegate_base<ReturnType (Params...)>::name;
+ using detail::device_delegate_base<ReturnType (Params...)>::finder_tag;
+ using detail::device_delegate_base<ReturnType (Params...)>::finder_target;
+
+ // perform the binding
+ using detail::device_delegate_base<ReturnType (Params...)>::resolve;
+
+ template <typename T>
+ void resolve_safe(T &&dflt)
+ {
+ if (this->isnull())
+ this->set([result = std::decay_t<T>(std::forward<T>(dflt))] (Params...) { return ReturnType(result); }, "default");
+ else if (!this->has_object())
+ this->late_bind(this->bound_object());
+ }
+};
+
+template <typename... Params>
+class device_delegate<void (Params...)> : protected detail::device_delegate_base<void (Params...)>
+{
+public:
+ template <unsigned Count> using array = device_delegate_array<void (Params...), Count>;
+
+ template <typename T>
+ using supports_callback = std::bool_constant<std::is_constructible_v<device_delegate, device_t &, char const *, T, char const *> >;
+
+ // constructors
+ using detail::device_delegate_base<void (Params...)>::device_delegate_base;
+ device_delegate(device_delegate const &) = default;
+ device_delegate(device_delegate const &proto, device_t &object) : detail::device_delegate_base<void (Params...)>(proto, object) { }
+
+ // assignment
+ device_delegate &operator=(device_delegate const &) = default;
+ device_delegate &operator=(std::nullptr_t) { this->reset(); }
+
+ // setters/unsetters
+ void set(device_delegate const &src) { operator=(src); }
+ using detail::device_delegate_base<void (Params...)>::set;
+ using detail::device_delegate_base<void (Params...)>::reset;
+
+ // accessors
+ using detail::device_delegate_base<void (Params...)>::operator();
+ using detail::device_delegate_base<void (Params...)>::isnull;
+ using detail::device_delegate_base<void (Params...)>::has_object;
+ using detail::device_delegate_base<void (Params...)>::name;
+ using detail::device_delegate_base<void (Params...)>::finder_tag;
+ using detail::device_delegate_base<void (Params...)>::finder_target;
+
+ // perform the binding
+ using detail::device_delegate_base<void (Params...)>::resolve;
+
+ void resolve_safe()
+ {
+ if (this->isnull())
+ this->set([] (Params...) { }, "default");
+ else if (!this->has_object())
+ this->late_bind(this->bound_object());
+ }
};
// simplifies constructing an array of delegates with a single owner
+
template <typename Signature, unsigned Count>
class device_delegate_array : public std::array<device_delegate<Signature>, Count>
{
@@ -280,8 +386,42 @@ public:
for (device_delegate<Signature> &elem : *this)
elem.resolve();
}
+
+ template <typename... T>
+ void resolve_all_safe(T &&... args)
+ {
+ for (device_delegate<Signature> &elem : *this)
+ elem.resolve_safe(args...);
+ }
};
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, typename ReturnType, typename... Params>
+device_delegate(device_t &, char const *, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (E::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class D, bool R, class E, typename ReturnType, typename... Params>
+device_delegate(device_finder<D, R> const &, ReturnType (*)(E &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (D::*)(Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (D::*)(Params...) const, char const *) -> device_delegate<ReturnType (Params...)>;
+
+template <class T, class D, typename ReturnType, typename... Params>
+device_delegate(T &, ReturnType (*)(D &, Params...), char const *) -> device_delegate<ReturnType (Params...)>;
+
} // namespace emu
diff --git a/src/emu/devfind.cpp b/src/emu/devfind.cpp
index d6bc984703e..6170b2fca8c 100644
--- a/src/emu/devfind.cpp
+++ b/src/emu/devfind.cpp
@@ -18,27 +18,42 @@
// BASE FINDER CLASS
//**************************************************************************
-constexpr char finder_base::DUMMY_TAG[];
+//-------------------------------------------------
+// device_resolver_base - constructor
+//-------------------------------------------------
+
+device_resolver_base::device_resolver_base(device_t &base)
+ : m_next(base.register_auto_finder(*this))
+{
+}
//-------------------------------------------------
-// finder_base - constructor
+// ~device_resolver_base - destructor
//-------------------------------------------------
-finder_base::finder_base(device_t &base, char const *tag)
- : m_next(base.register_auto_finder(*this))
- , m_base(base)
- , m_tag(tag)
- , m_resolved(false)
+device_resolver_base::~device_resolver_base()
{
}
+
+//**************************************************************************
+// BASE FINDER CLASS
+//**************************************************************************
+
+constexpr char finder_base::DUMMY_TAG[];
+
+
//-------------------------------------------------
-// ~finder_base - destructor
+// finder_base - constructor
//-------------------------------------------------
-finder_base::~finder_base()
+finder_base::finder_base(device_t &base, char const *tag)
+ : device_resolver_base(base)
+ , m_base(base)
+ , m_tag(tag)
+ , m_resolved(false)
{
}
@@ -50,6 +65,7 @@ finder_base::~finder_base()
void finder_base::set_tag(char const *tag)
{
assert(!m_resolved);
+ assert(tag);
m_base = m_base.get().mconfig().current_device();
m_tag = tag;
}
diff --git a/src/emu/devfind.h b/src/emu/devfind.h
index c8884d9582f..81ebb9f9812 100644
--- a/src/emu/devfind.h
+++ b/src/emu/devfind.h
@@ -216,21 +216,21 @@ public:
/// Abstract non-template base class for object auto-discovery helpers.
/// Provides the interface that the device_t uses to manage discovery at
/// resolution time.
-class finder_base
+class device_resolver_base
{
public:
/// \brief Destructor
///
/// Destruction via base class pointer and dynamic type behaviour
/// are allowed.
- virtual ~finder_base();
+ virtual ~device_resolver_base();
/// \brief Get next registered object discovery helper
///
/// Implementation of basic single-linked list behaviour.
/// \return Pointer to the next registered object discovery helper,
/// or nullptr if this is the last.
- finder_base *next() const { return m_next; }
+ device_resolver_base *next() const noexcept { return m_next; }
/// \brief Attempt discovery
///
@@ -254,6 +254,32 @@ public:
/// subsequently removes or replaces devices.
virtual void end_configuration() = 0;
+protected:
+ /// \brief Designated constructor
+ ///
+ /// Construct base object discovery helper and register with device
+ /// to be invoked at resolution time.
+ /// \param [in] base Device to register with for resolution.
+ device_resolver_base(device_t &base);
+
+
+ /// \brief Pointer to next registered discovery helper
+ ///
+ /// This is a polymorphic class, so it can't be held in a standard
+ /// list container that requires elements of the same type. Hence
+ /// it implements basic intrusive single-linked list behaviour.
+ device_resolver_base *const m_next;
+};
+
+
+/// \brief Base class for object discovery helpers
+///
+/// Abstract non-template base class for object auto-discovery helpers.
+/// Provides functionality for specifying a target as a base device and
+/// relative tag. Also supplies helpers for looking up resources.
+class finder_base : protected device_resolver_base
+{
+public:
/// \brief Get search tag
///
/// Returns the search tag.
@@ -280,6 +306,7 @@ public:
void set_tag(device_t &base, char const *tag)
{
assert(!m_resolved);
+ assert(tag);
m_base = base;
m_tag = tag;
}
@@ -315,7 +342,9 @@ protected:
///
/// Construct base object discovery helper and register with device
/// to be invoked at resolution time.
- /// \param [in] base Base device to search from.
+ /// \param [in] base Device to register with for resolution. Also
+ /// sets initial base device to search from. The tag must be
+ /// specified relative to this device.
/// \param [in] tag Object tag to search for. This is not copied,
/// it is the caller's responsibility to ensure this pointer
/// remains valid until resolution time.
@@ -419,13 +448,6 @@ protected:
bool report_missing(bool found, char const *objname, bool required) const;
- /// \brief Pointer to next registered discovery helper
- ///
- /// This is a polymorphic class, so it can't be held in a standard
- /// list container that requires elements of the same type. Hence
- /// it implements basic intrusive single-linked list behaviour.
- finder_base *const m_next;
-
/// \brief Base device to search from
std::reference_wrapper<device_t> m_base;
@@ -600,6 +622,12 @@ public:
return device;
}
+ /// \brief Look up target during configuration
+ /// Look up the current target device during configuration, before
+ /// resolution.
+ /// \return Pointer to target device if found, or nullptr otherwise.
+ DeviceClass *lookup() const { return this->m_base.get().template subdevice<DeviceClass>(this->m_tag); }
+
private:
/// \brief Check that device implementation has expected tag
/// \param [in] device Reference to device.
@@ -1186,6 +1214,33 @@ public:
/// been found.
size_t bytes() const { return m_bytes; }
+ /// \brief Get iterator to first element
+ ///
+ /// Returns an iterator to the first element of the memory share.
+ /// \return Iterator to first element.
+ PointerType *begin() const { return this->m_target; }
+
+ /// \brief Get iterator beyond last element
+ ///
+ /// Returns an iterator one past the last element of the memory
+ /// share.
+ /// \return Iterator one past last element.
+ PointerType *end() const { return this->m_target + length(); }
+
+ /// \brief Get constant iterator to first element
+ ///
+ /// Returns a constant iterator to the first element of the memory
+ /// share.
+ /// \return Constant iterator to first element.
+ PointerType const *cbegin() const { return this->m_target; }
+
+ /// \brief Get constant iterator beyond last element
+ ///
+ /// Returns a constant iterator one past the last element of the
+ /// memory share.
+ /// \return Constant iterator one past last element.
+ PointerType const *cend() const { return this->m_target + length(); }
+
private:
/// \brief Find memory share base pointer
///
@@ -1312,6 +1367,34 @@ public:
/// \return Memory share width in bytes.
u8 bytewidth() const { return m_target->bytewidth(); }
+ /// \brief Get iterator to first element
+ ///
+ /// Returns an iterator to the first element of the memory share.
+ /// Must not be called before creation is attempted.
+ /// \return Iterator to first element.
+ PointerType *begin() const { return target(); }
+
+ /// \brief Get iterator beyond last element
+ ///
+ /// Returns an iterator one past the last element of the memory
+ /// share. Must not be called before creation is attempted.
+ /// \return Iterator one past last element.
+ PointerType *end() const { return target() + length(); }
+
+ /// \brief Get constant iterator to first element
+ ///
+ /// Returns a constant iterator to the first element of the memory
+ /// share. Must not be called before creation is attempted.
+ /// \return Constant iterator to first element.
+ PointerType const *cbegin() const { return target(); }
+
+ /// \brief Get constant iterator beyond last element
+ ///
+ /// Returns a constant iterator one past the last element of the
+ /// memory share. Must not be called before creation is attempted.
+ /// \return Constant iterator one past last element.
+ PointerType const *cend() const { return target() + length(); }
+
protected:
virtual bool findit(validity_checker *valid) override;
virtual void end_configuration() override;
diff --git a/src/emu/device.cpp b/src/emu/device.cpp
index c9097a59d4f..1940c619455 100644
--- a/src/emu/device.cpp
+++ b/src/emu/device.cpp
@@ -224,7 +224,7 @@ void device_t::add_machine_configuration(machine_config &config)
assert(&config == &m_machine_config);
machine_config::token const tok(config.begin_configuration(*this));
device_add_mconfig(config);
- for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next())
+ for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next())
autodev->end_configuration();
}
@@ -321,11 +321,7 @@ void device_t::config_complete()
void device_t::validity_check(validity_checker &valid) const
{
- // validate callbacks
- for (devcb_base const *callback : m_callbacks)
- callback->validity_check(valid);
-
- // validate via the interfaces
+ // validate mixins
for (device_interface &intf : interfaces())
intf.interface_validity_check(valid);
@@ -365,7 +361,7 @@ void device_t::reset()
// unscaled clock
//-------------------------------------------------
-void device_t::set_unscaled_clock(u32 clock)
+void device_t::set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain)
{
// do nothing if no actual change
if (clock == m_unscaled_clock)
@@ -381,7 +377,7 @@ void device_t::set_unscaled_clock(u32 clock)
// if the device has already started, make sure it knows about the new clock
if (m_started)
- notify_clock_changed();
+ notify_clock_changed(sync_on_new_clock_domain);
}
@@ -460,28 +456,6 @@ u64 device_t::attotime_to_clocks(const attotime &duration) const noexcept
//-------------------------------------------------
-// timer_alloc - allocate a timer for our device
-// callback
-//-------------------------------------------------
-
-emu_timer *device_t::timer_alloc(device_timer_id id, void *ptr)
-{
- return machine().scheduler().timer_alloc(*this, id, ptr);
-}
-
-
-//-------------------------------------------------
-// timer_set - set a temporary timer that will
-// call our device callback
-//-------------------------------------------------
-
-void device_t::timer_set(const attotime &duration, device_timer_id id, int param, void *ptr)
-{
- machine().scheduler().timer_set(duration, *this, id, param, ptr);
-}
-
-
-//-------------------------------------------------
// set_machine - notify that the machine now
// exists
//-------------------------------------------------
@@ -500,26 +474,10 @@ void device_t::set_machine(running_machine &machine)
bool device_t::findit(validity_checker *valid) const
{
bool allfound = true;
- for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next())
+ for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next())
{
- if (valid)
- {
- // sanity checking
- char const *const tag = autodev->finder_tag();
- if (!tag)
- {
- osd_printf_error("Finder tag is null!\n");
- allfound = false;
- continue;
- }
- if (tag[0] == '^' && tag[1] == ':')
- {
- osd_printf_error("Malformed finder tag: %s\n", tag);
- allfound = false;
- continue;
- }
- }
- allfound &= autodev->findit(valid);
+ if (!autodev->findit(valid))
+ allfound = false;
}
return allfound;
}
@@ -609,7 +567,6 @@ void device_t::start()
}
// register our save states
- save_item(NAME(m_clock));
save_item(NAME(m_unscaled_clock));
save_item(NAME(m_clock_scale));
@@ -688,6 +645,21 @@ void device_t::pre_save()
void device_t::post_load()
{
+ // recompute clock-related parameters if something changed
+ u32 const scaled_clock = m_unscaled_clock * m_clock_scale;
+ if (m_clock != scaled_clock)
+ {
+ m_clock = scaled_clock;
+ m_attoseconds_per_clock = (scaled_clock == 0) ? 0 : HZ_TO_ATTOSECONDS(scaled_clock);
+
+ // recalculate all derived clocks
+ for (device_t &child : subdevices())
+ child.calculate_derived_clock();
+
+ // make sure the device knows about the new clock
+ notify_clock_changed();
+ }
+
// notify the interface
for (device_interface &intf : interfaces())
intf.interface_post_load();
@@ -702,11 +674,11 @@ void device_t::post_load()
// that the clock has changed
//-------------------------------------------------
-void device_t::notify_clock_changed()
+void device_t::notify_clock_changed(bool sync_on_new_clock_domain)
{
// first notify interfaces
for (device_interface &intf : interfaces())
- intf.interface_clock_changed();
+ intf.interface_clock_changed(sync_on_new_clock_domain);
// then notify the device
device_clock_changed();
@@ -868,17 +840,6 @@ void device_t::device_debug_setup()
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
-//-------------------------------------------------
-
-void device_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- // do nothing by default
-}
-
-
-//-------------------------------------------------
// subdevice_slow - perform a slow name lookup,
// caching the results
//-------------------------------------------------
@@ -1025,18 +986,9 @@ void device_t::subdevice_list::remove(device_t &device)
// list of stuff to find after we go live
//-------------------------------------------------
-finder_base *device_t::register_auto_finder(finder_base &autodev)
-{
- // add to this list
- finder_base *old = m_auto_finder_list;
- m_auto_finder_list = &autodev;
- return old;
-}
-
-
-void device_t::register_callback(devcb_base &callback)
+device_resolver_base *device_t::register_auto_finder(device_resolver_base &autodev)
{
- m_callbacks.emplace_back(&callback);
+ return std::exchange(m_auto_finder_list, &autodev);
}
@@ -1188,7 +1140,7 @@ void device_interface::interface_post_load()
// implementation
//-------------------------------------------------
-void device_interface::interface_clock_changed()
+void device_interface::interface_clock_changed(bool sync_on_new_clock_domain)
{
// do nothing by default
}
diff --git a/src/emu/device.h b/src/emu/device.h
index 77c12cb2d56..87736144292 100644
--- a/src/emu/device.h
+++ b/src/emu/device.h
@@ -37,19 +37,6 @@
//**************************************************************************
-// DEVICE CONFIGURATION MACROS
-//**************************************************************************
-
-// configure devices
-
-#define DECLARE_READ_LINE_MEMBER(name) int name()
-#define READ_LINE_MEMBER(name) int name()
-#define DECLARE_WRITE_LINE_MEMBER(name) void name([[maybe_unused]] int state)
-#define WRITE_LINE_MEMBER(name) void name([[maybe_unused]] int state)
-
-
-
-//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -210,7 +197,7 @@ private:
assert(!owner);
assert(!clock);
- return make_unique_clear<DriverClass>(mconfig, type, tag);
+ return std::make_unique<DriverClass>(mconfig, type, tag);
}
create_func const m_creator;
@@ -468,10 +455,6 @@ constexpr auto driver_device_creator = &emu::detail::driver_tag_func<DriverClass
class device_missing_dependencies : public emu_exception { };
-// timer IDs for devices
-typedef u32 device_timer_id;
-
-
/// \brief Base class for devices
///
/// The base class for all device implementations in MAME's modular
@@ -482,8 +465,7 @@ class device_t : public delegate_late_bind
friend class simple_list<device_t>;
friend class running_machine;
- friend class finder_base;
- friend class devcb_base;
+ friend class device_resolver_base;
class subdevice_list
{
@@ -651,8 +633,8 @@ public:
// interface helpers
interface_list &interfaces() { return m_interfaces; }
const interface_list &interfaces() const { return m_interfaces; }
- template<class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); }
- template<class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); }
+ template <class DeviceClass> bool interface(DeviceClass *&intf) { intf = dynamic_cast<DeviceClass *>(this); return (intf != nullptr); }
+ template <class DeviceClass> bool interface(DeviceClass *&intf) const { intf = dynamic_cast<const DeviceClass *>(this); return (intf != nullptr); }
// specialized helpers for common core interfaces
bool interface(device_execute_interface *&intf) { intf = m_interfaces.m_execute; return (intf != nullptr); }
@@ -675,8 +657,42 @@ public:
ioport_port *ioport(std::string_view tag) const;
device_t *subdevice(std::string_view tag) const;
device_t *siblingdevice(std::string_view tag) const;
- template<class DeviceClass> DeviceClass *subdevice(std::string_view tag) const { return downcast<DeviceClass *>(subdevice(tag)); }
- template<class DeviceClass> DeviceClass *siblingdevice(std::string_view tag) const { return downcast<DeviceClass *>(siblingdevice(tag)); }
+ template <class DeviceClass>
+ DeviceClass *subdevice(std::string_view tag) const
+ {
+ device_t *const found = subdevice(tag);
+ if constexpr (std::is_base_of_v<device_t, DeviceClass>)
+ {
+ return downcast<DeviceClass *>(found);
+ }
+ else
+ {
+ auto const result = dynamic_cast<DeviceClass *>(found);
+#if defined(MAME_DEBUG)
+ if (found && !result)
+ report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass));
+#endif
+ return result;
+ }
+ }
+ template <class DeviceClass>
+ DeviceClass *siblingdevice(std::string_view tag) const
+ {
+ device_t *const found = siblingdevice(tag);
+ if constexpr (std::is_base_of_v<device_t, DeviceClass>)
+ {
+ return downcast<DeviceClass *>(found);
+ }
+ else
+ {
+ auto const result = dynamic_cast<DeviceClass *>(found);
+#if defined(MAME_DEBUG)
+ if (found && !result)
+ report_bad_device_cast(found, typeid(device_t), typeid(DeviceClass));
+#endif
+ return result;
+ }
+ }
std::string parameter(std::string_view tag) const;
// configuration helpers
@@ -696,19 +712,17 @@ public:
// clock/timing accessors
u32 clock() const { return m_clock; }
u32 unscaled_clock() const { return m_unscaled_clock; }
- void set_unscaled_clock(u32 clock);
- void set_unscaled_clock(const XTAL &xtal) { set_unscaled_clock(xtal.value()); }
- void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock); } // non-overloaded name because binding to overloads is ugly
+ void set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain = false);
+ void set_unscaled_clock(const XTAL &xtal, bool sync_on_new_clock_domain = false) { set_unscaled_clock(xtal.value(), sync_on_new_clock_domain); }
+ void set_unscaled_clock_int(u32 clock) { set_unscaled_clock(clock, false); } // non-overloaded name because binding to overloads is ugly
+ void set_unscaled_clock_int_sync(u32 clock) { set_unscaled_clock(clock, true); } // non-overloaded name because binding to overloads is ugly
double clock_scale() const { return m_clock_scale; }
void set_clock_scale(double clockscale);
attotime clocks_to_attotime(u64 clocks) const noexcept;
u64 attotime_to_clocks(const attotime &duration) const noexcept;
// timer interfaces
- emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr);
- void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr);
- void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); }
- void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); }
+ template <typename... T> emu_timer *timer_alloc(T &&... args);
/// \brief Register data for save states
///
@@ -777,7 +791,7 @@ public:
/// \param [in] index A numeric value to distinguish between saved
/// items with the same name.
/// \sa save_item
- template<typename ItemType>
+ template <typename ItemType>
void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
{
assert(m_save);
@@ -806,7 +820,7 @@ public:
/// \param [in] index A numeric value to distinguish between saved
/// items with the same name.
/// \sa save_item
- template<typename ItemType, typename StructType, typename ElementType>
+ template <typename ItemType, typename StructType, typename ElementType>
void ATTR_COLD save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0)
{
assert(m_save);
@@ -834,9 +848,8 @@ protected:
void debug_setup();
void pre_save();
void post_load();
- void notify_clock_changed();
- finder_base *register_auto_finder(finder_base &autodev);
- void register_callback(devcb_base &callback);
+ void notify_clock_changed(bool sync_on_new_clock_domain = false);
+ device_resolver_base *register_auto_finder(device_resolver_base &autodev);
//------------------- begin derived class overrides
@@ -976,7 +989,6 @@ protected:
virtual void device_clock_changed();
virtual void device_debug_setup();
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
//------------------- end derived class overrides
@@ -1016,9 +1028,8 @@ private:
std::string m_basetag; // base part of the tag
bool m_config_complete; // have we completed our configuration?
bool m_started; // true if the start function has succeeded
- finder_base * m_auto_finder_list; // list of objects to auto-find
+ device_resolver_base * m_auto_finder_list; // list of objects to auto-find
mutable std::vector<rom_entry> m_rom_entries;
- std::list<devcb_base *> m_callbacks;
std::vector<memory_view *> m_viewlist; // list of views
// string formatting buffer for logerror
@@ -1182,7 +1193,7 @@ public:
/// \sa interface_pre_save device_t::device_post_load
virtual void interface_post_load() ATTR_COLD;
- virtual void interface_clock_changed();
+ virtual void interface_clock_changed(bool sync_on_new_clock_domain);
virtual void interface_debug_setup();
private:
diff --git a/src/emu/device.ipp b/src/emu/device.ipp
index 820f81093d0..e633ead4bda 100644
--- a/src/emu/device.ipp
+++ b/src/emu/device.ipp
@@ -75,6 +75,11 @@ inline void device_delegate_helper::set_tag(device_finder<DeviceClass, Required>
} // namespace emu::detail
+template <typename... T>
+inline emu_timer *device_t::timer_alloc(T &&... args)
+{
+ return machine().scheduler().timer_alloc(timer_expired_delegate(std::forward<T>(args)...));
+}
template <typename Format, typename... Params>
inline void device_t::popmessage(Format &&fmt, Params &&... args) const
@@ -88,7 +93,7 @@ inline void device_t::logerror(Format &&fmt, Params &&... args) const
{
if (m_machine != nullptr && m_machine->allow_logging())
{
- g_profiler.start(PROFILER_LOGERROR);
+ auto profile = g_profiler.start(PROFILER_LOGERROR);
// dump to the buffer
m_string_buffer.clear();
@@ -98,8 +103,6 @@ inline void device_t::logerror(Format &&fmt, Params &&... args) const
m_string_buffer.put('\0');
m_machine->strlog(&m_string_buffer.vec()[0]);
-
- g_profiler.stop();
}
}
diff --git a/src/emu/diexec.cpp b/src/emu/diexec.cpp
index 49dee5f650e..715f0c38459 100644
--- a/src/emu/diexec.cpp
+++ b/src/emu/diexec.cpp
@@ -68,9 +68,8 @@ device_execute_interface::device_execute_interface(const machine_config &mconfig
, m_divshift(0)
, m_cycles_per_second(0)
, m_attoseconds_per_cycle(0)
+ , m_spin_end_timer(nullptr)
{
- memset(&m_localtime, 0, sizeof(m_localtime));
-
// configure the fast accessor
assert(!device.interfaces().m_execute);
device.interfaces().m_execute = this;
@@ -164,7 +163,7 @@ void device_execute_interface::spin_until_time(const attotime &duration)
suspend_until_trigger(TRIGGER_SUSPENDTIME + timetrig, true);
// then set a timer for it
- m_scheduler->timer_set(duration, timer_expired_delegate(FUNC(device_execute_interface::timed_trigger_callback),this), TRIGGER_SUSPENDTIME + timetrig, this);
+ m_spin_end_timer->adjust(duration, TRIGGER_SUSPENDTIME + timetrig);
timetrig = (timetrig + 1) % 256;
}
@@ -384,9 +383,16 @@ void device_execute_interface::interface_pre_start()
m_profiler = profile_type(index + PROFILER_DEVICE_FIRST);
m_inttrigger = index + TRIGGER_INT;
- // allocate timers if we need them
+ // allocate a timed-interrupt timer if we need it
if (m_timed_interrupt_period != attotime::zero)
m_timedint_timer = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::trigger_periodic_interrupt), this));
+
+ // allocate a timer for triggering the end of spin-until conditions
+ m_spin_end_timer = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::timed_trigger_callback), this));
+
+ // allocate input-pulse timers if we have input lines
+ for (u32 i = 0; i < MAX_INPUT_LINES; i++)
+ m_pulse_end_timers[i] = m_scheduler->timer_alloc(timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this));
}
@@ -475,7 +481,7 @@ void device_execute_interface::interface_post_reset()
// information for this device
//-------------------------------------------------
-void device_execute_interface::interface_clock_changed()
+void device_execute_interface::interface_clock_changed(bool sync_on_new_clock_domain)
{
// a clock of zero disables the device
if (device().clock() == 0)
@@ -492,6 +498,10 @@ void device_execute_interface::interface_clock_changed()
m_cycles_per_second = clocks_to_cycles(device().clock());
m_attoseconds_per_cycle = HZ_TO_ATTOSECONDS(m_cycles_per_second);
+ // resynchronize the localtime to the clock domain when asked to
+ if (sync_on_new_clock_domain)
+ m_localtime = attotime::from_ticks(m_localtime.as_ticks(device().clock())+1, device().clock());
+
// update the device's divisor
s64 attos = m_attoseconds_per_cycle;
m_divshift = 0;
@@ -508,17 +518,12 @@ void device_execute_interface::interface_clock_changed()
//-------------------------------------------------
-// standard_irq_callback_member - IRQ acknowledge
+// standard_irq_callback - IRQ acknowledge
// callback; handles HOLD_LINE case and signals
// to the debugger
//-------------------------------------------------
-IRQ_CALLBACK_MEMBER( device_execute_interface::standard_irq_callback_member )
-{
- return device.execute().standard_irq_callback(irqline);
-}
-
-int device_execute_interface::standard_irq_callback(int irqline)
+int device_execute_interface::standard_irq_callback(int irqline, offs_t pc)
{
// get the default vector and acknowledge the interrupt if needed
int vector = m_input[irqline].default_irq_callback();
@@ -531,7 +536,7 @@ int device_execute_interface::standard_irq_callback(int irqline)
// notify the debugger
if (device().machine().debug_flags & DEBUG_FLAG_ENABLED)
- device().debug()->interrupt_hook(irqline);
+ device().debug()->interrupt_hook(irqline, pc);
return vector;
}
@@ -615,7 +620,7 @@ void device_execute_interface::pulse_input_line(int irqline, const attotime &dur
set_input_line(irqline, ASSERT_LINE);
attotime target_time = local_time() + duration;
- m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline);
+ m_pulse_end_timers[irqline]->adjust(target_time - m_scheduler->time(), irqline);
}
}
@@ -682,7 +687,7 @@ if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_execute->device().tag(), m_linen
if (event_index >= std::size(m_queue))
{
m_qindex--;
- empty_event_queue(nullptr,0);
+ empty_event_queue(0);
event_index = m_qindex++;
m_execute->device().logerror("Exceeded pending input line event queue on device '%s'!\n", m_execute->device().tag());
}
@@ -696,7 +701,7 @@ if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_execute->device().tag(), m_linen
// if this is the first one, set the timer
if (event_index == 0)
- m_execute->scheduler().synchronize(timer_expired_delegate(FUNC(device_execute_interface::device_input::empty_event_queue),this), 0, this);
+ m_execute->scheduler().synchronize(timer_expired_delegate(FUNC(device_execute_interface::device_input::empty_event_queue),this));
}
}
diff --git a/src/emu/diexec.h b/src/emu/diexec.h
index 065248a9046..51973ad19cc 100644
--- a/src/emu/diexec.h
+++ b/src/emu/diexec.h
@@ -161,10 +161,10 @@ public:
void abort_timeslice() noexcept;
// input and interrupt management
- void set_input_line(int linenum, int state) { m_input[linenum].set_state_synced(state); }
- void set_input_line_vector(int linenum, int vector) { m_input[linenum].set_vector(vector); }
- void set_input_line_and_vector(int linenum, int state, int vector) { m_input[linenum].set_state_synced(state, vector); }
- int input_state(int linenum) const { return m_input[linenum].m_curstate; }
+ void set_input_line(int linenum, int state) { assert(device().started()); m_input[linenum].set_state_synced(state); }
+ void set_input_line_vector(int linenum, int vector) { assert(device().started()); m_input[linenum].set_vector(vector); }
+ void set_input_line_and_vector(int linenum, int state, int vector) { assert(device().started()); m_input[linenum].set_state_synced(state, vector); }
+ int input_state(int linenum) const { assert(device().started()); return m_input[linenum].m_curstate; }
void pulse_input_line(int irqline, const attotime &duration);
// suspend/resume
@@ -216,13 +216,12 @@ protected:
virtual void interface_post_start() override;
virtual void interface_pre_reset() override;
virtual void interface_post_reset() override;
- virtual void interface_clock_changed() override;
+ virtual void interface_clock_changed(bool sync_on_new_clock_domain) override;
// for use by devcpu for now...
int current_input_state(unsigned i) const { return m_input[i].m_curstate; }
void set_icountptr(int &icount) { assert(!m_icountptr); m_icountptr = &icount; }
- IRQ_CALLBACK_MEMBER(standard_irq_callback_member);
- int standard_irq_callback(int irqline);
+ int standard_irq_callback(int irqline, offs_t pc);
// debugger hooks
bool debugger_enabled() const { return bool(device().machine().debug_flags & DEBUG_FLAG_ENABLED); }
@@ -304,7 +303,9 @@ private:
// cycle counting and executing
profile_type m_profiler; // profiler tag
+protected: // TODO: decide whether to bring up the wait-state methods
int * m_icountptr; // pointer to the icount
+private:
int m_cycles_running; // number of cycles we are executing
int m_cycles_stolen; // number of cycles we artificially stole
@@ -324,6 +325,9 @@ private:
u32 m_cycles_per_second; // cycles per second, adjusted for multipliers
attoseconds_t m_attoseconds_per_cycle; // attoseconds per adjusted clock cycle
+ emu_timer * m_spin_end_timer; // timer for triggering the end of spin_until_time
+ emu_timer * m_pulse_end_timers[MAX_INPUT_LINES]; // timer for ending input-line pulses
+
// callbacks
TIMER_CALLBACK_MEMBER(timed_trigger_callback) { trigger(param); }
diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp
index 031ed46eb30..59d1523a6b1 100644
--- a/src/emu/diimage.cpp
+++ b/src/emu/diimage.cpp
@@ -11,49 +11,20 @@
#include "emu.h"
#include "emuopts.h"
+#include "fileio.h"
#include "romload.h"
#include "softlist.h"
#include "softlist_dev.h"
-#include "ui/uimain.h"
-
#include "corestr.h"
#include "opresolv.h"
+#include "path.h"
#include "zippath.h"
#include <algorithm>
-#include <cctype>
#include <cstring>
#include <regex>
-
-
-//**************************************************************************
-// DEVICE CONFIG IMAGE INTERFACE
-//**************************************************************************
-const image_device_type_info device_image_interface::m_device_info_array[] =
- {
- { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */
- { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */
- { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */
- { IO_HARDDISK, "harddisk", "hard" }, /* 3 */
- { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */
- { IO_CASSETTE, "cassette", "cass" }, /* 5 */
- { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */
- { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */
- { IO_PRINTER, "printout", "prin" }, /* 8 */
- { IO_SERIAL, "serial", "serl" }, /* 9 */
- { IO_PARALLEL, "parallel", "parl" }, /* 10 */
- { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */
- { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */
- { IO_MEMCARD, "memcard", "memc" }, /* 13 */
- { IO_CDROM, "cdrom", "cdrm" }, /* 14 */
- { IO_MAGTAPE, "magtape", "magt" }, /* 15 */
- { IO_ROM, "romimage", "rom" }, /* 16 */
- { IO_MIDIIN, "midiin", "min" }, /* 17 */
- { IO_MIDIOUT, "midiout", "mout" }, /* 18 */
- { IO_PICTURE, "picture", "pic" }, /* 19 */
- { IO_VIDEO, "vidfile", "vid" } /* 20 */
- };
+#include <sstream>
//**************************************************************************
@@ -94,15 +65,18 @@ image_device_format::~image_device_format()
device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "image")
- , m_err()
, m_file()
, m_mame_file()
+ , m_default_region(-1)
+ , m_current_region(-1)
, m_software_part_ptr(nullptr)
+ , m_sequence_counter(0)
, m_readonly(false)
, m_created(false)
, m_create_format(0)
, m_create_args(nullptr)
, m_user_loadable(true)
+ , m_must_be_loaded(false)
, m_is_loading(false)
, m_is_reset_and_loading(false)
{
@@ -117,6 +91,17 @@ device_image_interface::~device_image_interface()
{
}
+//-------------------------------------------------
+// add_region - register a region that may
+// have a chd image
+//-------------------------------------------------
+void device_image_interface::add_region(std::string name, bool is_default)
+{
+ if (is_default)
+ m_default_region = m_possible_preset_regions.size();
+ m_possible_preset_regions.push_back(name);
+}
+
//-------------------------------------------------
// interface_config_complete - perform any
@@ -130,57 +115,134 @@ void device_image_interface::interface_config_complete()
update_names();
}
-
//-------------------------------------------------
-// find_device_type - search through list of
-// device types to extract data
+// check_preset_images - lookup the CHDs from the
+// region(s), if any
//-------------------------------------------------
-const image_device_type_info *device_image_interface::find_device_type(iodevice_t type)
+void device_image_interface::check_preset_images()
{
- for (const image_device_type_info &info : m_device_info_array)
+ if (!m_possible_preset_regions.empty())
{
- if (info.m_type == type)
- return &info;
+ for(const auto &r : m_possible_preset_regions)
+ m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r));
+ if (m_default_region != -1 && m_preset_images[m_default_region])
+ m_current_region = m_default_region;
+ else
+ {
+ for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++);
+ if (m_current_region == int(m_preset_images.size()))
+ fatalerror("%s: No configured region has an image\n", device().tag());
+ }
+ set_image_tag();
+ set_user_loadable(false);
+ }
+ else
+ {
+ std::string tag = device().owner()->tag();
+ auto *const chd = device().machine().rom_load().get_disk_handle(tag);
+ if (chd)
+ {
+ m_possible_preset_regions.emplace_back(std::move(tag));
+ m_preset_images.push_back(chd);
+ m_current_region = 0;
+ set_image_tag();
+ set_user_loadable(false);
+ }
}
- return nullptr;
}
//-------------------------------------------------
-// device_typename - retrieves device type name
+// has_preset_images - does the device have an
+// image to retrieve through current_image_*
//-------------------------------------------------
-const char *device_image_interface::device_typename(iodevice_t type)
+bool device_image_interface::has_preset_images() const
{
- const image_device_type_info *info = find_device_type(type);
- return (info != nullptr) ? info->m_name : "unknown";
+ return !m_possible_preset_regions.empty();
}
//-------------------------------------------------
-// device_brieftypename - retrieves device
-// brief type name
+// has_preset_images - does the device have
+// multiple preset images with user selection
//-------------------------------------------------
-const char *device_image_interface::device_brieftypename(iodevice_t type)
+bool device_image_interface::has_preset_images_selection() const
{
- const image_device_type_info *info = find_device_type(type);
- return (info != nullptr) ? info->m_shortname : "unk";
+ int icount = 0;
+ for (const auto *f : m_preset_images)
+ if (f)
+ icount ++;
+ return icount > 1;
}
+
//-------------------------------------------------
-// device_typeid - retrieves device type id
+// preset_images_list -- generate the list of
+// available image names
//-------------------------------------------------
-iodevice_t device_image_interface::device_typeid(const char *name)
+std::vector<std::string> device_image_interface::preset_images_list() const
{
- for (const image_device_type_info &info : m_device_info_array)
- {
- if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname))
- return info.m_type;
- }
- return (iodevice_t)-1;
+ std::vector<std::string> result;
+ for (unsigned int i = 0; i != m_preset_images.size(); i++)
+ if (m_preset_images[i])
+ result.push_back(m_possible_preset_regions[i]);
+ return result;
+}
+
+//-------------------------------------------------
+// current_preset_image_id -- current image id,
+// recomputed to ignore non-present images.
+// returns -1 if not in preset mode
+//-------------------------------------------------
+
+int device_image_interface::current_preset_image_id() const
+{
+ if (m_current_region == -1)
+ return -1;
+ int id = 0;
+ for (int i = 0; i != m_current_region; i++)
+ if (m_preset_images[i])
+ id++;
+ return id;
+}
+
+//-------------------------------------------------
+// current_preset_image_chd -- return the chd of
+// the current active image, nullptr if non
+//-------------------------------------------------
+
+chd_file *device_image_interface::current_preset_image_chd() const
+{
+ if (m_current_region == -1)
+ return nullptr;
+ return m_preset_images[m_current_region];
+}
+
+//-------------------------------------------------
+// switch_preset_image -- change of preset image
+//-------------------------------------------------
+
+void device_image_interface::switch_preset_image(int id)
+{
+ for (unsigned int i = 0; i != m_preset_images.size(); i++)
+ if (m_preset_images[i])
+ {
+ if(!id)
+ {
+ call_unload();
+ m_current_region = i;
+ call_load();
+ break;
+ }
+ id--;
+ }
+
+ return;
}
+
//-------------------------------------------------
// set_image_filename - specifies the filename of
// an image
@@ -194,9 +256,9 @@ void device_image_interface::set_image_filename(std::string_view filename)
// find the last "path separator"
auto iter = std::find_if(
- m_image_name.rbegin(),
- m_image_name.rend(),
- [](char c) { return (c == '\\') || (c == '/') || (c == ':'); });
+ m_image_name.rbegin(),
+ m_image_name.rend(),
+ [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); });
if (iter != m_image_name.rend())
m_basename.assign(iter.base(), m_image_name.end());
@@ -209,6 +271,20 @@ void device_image_interface::set_image_filename(std::string_view filename)
m_filetype = core_filename_extract_extension(m_basename, true);
}
+//-------------------------------------------------
+// set_image_tag - specifies the filename of
+// an image as the device tag
+//-------------------------------------------------
+
+void device_image_interface::set_image_tag()
+{
+ m_image_name = device().owner()->tag();
+ m_working_directory = "";
+ m_basename = "";
+ m_basename_noext = "";
+ m_filetype = "";
+}
+
//-------------------------------------------------
// is_filetype - check if the filetype matches
@@ -216,14 +292,24 @@ void device_image_interface::set_image_filename(std::string_view filename)
bool device_image_interface::is_filetype(std::string_view candidate_filetype) const
{
- return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(),
- [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; });
+ return util::streqlower(m_filetype, candidate_filetype);
}
-/****************************************************************************
- CREATION FORMATS
-****************************************************************************/
+//-------------------------------------------------
+// add_media_change_notifier - subscribe for
+// media change notifications
+//-------------------------------------------------
+
+util::notifier_subscription device_image_interface::add_media_change_notifier(delegate<void (media_change_event)> &&n)
+{
+ return m_media_change_notifier.subscribe(std::move(n));
+}
+
+
+//***************************************************************************
+// CREATION FORMATS
+//***************************************************************************
//-------------------------------------------------
// device_get_named_creatable_format -
@@ -231,10 +317,10 @@ bool device_image_interface::is_filetype(std::string_view candidate_filetype) co
// image creation by name
//-------------------------------------------------
-const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept
+const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept
{
- for (auto &format : m_formatlist)
- if (format->name() == format_name)
+ for (const auto &format : m_formatlist)
+ if (std::string_view(format->name()) == format_name)
return format.get();
return nullptr;
}
@@ -261,22 +347,9 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri
}
-/****************************************************************************
- ERROR HANDLING
-****************************************************************************/
-
-//-------------------------------------------------
-// image_clear_error - clear out any specified
-// error
-//-------------------------------------------------
-
-void device_image_interface::clear_error()
-{
- m_err.clear();
- m_err_message.clear();
-}
-
-
+//***************************************************************************
+// ERROR HANDLING
+//***************************************************************************
//-------------------------------------------------
// error - returns the error text for an image
@@ -298,7 +371,10 @@ std::error_category const &image_category() noexcept
"Internal error"sv,
"Unsupported operation"sv,
"Invalid image"sv,
+ "Invalid image length"sv,
"File already open"sv,
+ "Unrecognized software item"sv,
+ "Invalid software item"sv,
"Unspecified error"sv };
if ((0 <= condition) && (std::size(s_messages) > condition))
return std::string(s_messages[condition]);
@@ -310,50 +386,6 @@ std::error_category const &image_category() noexcept
return s_image_category_instance;
}
-std::string_view device_image_interface::error()
-{
- if (m_err && m_err_message.empty())
- m_err_message = m_err.message();
- return m_err_message;
-}
-
-
-
-//-------------------------------------------------
-// seterror - specifies an error on an image
-//-------------------------------------------------
-
-void device_image_interface::seterror(std::error_condition err, const char *message)
-{
- clear_error();
- m_err = err;
- if (message)
- m_err_message = message;
-}
-
-
-
-//-------------------------------------------------
-// message - used to display a message while
-// loading
-//-------------------------------------------------
-
-void device_image_interface::message(const char *format, ...)
-{
- va_list args;
- char buffer[256];
-
- /* format the message */
- va_start(args, format);
- vsnprintf(buffer, std::size(buffer), format, args);
- va_end(args);
-
- /* display the popup for a standard amount of time */
- device().machine().ui().popup_time(5, "%s: %s",
- basename(),
- buffer);
-}
-
//-------------------------------------------------
// software_entry - return a pointer to the
@@ -370,14 +402,13 @@ const software_info *device_image_interface::software_entry() const noexcept
// get_software_region
//-------------------------------------------------
-u8 *device_image_interface::get_software_region(const char *tag)
+u8 *device_image_interface::get_software_region(std::string_view tag)
{
if (!loaded_through_softlist())
return nullptr;
- std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
- memory_region *region = device().machine().root_device().memregion(full_tag);
- return region != nullptr ? region->base() : nullptr;
+ memory_region *const region = device().memregion(tag);
+ return region ? region->base() : nullptr;
}
@@ -385,11 +416,13 @@ u8 *device_image_interface::get_software_region(const char *tag)
// image_get_software_region_length
//-------------------------------------------------
-u32 device_image_interface::get_software_region_length(const char *tag)
+u32 device_image_interface::get_software_region_length(std::string_view tag)
{
- std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
- memory_region *region = device().machine().root_device().memregion(full_tag);
- return region != nullptr ? region->bytes() : 0;
+ if (!loaded_through_softlist())
+ return 0;
+
+ memory_region *const region = device().memregion(tag);
+ return region ? region->bytes() : 0;
}
@@ -397,7 +430,7 @@ u32 device_image_interface::get_software_region_length(const char *tag)
// image_get_feature
//-------------------------------------------------
-const char *device_image_interface::get_feature(const char *feature_name) const
+const char *device_image_interface::get_feature(std::string_view feature_name) const
{
return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name);
}
@@ -407,7 +440,7 @@ const char *device_image_interface::get_feature(const char *feature_name) const
// load_software_region -
//-------------------------------------------------
-bool device_image_interface::load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr)
+std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr<u8[]> &ptr)
{
size_t size = get_software_region_length(tag);
@@ -415,9 +448,10 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p
{
ptr = std::make_unique<u8[]>(size);
memcpy(ptr.get(), get_software_region(tag), size);
+ return std::error_condition();
}
-
- return size > 0;
+ else
+ return image_error::UNSUPPORTED;
}
@@ -428,48 +462,30 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p
// to be loaded
// ****************************************************************************
-bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
+std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
{
// reset the hash; we want to override existing data
hashes.reset();
// figure out the size, and "cap" the skip bytes
u64 size;
- if (file.length(size))
- return false;
+ std::error_condition filerr = file.length(size);
+ if (filerr)
+ return filerr;
skip_bytes = u32(std::min<u64>(skip_bytes, size));
- // seek to the beginning
- file.seek(skip_bytes, SEEK_SET); // TODO: check error return
- u64 position = skip_bytes;
-
- // keep on reading hashes
- hashes.begin(types);
- while (position < size)
- {
- uint8_t buffer[8192];
-
- // read bytes
- const size_t count = size_t(std::min<u64>(size - position, sizeof(buffer)));
- size_t actual_count;
- const std::error_condition filerr = file.read(buffer, count, actual_count);
- if (filerr || !actual_count)
- return false;
- position += actual_count;
-
- // and compute the hashes
- hashes.buffer(buffer, actual_count);
- }
- hashes.end();
+ // and compute the hashes
+ size_t actual_count;
+ filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types);
+ if (filerr)
+ return filerr;
- // cleanup
- file.seek(0, SEEK_SET); // TODO: check error return
- return true;
+ return std::error_condition();
}
-bool device_image_interface::image_checkhash()
+std::error_condition device_image_interface::image_checkhash()
{
// only calculate CRC if it hasn't been calculated, and the open_mode is read only
u32 crcval;
@@ -477,26 +493,25 @@ bool device_image_interface::image_checkhash()
{
// do not cause a linear read of 600 megs please
// TODO: use SHA1 in the CHD header as the hash
- if (image_type() == IO_CDROM)
- return true;
+ if (image_is_chd_type())
+ return std::error_condition();
// Skip calculating the hash when we have an image mounted through a software list
if (loaded_through_softlist())
- return true;
+ return std::error_condition();
// run the hash
- if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL))
- return false;
+ return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL);
}
- return true;
+ return std::error_condition();
}
-util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const
+util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const
{
// calculate the hash
util::hash_collection hash;
- if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
+ if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
hash.reset();
return hash;
}
@@ -514,33 +529,6 @@ u32 device_image_interface::crc()
}
-//-------------------------------------------------
-// support_command_line_image_creation - do we
-// want to support image creation from the front
-// end command line?
-//-------------------------------------------------
-
-bool device_image_interface::support_command_line_image_creation() const noexcept
-{
- bool result;
- switch (image_type())
- {
- case IO_PRINTER:
- case IO_SERIAL:
- case IO_PARALLEL:
- // going by the assumption that these device image types should support this
- // behavior; ideally we'd get rid of IO_* and just push this to the specific
- // devices
- result = true;
- break;
- default:
- result = false;
- break;
- }
- return result;
-}
-
-
// ****************************************************************************
// Battery functions
//
@@ -619,34 +607,6 @@ void device_image_interface::battery_save(const void *buffer, int length)
}
-//-------------------------------------------------
-// uses_file_extension - update configuration
-// based on completed device setup
-//-------------------------------------------------
-
-bool device_image_interface::uses_file_extension(const char *file_extension) const
-{
- bool result = false;
-
- if (file_extension[0] == '.')
- file_extension++;
-
- /* find the extensions */
- std::string extensions(file_extensions());
- char *ext = strtok((char*)extensions.c_str(),",");
- while (ext != nullptr)
- {
- if (!core_stricmp(ext, file_extension))
- {
- result = true;
- break;
- }
- ext = strtok (nullptr, ",");
- }
- return result;
-}
-
-
// ***************************************************************************
// IMAGE LOADING
// ***************************************************************************
@@ -712,15 +672,20 @@ std::vector<u32> device_image_interface::determine_open_plan(bool is_create)
{
std::vector<u32> open_plan;
- // emit flags into a vector
- if (!is_create && is_readable() && is_writeable())
- open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE);
- if (!is_create && !is_readable() && is_writeable())
- open_plan.push_back(OPEN_FLAG_WRITE);
- if (!is_create && is_readable())
- open_plan.push_back(OPEN_FLAG_READ);
- if (is_create && is_writeable() && is_creatable())
- open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ if (!is_create)
+ {
+ if (is_writeable())
+ open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE);
+ if (is_readable())
+ open_plan.push_back(OPEN_FLAG_READ);
+ }
+ else if (is_writeable() && is_creatable())
+ {
+ if (is_readable())
+ open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ else
+ open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ }
return open_plan;
}
@@ -772,9 +737,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp
// load_software - software image loading
//-------------------------------------------------
-bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start)
+std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start)
{
- bool retval = false;
+ std::error_condition retval;
int warningcount = 0;
for (const rom_entry *region = start; region; region = rom_next_region(region))
{
@@ -786,7 +751,7 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st
{
const software_info *const swinfo = swlist.find(std::string(swname));
if (!swinfo)
- return false;
+ return image_error::NOSOFTWARE;
if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED)
osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name());
@@ -816,14 +781,31 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st
else
filerr = m_mame_file->open(romp->name());
if (filerr)
+ {
m_mame_file.reset();
+ std::ostringstream msg;
+ util::stream_format(msg,
+ "%s: error opening image file %s: %s (%s:%d)",
+ device().tag(), romp->name(),
+ filerr.message(),
+ filerr.category().name(),
+ filerr.value());
+ if (!searchpath.empty())
+ {
+ msg << " (tried in";
+ for (auto const &path : searchpath)
+ msg << ' ' << path;
+ msg << ')';
+ }
+ osd_printf_error("%s\n", std::move(msg).str());
+ }
warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata()));
if (!filerr)
filerr = util::core_file::open_proxy(*m_mame_file, m_file);
- if (!filerr)
- retval = true;
+ if (filerr)
+ retval = filerr;
break; // load first item for start
}
@@ -841,16 +823,16 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st
// load_internal - core image loading
//-------------------------------------------------
-image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args)
{
+ std::pair<std::error_condition, std::string> err;
+
// first unload the image
unload();
- // clear any possible error messages
- clear_error();
-
// we are now loading
m_is_loading = true;
+ m_sequence_counter++;
// record the filename
set_image_filename(path);
@@ -858,50 +840,47 @@ image_init_result device_image_interface::load_internal(std::string_view path, b
if (core_opens_image_file())
{
// determine open plan
- std::vector<u32> open_plan = determine_open_plan(is_create);
+ std::vector<u32> const open_plan = determine_open_plan(is_create);
// attempt to open the file in various ways
for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++)
{
// open the file
- m_err = load_image_by_path(*iter, path);
- if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied))
- goto done;
+ err.first = load_image_by_path(*iter, path);
+ if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied))
+ break;
}
// did we fail to find the file?
- if (!m_file)
- {
- m_err = std::errc::no_such_file_or_directory;
- goto done;
- }
+ if (!err.first && !m_file)
+ err.first = std::errc::no_such_file_or_directory;
}
- // call device load or create
- m_create_format = create_format;
- m_create_args = create_args;
-
- if (!init_phase())
+ if (!err.first)
{
- m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL;
- if (m_err)
- goto done;
+ // call device load or create
+ m_create_format = create_format;
+ m_create_args = create_args;
+
+ if (!init_phase())
+ err = finish_load();
}
- // success!
-done:
- if (m_err)
+ if (err.first)
{
- if (!init_phase())
- {
- if (device().machine().phase() == machine_phase::RUNNING)
- device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error());
- else
- osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error());
- }
+ osd_printf_error(
+ !err.second.empty()
+ ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n")
+ : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"),
+ path,
+ err.second,
+ err.first.category().name(),
+ err.first.value(),
+ err.first.message());
clear();
}
- return m_err ? image_init_result::FAIL : image_init_result::PASS;
+
+ return err;
}
@@ -909,13 +888,13 @@ done:
// load - load an image into MAME
//-------------------------------------------------
-image_init_result device_image_interface::load(std::string_view path)
+std::pair<std::error_condition, std::string> device_image_interface::load(std::string_view path)
{
// is this a reset on load item?
if (is_reset_on_load() && !init_phase())
{
reset_and_load(path);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
return load_internal(path, false, 0, nullptr);
@@ -926,26 +905,26 @@ image_init_result device_image_interface::load(std::string_view path)
// load_software - loads a softlist item by name
//-------------------------------------------------
-image_init_result device_image_interface::load_software(std::string_view software_identifier)
+std::pair<std::error_condition, std::string> device_image_interface::load_software(std::string_view software_identifier)
{
// Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load
if (is_reset_on_load() && !init_phase())
{
reset_and_load(software_identifier);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
// Prepare to load
unload();
- clear_error();
m_is_loading = true;
// Check if there's a software list defined for this device and use that if we're not creating an image
- bool softload = load_software_part(software_identifier);
- if (!softload)
+ std::pair<std::error_condition, std::string> err;
+ err.first = load_software_part(software_identifier);
+ if (err.first)
{
m_is_loading = false;
- return image_init_result::FAIL;
+ return err;
}
// set up softlist stuff
@@ -955,9 +934,10 @@ image_init_result device_image_interface::load_software(std::string_view softwar
m_image_name = m_full_software_name;
m_basename = m_full_software_name;
m_basename_noext = m_full_software_name;
- m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr
- ? std::string(core_filename_extract_extension(m_mame_file->filename(), true))
- : "";
+ if (use_software_list_file_extension_for_filetype() && m_mame_file)
+ m_filetype = core_filename_extract_extension(m_mame_file->filename(), true);
+ else
+ m_filetype.clear();
// Copy some image information when we have been loaded through a software list
software_info &swinfo = m_software_part_ptr->info();
@@ -967,16 +947,31 @@ image_init_result device_image_interface::load_software(std::string_view softwar
fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n");
// set file type
- std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr)
+ std::string filename = (m_mame_file && m_mame_file->filename())
? m_mame_file->filename()
: "";
m_filetype = core_filename_extract_extension(filename, true);
// call finish_load if necessary
- if (init_phase() == false && (finish_load() != image_init_result::PASS))
- return image_init_result::FAIL;
+ if (!init_phase())
+ {
+ err = finish_load();
+ if (err.first)
+ {
+ osd_printf_error(
+ !err.second.empty()
+ ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n"
+ : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n",
+ software_identifier,
+ err.second,
+ err.first.category().name(),
+ err.first.value(),
+ err.first.message());
+ clear();
+ }
+ }
- return image_init_result::PASS;
+ return err;
}
@@ -985,53 +980,38 @@ image_init_result device_image_interface::load_software(std::string_view softwar
// from core
//-------------------------------------------------
-image_init_result device_image_interface::finish_load()
+std::pair<std::error_condition, std::string> device_image_interface::finish_load()
{
- image_init_result err = image_init_result::PASS;
+ std::pair<std::error_condition, std::string> err;
if (m_is_loading)
{
- if (!image_checkhash())
- {
- m_err = image_error::INVALIDIMAGE;
- err = image_init_result::FAIL;
- }
+ err.first = image_checkhash();
- if (err == image_init_result::PASS)
+ if (!err.first)
{
if (m_created)
- {
err = call_create(m_create_format, m_create_args);
- if (err != image_init_result::PASS)
- {
- if (!m_err)
- m_err = image_error::UNSPECIFIED;
- }
- }
else
- {
- // using device load
- err = call_load();
- if (err != image_init_result::PASS)
- {
- if (!m_err)
- m_err = image_error::UNSPECIFIED;
- }
- }
+ err = call_load(); // using device load
}
}
+
m_is_loading = false;
m_create_format = 0;
m_create_args = nullptr;
+ if (!err.first)
+ m_media_change_notifier(media_change_event::LOADED);
+
return err;
}
//-------------------------------------------------
-// create - create a image
+// create - create an image
//-------------------------------------------------
-image_init_result device_image_interface::create(std::string_view path)
+std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path)
{
return create(path, nullptr, nullptr);
}
@@ -1041,13 +1021,14 @@ image_init_result device_image_interface::create(std::string_view path)
// create - create a image
//-------------------------------------------------
-image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args)
{
int format_index = 0;
int cnt = 0;
for (auto &format : m_formatlist)
{
- if (create_format == format.get()) {
+ if (create_format == format.get())
+ {
format_index = cnt;
break;
}
@@ -1081,7 +1062,7 @@ void device_image_interface::reset_and_load(std::string_view path)
// to an image
//-------------------------------------------------
-void device_image_interface::clear()
+void device_image_interface::clear() noexcept
{
m_mame_file.reset();
m_file.reset();
@@ -1101,6 +1082,8 @@ void device_image_interface::clear()
m_software_list_name.clear();
m_hash.reset();
+
+ m_sequence_counter++;
}
@@ -1112,10 +1095,15 @@ void device_image_interface::unload()
{
if (is_loaded() || loaded_through_softlist())
{
+ m_sequence_counter++;
call_unload();
+ clear();
+ m_media_change_notifier(media_change_event::UNLOADED);
+ }
+ else
+ {
+ clear(); // just to make sure everything is reset
}
- clear();
- clear_error();
}
@@ -1137,12 +1125,10 @@ const util::option_guide &device_image_interface::create_option_guide() const
void device_image_interface::update_names()
{
- const char *inst_name = custom_instance_name();
- const char *brief_name = custom_brief_instance_name();
- if (inst_name == nullptr)
- inst_name = device_typename(image_type());
- if (brief_name == nullptr)
- brief_name = device_brieftypename(image_type());
+ const char *inst_name = image_type_name();
+ const char *brief_name = image_brief_type_name();
+ assert(inst_name != nullptr);
+ assert(brief_name != nullptr);
// count instances of the general image type, or device type if custom
int count = 0;
@@ -1151,19 +1137,21 @@ void device_image_interface::update_names()
{
if (this == &image)
index = count;
- const char *other_name = image.custom_instance_name();
- if (!other_name)
- other_name = device_typename(image.image_type());
+ const char *other_name = image.image_type_name();
+ const char *other_brief_name = image.image_brief_type_name();
+ assert(other_name != nullptr);
+ assert(other_brief_name != nullptr);
- if (other_name == inst_name || !strcmp(other_name, inst_name))
+ if (other_name == inst_name || !strcmp(other_name, inst_name) ||
+ other_brief_name == brief_name || !strcmp(other_brief_name, brief_name))
count++;
}
- m_canonical_instance_name = string_format("%s%d", inst_name, index + 1);
+ m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1);
if (count > 1)
{
m_instance_name = m_canonical_instance_name;
- m_brief_instance_name = string_format("%s%d", brief_name, index + 1);
+ m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1);
}
else
{
@@ -1256,7 +1244,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c
// sw_info and sw_part are also set.
//-------------------------------------------------
-bool device_image_interface::load_software_part(std::string_view identifier)
+std::error_condition device_image_interface::load_software_part(std::string_view identifier)
{
// if no match has been found, we suggest similar shortnames
software_list_device *swlist;
@@ -1264,14 +1252,14 @@ bool device_image_interface::load_software_part(std::string_view identifier)
if (m_software_part_ptr == nullptr)
{
software_list_device::display_matches(device().machine().config(), image_interface(), identifier);
- return false;
+ return image_error::NOSOFTWARE;
}
// Load the software part
const std::string &swname = m_software_part_ptr->info().shortname();
const rom_entry *start_entry = m_software_part_ptr->romdata().data();
const software_list_loader &loader = get_software_list_loader();
- bool result = loader.load_software(*this, *swlist, swname, start_entry);
+ std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry);
// check compatibility
switch (swlist->is_compatible(*m_software_part_ptr))
diff --git a/src/emu/diimage.h b/src/emu/diimage.h
index 67d20c43402..aa9c991c955 100644
--- a/src/emu/diimage.h
+++ b/src/emu/diimage.h
@@ -17,11 +17,13 @@
#ifndef MAME_EMU_DIIMAGE_H
#define MAME_EMU_DIIMAGE_H
+#include "notifier.h"
#include "utilfwd.h"
#include <memory>
#include <string>
#include <system_error>
+#include <utility>
#include <vector>
@@ -29,39 +31,15 @@
// TYPE DEFINITIONS
//**************************************************************************
-enum iodevice_t
-{
- /* List of all supported devices. Refer to the device by these names only */
- IO_UNKNOWN,
- IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */
- IO_FLOPPY, /* 2 - Floppy Disk unit */
- IO_HARDDISK, /* 3 - Hard Disk unit */
- IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */
- IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */
- IO_PUNCHCARD, /* 6 - Card Puncher/Reader */
- IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */
- IO_PRINTER, /* 8 - Printer device */
- IO_SERIAL, /* 9 - Generic Serial Port */
- IO_PARALLEL, /* 10 - Generic Parallel Port */
- IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */
- IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */
- IO_MEMCARD, /* 13 - Memory card */
- IO_CDROM, /* 14 - optical CD-ROM disc */
- IO_MAGTAPE, /* 15 - Magnetic tape */
- IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */
- IO_MIDIIN, /* 17 - MIDI In port */
- IO_MIDIOUT, /* 18 - MIDI Out port */
- IO_PICTURE, /* 19 - A single-frame image */
- IO_VIDEO, /* 20 - A video file */
- IO_COUNT /* 21 - Total Number of IO_devices for searching */
-};
-
enum class image_error : int
{
INTERNAL = 1,
UNSUPPORTED,
INVALIDIMAGE,
+ INVALIDLENGTH,
ALREADYOPEN,
+ NOSOFTWARE,
+ BADSOFTWARE,
UNSPECIFIED
};
@@ -69,13 +47,6 @@ const std::error_category &image_category() noexcept;
inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); }
namespace std { template <> struct is_error_condition_enum<image_error> : public std::true_type { }; }
-struct image_device_type_info
-{
- iodevice_t m_type;
- const char *m_name;
- const char *m_shortname;
-};
-
class image_device_format
{
public:
@@ -95,66 +66,56 @@ private:
};
-enum class image_init_result { PASS, FAIL };
-enum class image_verify_result { PASS, FAIL };
-
-//**************************************************************************
-// MACROS
-//**************************************************************************
-
-#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image)
-#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name)
-
-#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image)
-#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name)
-
-
// ======================> device_image_interface
// class representing interface-specific live image
class device_image_interface : public device_interface
{
public:
- typedef device_delegate<image_init_result (device_image_interface &)> load_delegate;
- typedef device_delegate<void (device_image_interface &)> unload_delegate;
+ enum class media_change_event
+ {
+ LOADED,
+ UNLOADED
+ };
- typedef std::vector<std::unique_ptr<image_device_format>> formatlist_type;
+ using formatlist_type = std::vector<std::unique_ptr<image_device_format> >;
// construction/destruction
device_image_interface(const machine_config &mconfig, device_t &device);
virtual ~device_image_interface();
- static const char *device_typename(iodevice_t type);
- static const char *device_brieftypename(iodevice_t type);
- static iodevice_t device_typeid(const char *name);
-
- virtual image_init_result call_load() { return image_init_result::PASS; }
- virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; }
+ virtual std::pair<std::error_condition, std::string> call_load() { return std::make_pair(std::error_condition(), std::string()); }
+ virtual std::pair<std::error_condition, std::string> call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); }
virtual void call_unload() { }
virtual std::string call_display() { return std::string(); }
virtual u32 unhashed_header_length() const noexcept { return 0; }
virtual bool core_opens_image_file() const noexcept { return true; }
- virtual iodevice_t image_type() const noexcept = 0;
+ virtual bool image_is_chd_type() const noexcept { return false; }
virtual bool is_readable() const noexcept = 0;
virtual bool is_writeable() const noexcept = 0;
virtual bool is_creatable() const noexcept = 0;
- virtual bool must_be_loaded() const noexcept = 0;
virtual bool is_reset_on_load() const noexcept = 0;
- virtual bool support_command_line_image_creation() const noexcept;
+ virtual bool support_command_line_image_creation() const noexcept { return false; }
virtual const char *image_interface() const noexcept { return nullptr; }
virtual const char *file_extensions() const noexcept = 0;
virtual const util::option_guide &create_option_guide() const;
- virtual const char *custom_instance_name() const noexcept { return nullptr; }
- virtual const char *custom_brief_instance_name() const noexcept { return nullptr; }
+ virtual const char *image_type_name() const noexcept = 0;
+ virtual const char *image_brief_type_name() const noexcept = 0;
+
+ // Set block device image regions for arcade systems
+ void add_region(std::string name, bool is_default = false);
+ bool has_preset_images() const;
+ bool has_preset_images_selection() const;
+ std::vector<std::string> preset_images_list() const;
+ int current_preset_image_id() const;
+ void switch_preset_image(int id);
+ chd_file *current_preset_image_chd() const;
+ void check_preset_images();
const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; }
- const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept;
+ const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept;
const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); }
- std::string_view error();
- void seterror(std::error_condition err, const char *message);
- void message(const char *format, ...) ATTR_PRINTF(2,3);
-
bool exists() const noexcept { return !m_image_name.empty(); }
// get image file path/name
@@ -165,9 +126,15 @@ public:
bool is_filetype(std::string_view candidate_filetype) const;
bool is_open() const noexcept { return bool(m_file); }
- util::core_file &image_core_file() const noexcept { return *m_file; }
+ util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; }
bool is_readonly() const noexcept { return m_readonly; }
+ u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc
+ util::notifier_subscription add_media_change_notifier(delegate<void (media_change_event)> &&n);
+ template <typename T>
+ util::notifier_subscription add_media_change_notifier(T &&n)
+ { return add_media_change_notifier(delegate<void (media_change_event)>(std::forward<T>(n))); }
+
// image file I/O wrappers
// TODO: move away from using these and let implementations use the I/O interface directly
// FIXME: don't swallow errors
@@ -181,15 +148,13 @@ public:
u32 fread(void *buffer, u32 length)
{
check_for_file();
- size_t actual;
- m_file->read(buffer, length, actual);
+ auto const [err, actual] = read(*m_file, buffer, length);
return actual;
}
u32 fwrite(const void *buffer, u32 length)
{
check_for_file();
- size_t actual;
- m_file->write(buffer, length, actual);
+ auto const [err, actual] = write(*m_file, buffer, length);
return actual;
}
std::error_condition fseek(s64 offset, int whence)
@@ -204,32 +169,6 @@ public:
m_file->tell(result);
return result;
}
- int fgetc()
- {
- char ch;
- if (fread(&ch, 1) != 1)
- ch = '\0';
- return ch;
- }
- char *fgets(char *buffer, u32 length)
- {
- check_for_file();
- return m_file->gets(buffer, length);
- }
- bool image_feof()
- {
- check_for_file();
- return m_file->eof();
- }
- const void *ptr()
- {
- check_for_file();
- return m_file->buffer();
- }
-
- // allocate and read into buffers
- u32 fread(std::unique_ptr<u8 []> &ptr, u32 length) { ptr = std::make_unique<u8 []>(length); return fread(ptr.get(), length); }
- u32 fread(std::unique_ptr<u8 []> &ptr, u32 length, offs_t offset) { ptr = std::make_unique<u8 []>(length); return fread(ptr.get() + offset, length - offset); }
// access to software list item information
const software_info *software_entry() const noexcept;
@@ -243,67 +182,62 @@ public:
const std::string &working_directory() const { return m_working_directory; }
// access to software list properties and ROM data areas
- u8 *get_software_region(const char *tag);
- u32 get_software_region_length(const char *tag);
- const char *get_feature(const char *feature_name) const;
- bool load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr);
+ u8 *get_software_region(std::string_view tag);
+ u32 get_software_region_length(std::string_view tag);
+ const char *get_feature(std::string_view feature_name) const;
+ std::error_condition load_software_region(std::string_view tag, std::unique_ptr<u8[]> &ptr);
u32 crc();
- util::hash_collection& hash() { return m_hash; }
- util::hash_collection calculate_hash_on_file(util::core_file &file) const;
+ util::hash_collection &hash() { return m_hash; }
+ util::hash_collection calculate_hash_on_file(util::random_read &file) const;
void battery_load(void *buffer, int length, int fill);
void battery_load(void *buffer, int length, const void *def_buffer);
void battery_save(const void *buffer, int length);
- const char *image_type_name() const { return device_typename(image_type()); }
-
const std::string &instance_name() const { return m_instance_name; }
const std::string &brief_instance_name() const { return m_brief_instance_name; }
const std::string &canonical_instance_name() const { return m_canonical_instance_name; }
- bool uses_file_extension(const char *file_extension) const;
const formatlist_type &formatlist() const { return m_formatlist; }
// loads an image file
- image_init_result load(std::string_view path);
+ std::pair<std::error_condition, std::string> load(std::string_view path);
// loads a softlist item by name
- image_init_result load_software(std::string_view software_identifier);
+ std::pair<std::error_condition, std::string> load_software(std::string_view software_identifier);
- image_init_result finish_load();
+ std::pair<std::error_condition, std::string> finish_load();
void unload();
- image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args);
- image_init_result create(std::string_view path);
- bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry);
+ std::pair<std::error_condition, std::string> create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args);
+ std::pair<std::error_condition, std::string> create(std::string_view path);
+ std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry);
std::error_condition reopen_for_write(std::string_view path);
- void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; }
+ void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; }
+ void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; }
bool user_loadable() const noexcept { return m_user_loadable; }
+ bool must_be_loaded() const noexcept { return m_must_be_loaded; }
bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; }
const std::string &full_software_name() const noexcept { return m_full_software_name; }
protected:
- // interface-level overrides
+ // device_interface implementation
virtual void interface_config_complete() override;
virtual const software_list_loader &get_software_list_loader() const;
- virtual const bool use_software_list_file_extension_for_filetype() const { return false; }
+ virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; }
- image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args);
std::error_condition load_image_by_path(u32 open_flags, std::string_view path);
- void clear();
- bool is_loaded() const { return m_file != nullptr; }
+ bool is_loaded() const noexcept { return m_file != nullptr; }
- void set_image_filename(std::string_view filename);
-
- void clear_error();
+ void set_image_tag();
void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); }
void make_readonly() noexcept { m_readonly = true; }
- bool image_checkhash();
+ std::error_condition image_checkhash();
const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const;
std::string software_get_default_slot(std::string_view default_card_slot) const;
@@ -311,17 +245,21 @@ protected:
void add_format(std::unique_ptr<image_device_format> &&format);
void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec);
- // derived class overrides
+private:
+ std::vector<u32> determine_open_plan(bool is_create);
+ void update_names();
+ void set_image_filename(std::string_view filename);
+ void clear() noexcept;
+ std::pair<std::error_condition, std::string> load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args);
+ std::error_condition load_software_part(std::string_view identifier);
- // configuration
- static const image_device_type_info *find_device_type(iodevice_t type);
- static const image_device_type_info m_device_info_array[];
+ bool init_phase() const;
+ static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types);
- // error related info
- std::error_condition m_err;
- std::string m_err_message;
+ // loads an image or software items and resets - called internally when we
+ // load an is_reset_on_load() item
+ void reset_and_load(std::string_view path);
-private:
// variables that are only non-zero when an image is mounted
util::core_file::ptr m_file;
std::unique_ptr<emu_file> m_mame_file;
@@ -330,29 +268,27 @@ private:
std::string m_basename_noext;
std::string m_filetype;
+ // preset images regions
+ std::vector<std::string> m_possible_preset_regions;
+ std::vector<chd_file *> m_preset_images;
+ int m_default_region, m_current_region;
+
// Software information
std::string m_full_software_name;
const software_part *m_software_part_ptr;
std::string m_software_list_name;
- std::vector<u32> determine_open_plan(bool is_create);
- void update_names();
- bool load_software_part(std::string_view identifier);
-
- bool init_phase() const;
- static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types);
-
- // loads an image or software items and resets - called internally when we
- // load an is_reset_on_load() item
- void reset_and_load(std::string_view path);
-
// creation info
formatlist_type m_formatlist;
// working directory; persists across mounts
std::string m_working_directory;
+ // to notify interested parties when media changes
+ util::notifier<media_change_event> m_media_change_notifier;
+
// flags
+ u32 m_sequence_counter;
bool m_readonly;
bool m_created;
@@ -370,6 +306,8 @@ private:
// we want to disable command line cart loading...
bool m_user_loadable;
+ bool m_must_be_loaded;
+
bool m_is_loading;
bool m_is_reset_and_loading;
@@ -378,4 +316,4 @@ private:
// iterator
typedef device_interface_enumerator<device_image_interface> image_interface_enumerator;
-#endif /* MAME_EMU_DIIMAGE_H */
+#endif // MAME_EMU_DIIMAGE_H
diff --git a/src/emu/dimemory.cpp b/src/emu/dimemory.cpp
index aa438fd22c0..81958b4f571 100644
--- a/src/emu/dimemory.cpp
+++ b/src/emu/dimemory.cpp
@@ -66,9 +66,10 @@ void device_memory_interface::set_addrmap(int spacenum, address_map_constructor
// translation is supported
//-------------------------------------------------
-bool device_memory_interface::memory_translate(int spacenum, int intention, offs_t &address)
+bool device_memory_interface::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
{
// by default it maps directly
+ target_space = &space(spacenum);
return true;
}
diff --git a/src/emu/dimemory.h b/src/emu/dimemory.h
index 119ec9bc6f9..14cd4d48ae2 100644
--- a/src/emu/dimemory.h
+++ b/src/emu/dimemory.h
@@ -19,34 +19,6 @@
#include <type_traits>
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// Translation intentions
-constexpr int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
-constexpr int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
-constexpr int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
-
-constexpr int TRANSLATE_READ = 0; // translate for read
-constexpr int TRANSLATE_WRITE = 1; // translate for write
-constexpr int TRANSLATE_FETCH = 2; // translate for instruction fetch
-constexpr int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
-constexpr int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
-constexpr int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
-constexpr int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
-constexpr int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
-constexpr int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
-
-
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> device_memory_interface
-
class device_memory_interface : public device_interface
{
friend class device_scheduler;
@@ -57,6 +29,13 @@ class device_memory_interface : public device_interface
template <typename T, typename U> using is_unrelated_interface = std::bool_constant<emu::detail::is_device_interface<T>::value && !is_related_class<T, U>::value >;
public:
+ // Translation intentions for the translate() call
+ enum {
+ TR_READ,
+ TR_WRITE,
+ TR_FETCH
+ };
+
// construction/destruction
device_memory_interface(const machine_config &mconfig, device_t &device);
virtual ~device_memory_interface();
@@ -85,7 +64,7 @@ public:
address_space &space(int index = 0) const { assert(index >= 0 && index < int(m_addrspace.size()) && m_addrspace[index]); return *m_addrspace[index]; }
// address translation
- bool translate(int spacenum, int intention, offs_t &address) { return memory_translate(spacenum, intention, address); }
+ bool translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { return memory_translate(spacenum, intention, address, target_space); }
// deliberately ambiguous functions; if you have the memory interface
// just use it
@@ -110,7 +89,7 @@ protected:
virtual space_config_vector memory_space_config() const = 0;
// optional operation overrides
- virtual bool memory_translate(int spacenum, int intention, offs_t &address);
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space);
// interface-level overrides
virtual void interface_config_complete() override;
diff --git a/src/emu/dinetwork.cpp b/src/emu/dinetwork.cpp
index 69cc7e9235f..bbc5ee3054d 100644
--- a/src/emu/dinetwork.cpp
+++ b/src/emu/dinetwork.cpp
@@ -1,14 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Carl, Miodrag Milanovic
+
#include "emu.h"
+#include "dinetwork.h"
+
#include "osdnet.h"
-device_network_interface::device_network_interface(const machine_config &mconfig, device_t &device, float bandwidth)
+#include <algorithm>
+
+
+device_network_interface::device_network_interface(const machine_config &mconfig, device_t &device, u32 bandwidth, u32 mtu)
: device_interface(device, "network")
+ , m_poll_timer(nullptr)
+ , m_send_timer(nullptr)
+ , m_recv_timer(nullptr)
{
- m_promisc = false;
- m_bandwidth = bandwidth;
- set_mac("\0\0\0\0\0\0");
+ // Convert to Mibps to Bps
+ m_bandwidth = bandwidth << (20 - 3);
+ m_mtu = mtu;
m_intf = -1;
m_loopback_control = false;
}
@@ -17,15 +26,23 @@ device_network_interface::~device_network_interface()
{
}
-void device_network_interface::interface_pre_start()
+void device_network_interface::interface_post_start()
{
+ m_poll_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::poll_device), this));
m_send_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::send_complete), this));
m_recv_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::recv_complete), this));
+
+ device().save_item(NAME(m_loopback_control));
}
-void device_network_interface::interface_post_start()
+void device_network_interface::interface_post_load()
{
- device().save_item(NAME(m_loopback_control));
+ if (!m_dev)
+ m_poll_timer->reset();
+ else if (!m_loopback_control && !m_recv_timer->enabled())
+ start_net_device();
+ else
+ stop_net_device();
}
int device_network_interface::send(u8 *buf, int len, int fcs)
@@ -44,7 +61,7 @@ int device_network_interface::send(u8 *buf, int len, int fcs)
if (result)
{
// schedule receive complete callback
- m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result);
+ m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
}
}
else if (m_dev)
@@ -56,11 +73,30 @@ int device_network_interface::send(u8 *buf, int len, int fcs)
}
// schedule transmit complete callback
- m_send_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result);
+ m_send_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
return result;
}
+TIMER_CALLBACK_MEMBER(device_network_interface::poll_device)
+{
+ m_dev->poll();
+}
+
+void device_network_interface::start_net_device()
+{
+ // Set device polling time to transfer time for one MTU
+ m_dev->start();
+ const attotime interval = attotime::from_hz(m_bandwidth / m_mtu);
+ m_poll_timer->adjust(attotime::zero, 0, interval);
+}
+
+void device_network_interface::stop_net_device()
+{
+ m_poll_timer->reset();
+ m_dev->stop();
+}
+
TIMER_CALLBACK_MEMBER(device_network_interface::send_complete)
{
send_complete_cb(param);
@@ -81,10 +117,10 @@ void device_network_interface::recv_cb(u8 *buf, int len)
{
// stop receiving more data from the network
if (m_dev)
- m_dev->stop();
+ stop_net_device();
// schedule receive complete callback
- m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth * 1'000'000 / 8), result);
+ m_recv_timer->adjust(attotime::from_ticks(len, m_bandwidth), result);
}
}
@@ -94,27 +130,36 @@ TIMER_CALLBACK_MEMBER(device_network_interface::recv_complete)
// start receiving data from the network again
if (m_dev && !m_loopback_control)
- m_dev->start();
+ start_net_device();
}
void device_network_interface::set_promisc(bool promisc)
{
m_promisc = promisc;
- if(m_dev) m_dev->set_promisc(promisc);
+ if (m_dev)
+ m_dev->set_promisc(promisc);
}
-void device_network_interface::set_mac(const char *mac)
+void device_network_interface::set_mac(const u8 *mac)
{
- memcpy(m_mac, mac, 6);
- if(m_dev) m_dev->set_mac(m_mac);
+ std::copy_n(mac, std::size(m_mac), std::begin(m_mac));
+ if (m_dev)
+ m_dev->set_mac(&m_mac[0]);
}
void device_network_interface::set_interface(int id)
{
- if(m_dev)
- m_dev->stop();
- m_dev.reset(open_netdev(id, this, (int)(m_bandwidth*1000000/8.0f/1500)));
- if(!m_dev) {
+ if (m_dev)
+ stop_net_device();
+
+ m_dev.reset(open_netdev(id, *this));
+ if (m_dev)
+ {
+ if (!m_loopback_control)
+ start_net_device();
+ }
+ else
+ {
device().logerror("Network interface %d not found\n", id);
id = -1;
}
@@ -131,8 +176,8 @@ void device_network_interface::set_loopback(bool loopback)
if (m_dev)
{
if (loopback)
- m_dev->stop();
+ stop_net_device();
else if (!m_recv_timer->enabled())
- m_dev->start();
+ start_net_device();
}
}
diff --git a/src/emu/dinetwork.h b/src/emu/dinetwork.h
index 99909e93905..522f8b8d041 100644
--- a/src/emu/dinetwork.h
+++ b/src/emu/dinetwork.h
@@ -3,30 +3,31 @@
#ifndef MAME_EMU_DINETWORK_H
#define MAME_EMU_DINETWORK_H
-class osd_netdev;
+#include "interface/nethandler.h"
-class device_network_interface : public device_interface
+
+class osd_network_device;
+
+class device_network_interface : public device_interface, public osd::network_handler
{
public:
- device_network_interface(const machine_config &mconfig, device_t &device, float bandwidth);
+ device_network_interface(const machine_config &mconfig, device_t &device, u32 bandwidth, u32 mtu = 1500);
virtual ~device_network_interface();
- void interface_pre_start() override;
- void interface_post_start() override;
+ void interface_post_start() override ATTR_COLD;
+ void interface_post_load() override ATTR_COLD;
- void set_interface(int id);
+ void set_interface(int id) ATTR_COLD;
void set_promisc(bool promisc);
- void set_mac(const char *mac);
+ void set_mac(const u8 *mac);
void set_loopback(bool loopback);
- const char *get_mac() const { return m_mac; }
- bool get_promisc() const { return m_promisc; }
int get_interface() const { return m_intf; }
int send(u8 *buf, int len, int fcs = 0);
// TODO: de-virtualise this when existing devices implement delayed receive
- virtual void recv_cb(u8 *buf, int len);
+ virtual void recv_cb(u8 *buf, int len) override;
// delayed transmit/receive handlers
virtual void send_complete_cb(int result) {}
@@ -34,16 +35,25 @@ public:
virtual void recv_complete_cb(int result) {}
protected:
- TIMER_CALLBACK_MEMBER(send_complete);
- TIMER_CALLBACK_MEMBER(recv_complete);
+ bool has_net_device() const noexcept { return bool(m_dev); }
- bool m_promisc;
- char m_mac[6];
- float m_bandwidth;
- std::unique_ptr<osd_netdev> m_dev;
+ // bandwidth in bytes per second
+ u32 m_bandwidth;
+ // maximum transmission unit, used for device polling time
+ u32 m_mtu;
int m_intf;
bool m_loopback_control;
+private:
+ TIMER_CALLBACK_MEMBER(poll_device);
+ TIMER_CALLBACK_MEMBER(send_complete);
+ TIMER_CALLBACK_MEMBER(recv_complete);
+
+ void start_net_device();
+ void stop_net_device();
+
+ std::unique_ptr<osd_network_device> m_dev;
+ emu_timer *m_poll_timer;
emu_timer *m_send_timer;
emu_timer *m_recv_timer;
};
diff --git a/src/emu/dinvram.cpp b/src/emu/dinvram.cpp
index c2ba7408849..7a3ec7f658f 100644
--- a/src/emu/dinvram.cpp
+++ b/src/emu/dinvram.cpp
@@ -20,8 +20,9 @@
// device_nvram_interface - constructor
//-------------------------------------------------
-device_nvram_interface::device_nvram_interface(const machine_config &mconfig, device_t &device)
+device_nvram_interface::device_nvram_interface(const machine_config &mconfig, device_t &device, bool backup_enabled)
: device_interface(device, "nvram")
+ , m_backup_enabled(backup_enabled)
{
}
diff --git a/src/emu/dinvram.h b/src/emu/dinvram.h
index fb02a9c6e14..0efcc9d1054 100644
--- a/src/emu/dinvram.h
+++ b/src/emu/dinvram.h
@@ -30,21 +30,28 @@ class device_nvram_interface : public device_interface
{
public:
// construction/destruction
- device_nvram_interface(const machine_config &mconfig, device_t &device);
+ device_nvram_interface(const machine_config &mconfig, device_t &device, bool backup_enabled = true);
virtual ~device_nvram_interface();
+ // configuration
+ void nvram_enable_backup(bool enabled) { assert(!device().started()); m_backup_enabled = enabled; }
+
// public accessors... for now
void nvram_reset() { nvram_default(); }
- void nvram_load(emu_file &file) { nvram_read(file); }
- void nvram_save(emu_file &file) { nvram_write(file); }
- bool nvram_can_save() { return nvram_can_write(); }
+ bool nvram_load(util::read_stream &file) { return nvram_read(file); }
+ bool nvram_save(util::write_stream &file) { return nvram_write(file); }
+ bool nvram_backup_enabled() const noexcept { return m_backup_enabled; }
+ bool nvram_can_save() const { return m_backup_enabled && nvram_can_write(); }
protected:
// derived class overrides
virtual void nvram_default() = 0;
- virtual void nvram_read(emu_file &file) = 0;
- virtual void nvram_write(emu_file &file) = 0;
- virtual bool nvram_can_write() { return true; }
+ virtual bool nvram_read(util::read_stream &file) = 0;
+ virtual bool nvram_write(util::write_stream &file) = 0;
+ virtual bool nvram_can_write() const { return true; }
+
+private:
+ bool m_backup_enabled;
};
// iterator
diff --git a/src/emu/dipalette.h b/src/emu/dipalette.h
index 1e84b2848e8..5d7f6b30506 100644
--- a/src/emu/dipalette.h
+++ b/src/emu/dipalette.h
@@ -43,8 +43,8 @@ class device_palette_interface : public device_interface
public:
// getters
- u32 entries() const { return palette_entries(); }
- u32 indirect_entries() const { return palette_indirect_entries(); }
+ u32 entries() const noexcept { return palette_entries(); }
+ u32 indirect_entries() const noexcept { return palette_indirect_entries(); }
palette_t *palette() const { return m_palette; }
const pen_t &pen(int index) const { return m_pens[index]; }
const pen_t *pens() const { return m_pens; }
@@ -53,8 +53,8 @@ public:
double pen_contrast(pen_t pen) const { return m_palette->entry_contrast(pen); }
pen_t black_pen() const { return m_black_pen; }
pen_t white_pen() const { return m_white_pen; }
- bool shadows_enabled() const { return palette_shadows_enabled(); }
- bool hilights_enabled() const { return palette_hilights_enabled(); }
+ bool shadows_enabled() const noexcept { return palette_shadows_enabled(); }
+ bool hilights_enabled() const noexcept { return palette_hilights_enabled(); }
// setters
void set_pen_color(pen_t pen, rgb_t rgb) { m_palette->entry_set_color(pen, rgb); }
@@ -92,10 +92,10 @@ protected:
virtual void interface_post_stop() override;
// configuration-related overrides
- virtual u32 palette_entries() const = 0;
- virtual u32 palette_indirect_entries() const { return 0; }
- virtual bool palette_shadows_enabled() const { return false; }
- virtual bool palette_hilights_enabled() const { return false; }
+ virtual u32 palette_entries() const noexcept = 0;
+ virtual u32 palette_indirect_entries() const noexcept { return 0; }
+ virtual bool palette_shadows_enabled() const noexcept { return false; }
+ virtual bool palette_hilights_enabled() const noexcept { return false; }
private:
// internal helpers
diff --git a/src/emu/dipty.h b/src/emu/dipty.h
index 9fc1ddbc7e1..d2e92f14969 100644
--- a/src/emu/dipty.h
+++ b/src/emu/dipty.h
@@ -27,7 +27,7 @@ public:
bool is_open() const;
- ssize_t read(u8 *rx_chars , size_t count) const;
+ ssize_t read(u8 *rx_chars, size_t count) const;
void write(u8 tx_char) const;
bool is_slave_connected() const;
diff --git a/src/emu/dirom.h b/src/emu/dirom.h
index 8243400c547..72d844f8b0e 100644
--- a/src/emu/dirom.h
+++ b/src/emu/dirom.h
@@ -22,6 +22,7 @@ public:
template <typename... T> void set_map(T &&... args) { set_addrmap(0, std::forward<T>(args)...); }
template <typename T> void set_device_rom_tag(T &&tag) { m_rom_region.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_space(T &&tag, int spacenum) { m_rom_space.set_tag(tag, spacenum); }
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); }
@@ -32,13 +33,15 @@ public:
void set_rom_bank(int bank);
protected:
- virtual void rom_bank_updated() = 0;
+ virtual void rom_bank_pre_change() { }
+ virtual void rom_bank_post_change() { }
virtual space_config_vector memory_space_config() const override;
void override_address_width(u8 width);
private:
optional_memory_region m_rom_region;
+ optional_address_space m_rom_space;
address_space_config m_rom_config;
typename memory_access<AddrWidth, DataWidth, AddrShift, Endian>::cache m_rom_cache;
diff --git a/src/emu/dirom.ipp b/src/emu/dirom.ipp
index 24697a0fbba..d41da70a618 100644
--- a/src/emu/dirom.ipp
+++ b/src/emu/dirom.ipp
@@ -9,6 +9,7 @@ template<int AddrWidth, int DataWidth, int AddrShift, endianness_t Endian>
device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::device_rom_interface(const machine_config &mconfig, device_t &device) :
device_memory_interface(mconfig, device),
m_rom_region(device, DEVICE_SELF),
+ m_rom_space(device, finder_base::DUMMY_TAG, -1),
m_rom_config("rom", Endian, 8 << DataWidth, AddrWidth, AddrShift),
m_bank(device, "bank"),
m_cur_bank(-1)
@@ -45,9 +46,10 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::set_rom_bank
}
if (m_cur_bank != bank) {
+ rom_bank_pre_change();
m_cur_bank = bank;
m_bank->set_entry(bank);
- rom_bank_updated();
+ rom_bank_post_change();
}
}
@@ -108,6 +110,11 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::interface_pr
{
device_memory_interface::interface_pre_start();
+ if(m_rom_space.spacenum() != -1) {
+ m_rom_space->cache(m_rom_cache);
+ return;
+ }
+
if(!has_space(0))
return;
diff --git a/src/emu/dirtc.cpp b/src/emu/dirtc.cpp
index f3c61dede01..bf1a9366578 100644
--- a/src/emu/dirtc.cpp
+++ b/src/emu/dirtc.cpp
@@ -30,6 +30,7 @@ static const int DAYS_PER_MONTH[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31,
device_rtc_interface::device_rtc_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "rtc")
+ , m_use_utc(false)
{
}
@@ -78,8 +79,9 @@ void device_rtc_interface::set_time(bool update, int year, int month, int day, i
void device_rtc_interface::set_current_time(const system_time &systime)
{
- set_time(true, systime.local_time.year, systime.local_time.month + 1, systime.local_time.mday, systime.local_time.weekday + 1,
- systime.local_time.hour, systime.local_time.minute, systime.local_time.second);
+ const system_time::full_time &time = m_use_utc ? systime.utc_time : systime.local_time;
+ set_time(true, time.year, time.month + 1, time.mday, time.weekday + 1,
+ time.hour, time.minute, time.second);
}
diff --git a/src/emu/dirtc.h b/src/emu/dirtc.h
index 89a08deb830..e741cfc2628 100644
--- a/src/emu/dirtc.h
+++ b/src/emu/dirtc.h
@@ -47,8 +47,11 @@ public:
device_rtc_interface(const machine_config &mconfig, device_t &device);
virtual ~device_rtc_interface();
+ // use UTC instead of local time when syncing at startup
+ void set_use_utc(bool use_utc) { m_use_utc = use_utc; }
+
void set_time(bool update, int year, int month, int day, int day_of_week, int hour, int minute, int second);
- void set_current_time(const system_time &systime);
+ virtual void set_current_time(const system_time &systime);
bool has_battery() const { return rtc_battery_backed(); }
@@ -72,6 +75,8 @@ protected:
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) = 0;
int m_register[7];
+
+ bool m_use_utc;
};
// iterator
diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp
index 21da108c045..e88aaafc3ca 100644
--- a/src/emu/diserial.cpp
+++ b/src/emu/diserial.cpp
@@ -10,9 +10,9 @@
#include "emu.h"
#include "diserial.h"
-#define LOG_SETUP (1 << 1U)
-#define LOG_TX (1 << 2U)
-#define LOG_RX (1 << 3U)
+#define LOG_SETUP (1U << 1)
+#define LOG_TX (1U << 2)
+#define LOG_RX (1U << 3)
#define VERBOSE (0)
#define LOG_OUTPUT_FUNC device().logerror
@@ -138,7 +138,7 @@ void device_serial_interface::rcv_edge()
}
}
-WRITE_LINE_MEMBER(device_serial_interface::tx_clock_w)
+void device_serial_interface::tx_clock_w(int state)
{
if(state != m_tra_clock_state) {
m_tra_clock_state = state;
@@ -147,7 +147,7 @@ WRITE_LINE_MEMBER(device_serial_interface::tx_clock_w)
}
}
-WRITE_LINE_MEMBER(device_serial_interface::rx_clock_w)
+void device_serial_interface::rx_clock_w(int state)
{
if(state != m_rcv_clock_state) {
m_rcv_clock_state = state;
@@ -156,7 +156,7 @@ WRITE_LINE_MEMBER(device_serial_interface::rx_clock_w)
}
}
-WRITE_LINE_MEMBER(device_serial_interface::clock_w)
+void device_serial_interface::clock_w(int state)
{
tx_clock_w(state);
rx_clock_w(state);
@@ -216,19 +216,21 @@ void device_serial_interface::receive_register_reset()
}
}
-WRITE_LINE_MEMBER(device_serial_interface::rx_w)
+void device_serial_interface::rx_w(int state)
{
m_rcv_line = state;
- if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
+ if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
return;
receive_register_update_bit(state);
- if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
+ if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
{
LOGMASKED(LOG_RX, "Receiver is synchronized\n");
- if(m_rcv_clock && !(m_rcv_rate.is_never()))
- // make start delay just a bit longer to make sure we are called after the sender
- m_rcv_clock->adjust(((m_rcv_rate*3)/2), 0, m_rcv_rate);
- else if(m_start_bit_hack_for_external_clocks)
+ if (m_rcv_clock && !(m_rcv_rate.is_never()))
+ {
+ // make start delay half a cycle longer to make sure we are called after the sender
+ m_rcv_clock->adjust(m_rcv_rate*2, 0, m_rcv_rate);
+ }
+ else if (m_start_bit_hack_for_external_clocks)
m_rcv_bit_count_received--;
}
return;
@@ -261,7 +263,7 @@ void device_serial_interface::receive_register_update_bit(int bit)
/* yes */
if (bit==0)
{
- LOGMASKED(LOG_RX, "Receiver saw start bit\n");
+ LOGMASKED(LOG_RX, "Receiver saw start bit (%s)\n", device().machine().time().to_string());
/* seen start bit! */
/* not waiting for start bit now! */
@@ -274,10 +276,9 @@ void device_serial_interface::receive_register_update_bit(int bit)
}
}
}
- else
- if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
+ else if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
{
- LOGMASKED(LOG_RX, "Received bit %d as %d\n", m_rcv_bit_count_received, bit);
+ LOGMASKED(LOG_RX, "Received bit %d as %d (%s)\n", m_rcv_bit_count_received, bit, device().machine().time().to_string());
m_rcv_bit_count_received++;
if (!bit && (m_rcv_bit_count_received > (m_rcv_bit_count - m_df_stop_bit_count)))
@@ -312,6 +313,7 @@ void device_serial_interface::receive_register_extract()
data &= ~(0xff<<m_df_word_length);
m_rcv_byte_received = data;
+ LOGMASKED(LOG_RX, "Receive data 0x%02x\n", m_rcv_byte_received);
if(m_df_parity == PARITY_NONE)
return;
@@ -437,9 +439,9 @@ u8 device_serial_interface::transmit_register_get_data_bit()
bit = (m_tra_register_data>>(m_tra_bit_count-1-m_tra_bit_count_transmitted))&1;
if (m_tra_bit_count_transmitted < m_df_start_bit_count)
- LOGMASKED(LOG_TX, "Transmitting start bit as %d\n", m_tra_bit_count_transmitted, bit);
+ LOGMASKED(LOG_TX, "Transmitting start bit %d as %d (%s)\n", m_tra_bit_count_transmitted, bit, device().machine().time().to_string());
else
- LOGMASKED(LOG_TX, "Transmitting bit %d as %d\n", m_tra_bit_count_transmitted - m_df_start_bit_count, bit);
+ LOGMASKED(LOG_TX, "Transmitting bit %d as %d (%s)\n", m_tra_bit_count_transmitted - m_df_start_bit_count, bit, device().machine().time().to_string());
m_tra_bit_count_transmitted++;
/* have all bits of this stream formatted byte been sent? */
diff --git a/src/emu/diserial.h b/src/emu/diserial.h
index 62b13c028a1..aab03940206 100644
--- a/src/emu/diserial.h
+++ b/src/emu/diserial.h
@@ -76,10 +76,10 @@ public:
device_serial_interface(const machine_config &mconfig, device_t &device);
virtual ~device_serial_interface();
- DECLARE_WRITE_LINE_MEMBER(rx_w);
- DECLARE_WRITE_LINE_MEMBER(tx_clock_w);
- DECLARE_WRITE_LINE_MEMBER(rx_clock_w);
- DECLARE_WRITE_LINE_MEMBER(clock_w);
+ void rx_w(int state);
+ void tx_clock_w(int state);
+ void rx_clock_w(int state);
+ void clock_w(int state);
protected:
void set_data_frame(int start_bit_count, int data_bit_count, parity_t parity, stop_bits_t stop_bits);
diff --git a/src/emu/dislot.cpp b/src/emu/dislot.cpp
index e30cd41d46f..43d2ed96cdd 100644
--- a/src/emu/dislot.cpp
+++ b/src/emu/dislot.cpp
@@ -8,9 +8,10 @@
#include "emu.h"
#include "emuopts.h"
+
+#include "corestr.h"
+#include "path.h"
#include "zippath.h"
-#include <algorithm>
-#include <cctype>
device_slot_interface::device_slot_interface(const machine_config &mconfig, device_t &device) :
@@ -27,7 +28,7 @@ device_slot_interface::~device_slot_interface()
}
-device_slot_interface::slot_option::slot_option(const char *name, const device_type &devtype, bool selectable) :
+device_slot_interface::slot_option::slot_option(const char *name, device_type devtype, bool selectable) :
m_name(name),
m_devtype(devtype),
m_selectable(selectable),
@@ -46,7 +47,7 @@ void device_slot_interface::interface_validity_check(validity_checker &valid) co
}
-device_slot_interface::slot_option &device_slot_interface::option_add(const char *name, const device_type &devtype)
+device_slot_interface::slot_option &device_slot_interface::option_add(const char *name, device_type devtype)
{
if (!name || !*name)
throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag());
@@ -59,7 +60,7 @@ device_slot_interface::slot_option &device_slot_interface::option_add(const char
}
-device_slot_interface::slot_option &device_slot_interface::option_add_internal(const char *name, const device_type &devtype)
+device_slot_interface::slot_option &device_slot_interface::option_add_internal(const char *name, device_type devtype)
{
if (!name || !*name)
throw emu_fatalerror("slot '%s' attempt to add option without name\n", device().tag());
@@ -72,6 +73,42 @@ device_slot_interface::slot_option &device_slot_interface::option_add_internal(c
}
+device_slot_interface::slot_option &device_slot_interface::option_replace(const char *name, device_type devtype)
+{
+ if (!name || !*name)
+ throw emu_fatalerror("slot '%s' attempt to replace option without name\n", device().tag());
+
+ auto search = m_options.find(name);
+ if (search == m_options.end())
+ throw emu_fatalerror("slot '%s' attempt to replace nonexistent option '%s'\n", device().tag(), name);
+
+ return (search->second = std::make_unique<slot_option>(name, devtype, true))->clock(m_default_clock);
+}
+
+
+device_slot_interface::slot_option &device_slot_interface::option_replace_internal(const char *name, device_type devtype)
+{
+ if (!name || !*name)
+ throw emu_fatalerror("slot '%s' attempt to replace option without name\n", device().tag());
+
+ auto search = m_options.find(name);
+ if (search == m_options.end())
+ throw emu_fatalerror("slot '%s' attempt to replace nonexistent option '%s'\n", device().tag(), name);
+
+ return (search->second = std::make_unique<slot_option>(name, devtype, false))->clock(m_default_clock);
+}
+
+
+void device_slot_interface::option_remove(const char *name)
+{
+ if (!name || !*name)
+ throw emu_fatalerror("slot '%s' attempt to remove option without name\n", device().tag());
+
+ if (m_options.erase(name) == 0)
+ throw emu_fatalerror("slot '%s' attempt to remove nonexistent option '%s'\n", device().tag(), name);
+}
+
+
device_slot_interface::slot_option *device_slot_interface::config_option(const char *name)
{
auto const search = m_options.find(name);
@@ -134,6 +171,5 @@ bool get_default_card_software_hook::hashfile_extrainfo(std::string &extrainfo)
bool get_default_card_software_hook::is_filetype(std::string_view candidate_filetype) const
{
- return std::equal(m_file_type.begin(), m_file_type.end(), candidate_filetype.begin(), candidate_filetype.end(),
- [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; });
+ return util::streqlower(m_file_type, candidate_filetype);
}
diff --git a/src/emu/dislot.h b/src/emu/dislot.h
index 97d314028a2..f6e1f86fcb3 100644
--- a/src/emu/dislot.h
+++ b/src/emu/dislot.h
@@ -46,10 +46,10 @@ public:
class slot_option
{
public:
- slot_option(char const *name, device_type const &devtype, bool selectable);
+ slot_option(char const *name, device_type devtype, bool selectable);
char const *name() const { return m_name; }
- device_type const &devtype() const { return m_devtype; }
+ device_type devtype() const { return m_devtype; }
bool selectable() const { return m_selectable; }
char const *default_bios() const { return m_default_bios; }
std::function<void (device_t *)> const &machine_config() const { return m_machine_config; }
@@ -83,7 +83,7 @@ public:
/// \param [in] fixed True to mark the slot as fixed, or false to
/// mark it user-configurable.
/// \sa fixed
- void set_fixed(bool fixed) { m_fixed = fixed; }
+ device_slot_interface &set_fixed(bool fixed) { m_fixed = fixed; return *this; }
/// \brief Set the default option
///
@@ -97,12 +97,12 @@ public:
/// valid for the lifetime of the device (or until another default
/// option is configured).
/// \sa default_option
- void set_default_option(const char *option) { m_default_option = option; }
+ device_slot_interface &set_default_option(const char *option) { m_default_option = option; return *this; }
/// \brief Clear options
///
/// This removes all previously added options.
- void option_reset() { m_options.clear(); }
+ device_slot_interface &option_reset() { m_options.clear(); return *this; }
/// \brief Add a user-selectable option
///
@@ -116,7 +116,7 @@ public:
/// description is used in the user interface.
/// \return A reference to the added option for additional
/// configuration.
- slot_option &option_add(char const *option, const device_type &devtype);
+ slot_option &option_add(char const *option, device_type devtype);
/// \brief Add an internal option
///
@@ -130,7 +130,11 @@ public:
/// description is used in the user interface.
/// \return A reference to the added option for additional
/// configuration.
- slot_option &option_add_internal(const char *option, const device_type &devtype);
+ slot_option &option_add_internal(const char *option, device_type devtype);
+
+ slot_option &option_replace(const char *option, device_type devtype);
+ slot_option &option_replace_internal(const char *option, device_type devtype);
+ void option_remove(const char *option);
void set_option_default_bios(const char *option, const char *default_bios) { config_option(option)->default_bios(default_bios); }
template <typename T> void set_option_machine_config(const char *option, T &&machine_config) { config_option(option)->machine_config(std::forward<T>(machine_config)); }
@@ -162,7 +166,7 @@ public:
device_t *get_card_device() const { return m_card_device; }
void set_card_device(device_t *dev) { m_card_device = dev; }
const char *slot_name() const { return device().tag() + 1; }
- slot_option &option_set(const char *tag, const device_type &devtype) { m_default_option = tag; m_fixed = true; return option_add_internal(tag, devtype); }
+ slot_option &option_set(const char *tag, device_type devtype) { m_default_option = tag; m_fixed = true; return option_add_internal(tag, devtype); }
protected:
device_slot_interface(machine_config const &mconfig, device_t &device);
diff --git a/src/emu/distate.cpp b/src/emu/distate.cpp
index 0d94c4dcf81..76ede23dfe2 100644
--- a/src/emu/distate.cpp
+++ b/src/emu/distate.cpp
@@ -101,7 +101,7 @@ device_state_entry &device_state_entry::formatstr(const char *_format)
// set the DSF_CUSTOM_STRING flag by formatting with a nullptr string
m_flags &= ~DSF_CUSTOM_STRING;
- format(nullptr);
+ format(nullptr, 0);
return *this;
}
@@ -127,9 +127,7 @@ void device_state_entry::format_from_mask()
// make up a format based on the mask
if (m_datamask == 0)
throw emu_fatalerror("%s state entry requires a nonzero mask\n", m_symbol);
- int width = 0;
- for (u64 tempmask = m_datamask; tempmask != 0; tempmask >>= 4)
- width++;
+ int width = (63 - count_leading_zeros_64(m_datamask)) / 4 + 1;
m_format = string_format("%%0%dX", width);
}
@@ -201,12 +199,10 @@ double device_state_entry::entry_dvalue() const
// pieces of indexed state as a string
//-------------------------------------------------
-std::string device_state_entry::format(const char *string, bool maxout) const
+std::string device_state_entry::format(const char *string, u64 result, bool maxout) const
{
- std::string dest;
- u64 result = entry_value() & m_datamask;
-
// parse the format
+ std::string dest;
bool leadzero = false;
bool percent = false;
bool explicitsign = false;
@@ -400,7 +396,7 @@ std::string device_state_entry::to_string() const
custom = string_format("%-12G", entry_dvalue());
// ask the entry to format itself
- return format(custom.c_str());
+ return format(custom.c_str(), value());
}
@@ -412,7 +408,7 @@ std::string device_state_entry::to_string() const
int device_state_entry::max_length() const
{
// ask the entry to format itself maximally
- return format("", true).length();
+ return format("", 0, true).length();
}
diff --git a/src/emu/distate.h b/src/emu/distate.h
index f0cf04eadeb..b4727c259f4 100644
--- a/src/emu/distate.h
+++ b/src/emu/distate.h
@@ -104,10 +104,10 @@ protected:
private:
// helpers
void format_from_mask();
- std::string format(const char *string, bool maxout = false) const;
+ std::string format(const char *string, u64 result, bool maxout = false) const;
// statics
- static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values
+ static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values
// public state description
device_state_interface *m_device_state; // link to parent device state
@@ -286,12 +286,14 @@ class device_state_interface : public device_interface
friend class device_state_entry;
public:
+ using entrylist_type = std::vector<std::unique_ptr<device_state_entry> >;
+
// construction/destruction
device_state_interface(const machine_config &mconfig, device_t &device);
virtual ~device_state_interface();
// configuration access
- const std::vector<std::unique_ptr<device_state_entry>> &state_entries() const { return m_state_list; }
+ const entrylist_type &state_entries() const { return m_state_list; }
// state getters
u64 state_int(int index) const { const device_state_entry *entry = state_find_entry(index); return (entry == nullptr) ? 0 : entry->value(); }
@@ -357,13 +359,12 @@ protected:
virtual void interface_post_start() override;
// constants
- static constexpr int FAST_STATE_MIN = -4; // range for fast state
- static constexpr int FAST_STATE_MAX = 256; // lookups
+ static constexpr int FAST_STATE_MIN = -4; // range for fast state
+ static constexpr int FAST_STATE_MAX = 256; // lookups
// state
- std::vector<std::unique_ptr<device_state_entry>> m_state_list; // head of state list
- device_state_entry * m_fast_state[FAST_STATE_MAX + 1 - FAST_STATE_MIN];
- // fast access to common entries
+ entrylist_type m_state_list; // head of state list
+ device_state_entry *m_fast_state[FAST_STATE_MAX + 1 - FAST_STATE_MIN]; // fast access to common entries
};
// iterator
diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp
index 41a0aa96aad..ec0469cac02 100644
--- a/src/emu/divtlb.cpp
+++ b/src/emu/divtlb.cpp
@@ -68,7 +68,7 @@ void device_vtlb_interface::interface_validity_check(validity_checker &valid) co
const address_space_config *spaceconfig = intf->space_config(m_space);
if (spaceconfig == nullptr)
osd_printf_error("No memory address space configuration found for space %d\n", m_space);
- else if ((1 << spaceconfig->page_shift()) <= VTLB_FLAGS_MASK || spaceconfig->logaddr_width() <= spaceconfig->page_shift())
+ else if ((1 << spaceconfig->page_shift()) <= FLAGS_MASK || spaceconfig->logaddr_width() <= spaceconfig->page_shift())
osd_printf_error("Invalid page shift %d for VTLB\n", spaceconfig->page_shift());
}
}
@@ -142,11 +142,10 @@ void device_vtlb_interface::interface_pre_reset()
// response to an unmapped access
//-------------------------------------------------
-bool device_vtlb_interface::vtlb_fill(offs_t address, int intention)
+bool device_vtlb_interface::vtlb_fill(offs_t address, offs_t taddress, int intention)
{
offs_t tableindex = address >> m_pageshift;
vtlb_entry entry = m_table[tableindex];
- offs_t taddress;
#if PRINTF_TLB
osd_printf_debug("vtlb_fill: %08X(%X) ... ", address, intention);
@@ -164,18 +163,8 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention)
return false;
}
- // ask the CPU core to translate for us
- taddress = address;
- if (!device().memory().translate(m_space, intention, taddress))
- {
-#if PRINTF_TLB
- osd_printf_debug("failed: no translation\n");
-#endif
- return false;
- }
-
// if this is the first successful translation for this address, allocate a new entry
- if ((entry & VTLB_FLAGS_MASK) == 0)
+ if ((entry & FLAGS_MASK) == 0)
{
int liveindex = m_dynindex;
@@ -196,7 +185,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention)
// form a new blank entry
entry = (taddress >> m_pageshift) << m_pageshift;
- entry |= VTLB_FLAG_VALID;
+ entry |= FLAG_VALID;
#if PRINTF_TLB
osd_printf_debug("success (%08X), new entry\n", taddress);
@@ -207,7 +196,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention)
else
{
assert((entry >> m_pageshift) == (taddress >> m_pageshift));
- assert(entry & VTLB_FLAG_VALID);
+ assert(entry & FLAG_VALID);
#if PRINTF_TLB
osd_printf_debug("success (%08X), existing entry\n", taddress);
@@ -215,7 +204,7 @@ bool device_vtlb_interface::vtlb_fill(offs_t address, int intention)
}
// add the intention to the list of valid intentions and store
- entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK));
+ entry |= 1 << intention;
m_table[tableindex] = entry;
return true;
}
@@ -256,7 +245,7 @@ void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address
m_refcnt[tableindex]++;
// store the raw value, making sure the "fixed" flag is set
- value |= VTLB_FLAG_FIXED;
+ value |= FLAG_FIXED;
m_fixedpages[entrynum] = numpages;
for (pagenum = 0; pagenum < numpages; pagenum++)
m_table[tableindex + pagenum] = value + (pagenum << m_pageshift);
@@ -283,7 +272,7 @@ void device_vtlb_interface::vtlb_dynload(u32 index, offs_t address, vtlb_entry v
m_dynindex = (m_dynindex + 1) % m_dynamic;
// is entry already live?
- if (!(entry & VTLB_FLAG_VALID))
+ if (!(entry & FLAG_VALID))
{
// if an entry already exists at this index, free it
if (m_live[liveindex] != 0)
@@ -294,7 +283,7 @@ void device_vtlb_interface::vtlb_dynload(u32 index, offs_t address, vtlb_entry v
}
// form a new blank entry
entry = (address >> m_pageshift) << m_pageshift;
- entry |= VTLB_FLAG_VALID | value;
+ entry |= FLAG_VALID | value;
#if PRINTF_TLB
osd_printf_debug("success (%08X), new entry\n", address);
@@ -356,7 +345,7 @@ void device_vtlb_interface::vtlb_flush_address(offs_t address)
// the linear VTLB lookup table
//-------------------------------------------------
-const vtlb_entry *device_vtlb_interface::vtlb_table() const
+const device_vtlb_interface::vtlb_entry *device_vtlb_interface::vtlb_table() const
{
return m_table_base;
}
diff --git a/src/emu/divtlb.h b/src/emu/divtlb.h
index c64bca0a21c..13adbd4a4ce 100644
--- a/src/emu/divtlb.h
+++ b/src/emu/divtlb.h
@@ -13,38 +13,35 @@
#pragma once
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-constexpr u32 VTLB_FLAGS_MASK = 0xff;
-
-constexpr u32 VTLB_READ_ALLOWED = 0x01; /* (1 << TRANSLATE_READ) */
-constexpr u32 VTLB_WRITE_ALLOWED = 0x02; /* (1 << TRANSLATE_WRITE) */
-constexpr u32 VTLB_FETCH_ALLOWED = 0x04; /* (1 << TRANSLATE_FETCH) */
-constexpr u32 VTLB_FLAG_VALID = 0x08;
-constexpr u32 VTLB_USER_READ_ALLOWED = 0x10; /* (1 << TRANSLATE_READ_USER) */
-constexpr u32 VTLB_USER_WRITE_ALLOWED = 0x20; /* (1 << TRANSLATE_WRITE_USER) */
-constexpr u32 VTLB_USER_FETCH_ALLOWED = 0x40; /* (1 << TRANSLATE_FETCH_USER) */
-constexpr u32 VTLB_FLAG_FIXED = 0x80;
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* represents an entry in the VTLB */
-typedef u32 vtlb_entry;
-
-
-// ======================> device_vtlb_interface
-
class device_vtlb_interface : public device_interface
{
public:
+ using vtlb_entry = u32;
+
+ // Translation type flags
+ // TR_READ/WRITE/FETCH come from device_memory_interface
+ enum {
+ TR_UREAD = 4,
+ TR_UWRITE = 5,
+ TR_UFETCH = 6,
+
+ TR_TYPE = 3,
+ TR_USER = 4
+ };
+
+ enum {
+ FLAGS_MASK = 0xff,
+
+ READ_ALLOWED = 0x01, /* (1 << TR_READ) */
+ WRITE_ALLOWED = 0x02, /* (1 << TR_WRITE) */
+ FETCH_ALLOWED = 0x04, /* (1 << TR_FETCH) */
+ FLAG_VALID = 0x08,
+ USER_READ_ALLOWED = 0x10, /* (1 << TR_UREAD) */
+ USER_WRITE_ALLOWED = 0x20, /* (1 << TR_UWRITE) */
+ USER_FETCH_ALLOWED = 0x40, /* (1 << TR_UFETCH) */
+ FLAG_FIXED = 0x80
+ };
+
// construction/destruction
device_vtlb_interface(const machine_config &mconfig, device_t &device, int space);
virtual ~device_vtlb_interface();
@@ -54,7 +51,7 @@ public:
void set_vtlb_fixed_entries(int entries) { m_fixed = entries; }
// filling
- bool vtlb_fill(offs_t address, int intention);
+ bool vtlb_fill(offs_t address, offs_t taddress, int intention);
void vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value);
void vtlb_dynload(u32 index, offs_t address, vtlb_entry value);
diff --git a/src/emu/drawgfxt.ipp b/src/emu/drawgfxt.ipp
index 4d756497102..4277bf21634 100644
--- a/src/emu/drawgfxt.ipp
+++ b/src/emu/drawgfxt.ipp
@@ -421,7 +421,7 @@ while (0)
template <typename BitmapType, typename FunctionClass>
inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_DRAWGFX);
+ auto profile = g_profiler.start(PROFILER_DRAWGFX);
do {
assert(dest.valid());
assert(dest.cliprect().contains(cliprect));
@@ -551,14 +551,13 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec
}
}
} while (0);
- g_profiler.stop();
}
template <typename BitmapType, typename PriorityType, typename FunctionClass>
inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, PriorityType &priority, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_DRAWGFX);
+ auto profile = g_profiler.start(PROFILER_DRAWGFX);
do {
assert(dest.valid());
assert(priority.valid());
@@ -695,7 +694,6 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec
}
}
} while (0);
- g_profiler.stop();
}
@@ -724,7 +722,7 @@ inline void gfx_element::drawgfx_core(BitmapType &dest, const rectangle &cliprec
template <typename BitmapType, typename FunctionClass>
inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_DRAWGFX);
+ auto profile = g_profiler.start(PROFILER_DRAWGFX);
do {
assert(dest.valid());
assert(dest.cliprect().contains(cliprect));
@@ -830,14 +828,13 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli
}
}
} while (0);
- g_profiler.stop();
}
template <typename BitmapType, typename PriorityType, typename FunctionClass>
inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 scalex, u32 scaley, PriorityType &priority, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_DRAWGFX);
+ auto profile = g_profiler.start(PROFILER_DRAWGFX);
do {
assert(dest.valid());
assert(priority.valid());
@@ -877,10 +874,7 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli
// compute final pixel in Y and exit if we are entirely clipped
s32 destendy = desty + dstheight - 1;
if (desty > cliprect.bottom() || destendy < cliprect.top())
- {
- g_profiler.stop();
return;
- }
// apply top clip
s32 srcy = 0;
@@ -950,7 +944,6 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli
}
}
} while (0);
- g_profiler.stop();
}
@@ -975,7 +968,7 @@ inline void gfx_element::drawgfxzoom_core(BitmapType &dest, const rectangle &cli
template <typename BitmapType, typename FunctionClass>
inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_COPYBITMAP);
+ auto profile = g_profiler.start(PROFILER_COPYBITMAP);
do {
assert(dest.valid());
assert(src.valid());
@@ -1108,14 +1101,13 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx,
}
}
} while (0);
- g_profiler.stop();
}
template <typename BitmapType, typename PriorityType, typename FunctionClass>
inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, PriorityType &priority, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_COPYBITMAP);
+ auto profile = g_profiler.start(PROFILER_COPYBITMAP);
do {
assert(dest.valid());
assert(src.valid());
@@ -1255,7 +1247,6 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx,
}
}
} while (0);
- g_profiler.stop();
}
@@ -1283,7 +1274,7 @@ inline void copybitmap_core(BitmapType &dest, const BitmapType &src, int flipx,
template <typename BitmapType, typename FunctionClass>
inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool wraparound, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_COPYBITMAP);
+ auto profile = g_profiler.start(PROFILER_COPYBITMAP);
assert(dest.valid());
assert(dest.valid());
@@ -1293,10 +1284,7 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons
// ignore empty/invalid cliprects
if (cliprect.empty())
- {
- g_profiler.stop();
return;
- }
// compute fixed-point 16.16 size of the source bitmap
u32 srcfixwidth = src.width() << 16;
@@ -1537,14 +1525,13 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons
}
}
}
- g_profiler.stop();
}
template <typename BitmapType, typename PriorityType, typename FunctionClass>
inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, const BitmapType &src, s32 startx, s32 starty, s32 incxx, s32 incxy, s32 incyx, s32 incyy, bool wraparound, PriorityType &priority, FunctionClass pixel_op)
{
- g_profiler.start(PROFILER_COPYBITMAP);
+ auto profile = g_profiler.start(PROFILER_COPYBITMAP);
assert(dest.valid());
assert(dest.valid());
@@ -1555,10 +1542,7 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons
// ignore empty/invalid cliprects
if (cliprect.empty())
- {
- g_profiler.stop();
return;
- }
// compute fixed-point 16.16 size of the source bitmap
u32 srcfixwidth = src.width() << 16;
@@ -1811,7 +1795,6 @@ inline void copyrozbitmap_core(BitmapType &dest, const rectangle &cliprect, cons
}
}
}
- g_profiler.stop();
}
diff --git a/src/emu/driver.cpp b/src/emu/driver.cpp
index 04c6489aae3..9b0dd9c5e59 100644
--- a/src/emu/driver.cpp
+++ b/src/emu/driver.cpp
@@ -67,7 +67,6 @@ void driver_device::static_set_callback(device_t &device, callback_type type, dr
void driver_device::empty_init()
{
- driver_init();
}
@@ -82,16 +81,6 @@ std::vector<std::string> driver_device::searchpath() const
//-------------------------------------------------
-// driver_init - default implementation which
-// does nothing
-//-------------------------------------------------
-
-void driver_device::driver_init()
-{
-}
-
-
-//-------------------------------------------------
// driver_start - default implementation which
// does nothing
//-------------------------------------------------
@@ -260,10 +249,7 @@ void driver_device::device_reset_after_children()
sound_reset();
- if (!m_callbacks[CB_VIDEO_RESET].isnull())
- m_callbacks[CB_VIDEO_RESET]();
- else
- video_reset();
+ video_reset();
}
@@ -328,16 +314,16 @@ void driver_device::updateflip()
// flip_screen_set - set global flip
//-------------------------------------------------
-void driver_device::flip_screen_set(u32 on)
+void driver_device::flip_screen_set(int state)
{
// normalize to all 1
- if (on)
- on = ~0;
+ if (state)
+ state = 0xff;
// if something's changed, handle it
- if (m_flip_screen_x != on || m_flip_screen_y != on)
+ if (m_flip_screen_x != state || m_flip_screen_y != state)
{
- m_flip_screen_x = m_flip_screen_y = on;
+ m_flip_screen_x = m_flip_screen_y = state;
updateflip();
}
}
@@ -347,16 +333,16 @@ void driver_device::flip_screen_set(u32 on)
// flip_screen_x_set - set global horizontal flip
//-------------------------------------------------
-void driver_device::flip_screen_x_set(u32 on)
+void driver_device::flip_screen_x_set(int state)
{
// normalize to all 1
- if (on)
- on = ~0;
+ if (state)
+ state = 0xff;
// if something's changed, handle it
- if (m_flip_screen_x != on)
+ if (m_flip_screen_x != state)
{
- m_flip_screen_x = on;
+ m_flip_screen_x = state;
updateflip();
}
}
@@ -366,16 +352,16 @@ void driver_device::flip_screen_x_set(u32 on)
// flip_screen_y_set - set global vertical flip
//-------------------------------------------------
-void driver_device::flip_screen_y_set(u32 on)
+void driver_device::flip_screen_y_set(int state)
{
// normalize to all 1
- if (on)
- on = ~0;
+ if (state)
+ state = 0xff;
// if something's changed, handle it
- if (m_flip_screen_y != on)
+ if (m_flip_screen_y != state)
{
- m_flip_screen_y = on;
+ m_flip_screen_y = state;
updateflip();
}
}
diff --git a/src/emu/driver.h b/src/emu/driver.h
index 0656775ab7b..75e035d46c9 100644
--- a/src/emu/driver.h
+++ b/src/emu/driver.h
@@ -26,6 +26,9 @@
#define MCFG_MACHINE_START_OVERRIDE(_class, _func) \
driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_START, driver_callback_delegate(&_class::MACHINE_START_NAME(_func), this));
+#define MCFG_MACHINE_START_REMOVE() \
+ driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_START, driver_callback_delegate());
+
#define MCFG_MACHINE_RESET_OVERRIDE(_class, _func) \
driver_device::static_set_callback(config.root_device(), driver_device::CB_MACHINE_RESET, driver_callback_delegate(&_class::MACHINE_RESET_NAME(_func), this));
@@ -37,8 +40,8 @@
#define MCFG_VIDEO_START_OVERRIDE(_class, _func) \
driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_START, driver_callback_delegate(&_class::VIDEO_START_NAME(_func), this));
-#define MCFG_VIDEO_RESET_OVERRIDE(_class, _func) \
- driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_RESET, driver_callback_delegate(&_class::VIDEO_RESET_NAME(_func), this));
+#define MCFG_VIDEO_START_REMOVE() \
+ driver_device::static_set_callback(config.root_device(), driver_device::CB_VIDEO_START, driver_callback_delegate());
@@ -61,11 +64,6 @@
#define DECLARE_VIDEO_START(name) void VIDEO_START_NAME(name)() ATTR_COLD
#define VIDEO_START_MEMBER(cls,name) void cls::VIDEO_START_NAME(name)()
-#define VIDEO_RESET_NAME(name) video_reset_##name
-#define VIDEO_RESET_CALL_MEMBER(name) VIDEO_RESET_NAME(name)()
-#define DECLARE_VIDEO_RESET(name) void VIDEO_RESET_NAME(name)()
-#define VIDEO_RESET_MEMBER(cls,name) void cls::VIDEO_RESET_NAME(name)()
-
//**************************************************************************
@@ -100,7 +98,6 @@ public:
CB_MACHINE_START,
CB_MACHINE_RESET,
CB_VIDEO_START,
- CB_VIDEO_RESET,
CB_COUNT
};
@@ -145,8 +142,6 @@ public:
virtual std::vector<std::string> searchpath() const override;
- virtual void driver_init();
-
protected:
// helpers called at startup
virtual void driver_start();
@@ -168,12 +163,12 @@ protected:
virtual void device_reset_after_children() override;
// generic video
- void flip_screen_set(u32 on);
- void flip_screen_x_set(u32 on);
- void flip_screen_y_set(u32 on);
- u32 flip_screen() const { return m_flip_screen_x; }
- u32 flip_screen_x() const { return m_flip_screen_x; }
- u32 flip_screen_y() const { return m_flip_screen_y; }
+ void flip_screen_set(int state);
+ void flip_screen_x_set(int state);
+ void flip_screen_y_set(int state);
+ u8 flip_screen() const { return m_flip_screen_x; } // & m_flip_screen_y?
+ u8 flip_screen_x() const { return m_flip_screen_x; }
+ u8 flip_screen_y() const { return m_flip_screen_y; }
private:
// helpers
@@ -185,8 +180,8 @@ private:
driver_callback_delegate m_callbacks[CB_COUNT]; // start/reset callbacks
// generic video
- u8 m_flip_screen_x;
- u8 m_flip_screen_y;
+ u8 m_flip_screen_x;
+ u8 m_flip_screen_y;
};
diff --git a/src/emu/drivers/empty.cpp b/src/emu/drivers/empty.cpp
index 23cf5443013..9b907214487 100644
--- a/src/emu/drivers/empty.cpp
+++ b/src/emu/drivers/empty.cpp
@@ -9,8 +9,11 @@
**************************************************************************/
#include "emu.h"
+
#include "emuopts.h"
-#include "render.h"
+#include "main.h"
+#include "screen.h"
+
//**************************************************************************
// DRIVER STATE
diff --git a/src/emu/drivers/testcpu.cpp b/src/emu/drivers/testcpu.cpp
index 574e6fc88b3..95e3d5a1ec2 100644
--- a/src/emu/drivers/testcpu.cpp
+++ b/src/emu/drivers/testcpu.cpp
@@ -38,7 +38,7 @@ public:
}
// timer callback; used to wrest control of the system
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override
+ TIMER_CALLBACK_MEMBER(timer_tick)
{
static const u32 sample_instructions[] =
{
@@ -101,7 +101,7 @@ public:
m_cpu->ppcdrc_set_options(PPCDRC_COMPATIBLE_OPTIONS);
// set a timer to go off right away
- timer_set(attotime::zero);
+ timer_alloc(FUNC(timer_tick), this)->adjust(attotime::zero);
}
// dump the current CPU state
diff --git a/src/emu/emu.h b/src/emu/emu.h
index d648ee932de..679687f772d 100644
--- a/src/emu/emu.h
+++ b/src/emu/emu.h
@@ -18,6 +18,9 @@
#ifndef __EMU_H__
#define __EMU_H__
+// get forward declarations before anything else
+#include "emufwd.h"
+
#include <list>
#include <forward_list>
#include <vector>
@@ -34,17 +37,13 @@
#include "attotime.h"
#include "profiler.h"
-// http interface helpers
-#include "http.h"
-
// commonly-referenced utilities imported from lib/util
-#include "corealloc.h"
+#include "corefile.h"
+#include "delegate.h"
+#include "hash.h"
#include "palette.h"
// emulator-specific utilities
-#include "hash.h"
-#include "fileio.h"
-#include "delegate.h"
#include "devdelegate.h"
// memory and address spaces
@@ -73,7 +72,6 @@
#include "divideo.h"
#include "dinvram.h"
#include "schedule.h"
-#include "dinetwork.h"
// machine and driver configuration
#include "mconfig.h"
@@ -81,7 +79,6 @@
#include "parameters.h"
// the running machine
-#include "main.h"
#include "machine.h"
#include "driver.h"
diff --git a/src/emu/emucore.cpp b/src/emu/emucore.cpp
index bc6139fe3cf..d9a314cfaa2 100644
--- a/src/emu/emucore.cpp
+++ b/src/emu/emucore.cpp
@@ -13,13 +13,13 @@
#include "emucore.h"
#include "osdcore.h"
-emu_fatalerror::emu_fatalerror(util::format_argument_pack<std::ostream> const &args)
+emu_fatalerror::emu_fatalerror(util::format_argument_pack<char> const &args)
: emu_fatalerror(0, args)
{
osd_break_into_debugger(m_text.c_str());
}
-emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args)
+emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<char> const &args)
: m_text(util::string_format(args))
, m_code(_exitcode)
{
diff --git a/src/emu/emucore.h b/src/emu/emucore.h
index 768fa8c7280..ca54f5208cd 100644
--- a/src/emu/emucore.h
+++ b/src/emu/emucore.h
@@ -13,35 +13,38 @@
#pragma once
-// standard C includes
-#include <cassert>
-#include <cmath>
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-#include <cstdarg>
-
// some cleanups for Solaris for things defined in stdlib.h
#if defined(__sun__) && defined(__svr4__)
#undef si_status
#undef WWORD
#endif
-// standard C++ includes
-#include <exception>
-#include <string>
-#include <type_traits>
-#include <typeinfo>
+// centralised forward declarations
+#include "emufwd.h"
-// core system includes
-#include "osdcomm.h"
+// common stuff from lib/util
+#include "corealloc.h"
#include "coretmpl.h"
#include "bitmap.h"
#include "endianness.h"
#include "strformat.h"
#include "vecstream.h"
-#include "emufwd.h"
+// common stuff from osd
+#include "osdcomm.h"
+
+// standard C++ includes
+#include <exception>
+#include <string>
+#include <type_traits>
+#include <typeinfo>
+
+// standard C includes
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
//**************************************************************************
@@ -95,6 +98,9 @@ using util::DWORD_XOR_BE;
using util::DWORD_XOR_LE;
+// input ports support up to 32 bits each
+typedef u32 ioport_value;
+
// pen_t is used to represent pixel values in bitmaps
typedef u32 pen_t;
@@ -193,73 +199,11 @@ constexpr int ROT270 = ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y;
/// \}
-// these are UTF-8 encoded strings for common characters
-#define UTF8_NBSP "\xc2\xa0" /* non-breaking space */
-
-#define UTF8_MULTIPLY "\xc3\x97" /* multiplication sign */
-#define UTF8_DIVIDE "\xc3\xb7" /* division sign */
-#define UTF8_SQUAREROOT "\xe2\x88\x9a" /* square root symbol */
-#define UTF8_PLUSMINUS "\xc2\xb1" /* plusminus symbol */
-
-#define UTF8_POW_2 "\xc2\xb2" /* superscript 2 */
-#define UTF8_POW_X "\xcb\xa3" /* superscript x */
-#define UTF8_POW_Y "\xca\xb8" /* superscript y */
-#define UTF8_PRIME "\xca\xb9" /* prime symbol */
-#define UTF8_DEGREES "\xc2\xb0" /* degrees symbol */
-
-#define UTF8_SMALL_PI "\xcf\x80" /* Greek small letter pi */
-#define UTF8_CAPITAL_SIGMA "\xce\xa3" /* Greek capital letter sigma */
-#define UTF8_CAPITAL_DELTA "\xce\x94" /* Greek capital letter delta */
-
-#define UTF8_MACRON "\xc2\xaf" /* macron symbol */
-#define UTF8_NONSPACE_MACRON "\xcc\x84" /* nonspace macron, use after another char */
-
-#define a_RING "\xc3\xa5" /* small a with a ring */
-#define a_UMLAUT "\xc3\xa4" /* small a with an umlaut */
-#define o_UMLAUT "\xc3\xb6" /* small o with an umlaut */
-#define u_UMLAUT "\xc3\xbc" /* small u with an umlaut */
-#define e_ACUTE "\xc3\xa9" /* small e with an acute */
-#define n_TILDE "\xc3\xb1" /* small n with a tilde */
-
-#define A_RING "\xc3\x85" /* capital A with a ring */
-#define A_UMLAUT "\xc3\x84" /* capital A with an umlaut */
-#define O_UMLAUT "\xc3\x96" /* capital O with an umlaut */
-#define U_UMLAUT "\xc3\x9c" /* capital U with an umlaut */
-#define E_ACUTE "\xc3\x89" /* capital E with an acute */
-#define N_TILDE "\xc3\x91" /* capital N with a tilde */
-
-#define UTF8_LEFT "\xe2\x86\x90" /* cursor left */
-#define UTF8_RIGHT "\xe2\x86\x92" /* cursor right */
-#define UTF8_UP "\xe2\x86\x91" /* cursor up */
-#define UTF8_DOWN "\xe2\x86\x93" /* cursor down */
-
-
//**************************************************************************
// COMMON MACROS
//**************************************************************************
-// macro for defining a copy constructor and assignment operator to prevent copying
-#define DISABLE_COPYING(TYPE) \
- TYPE(const TYPE &) = delete; \
- TYPE &operator=(const TYPE &) = delete
-
-// macro for declaring enumeration operators that increment/decrement like plain old C
-#define DECLARE_ENUM_INCDEC_OPERATORS(TYPE) \
-inline TYPE &operator++(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) + 1); } \
-inline TYPE &operator--(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) - 1); } \
-inline TYPE operator++(TYPE &value, int) { TYPE const old(value); ++value; return old; } \
-inline TYPE operator--(TYPE &value, int) { TYPE const old(value); --value; return old; }
-
-// macro for declaring bitwise operators for an enumerated type
-#define DECLARE_ENUM_BITWISE_OPERATORS(TYPE) \
-constexpr TYPE operator~(TYPE value) { return TYPE(~std::underlying_type_t<TYPE>(value)); } \
-constexpr TYPE operator&(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) & std::underlying_type_t<TYPE>(b)); } \
-constexpr TYPE operator|(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) | std::underlying_type_t<TYPE>(b)); } \
-inline TYPE &operator&=(TYPE &a, TYPE b) { return a = a & b; } \
-inline TYPE &operator|=(TYPE &a, TYPE b) { return a = a | b; }
-
-
// this macro passes an item followed by a string version of itself as two consecutive parameters
#define NAME(x) x, #x
@@ -284,17 +228,19 @@ class emu_exception : public std::exception { };
class emu_fatalerror : public emu_exception
{
public:
- emu_fatalerror(util::format_argument_pack<std::ostream> const &args);
- emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args);
+ emu_fatalerror(emu_fatalerror const &) = default;
+ emu_fatalerror(emu_fatalerror &&) = default;
+ emu_fatalerror(util::format_argument_pack<char> const &args);
+ emu_fatalerror(int _exitcode, util::format_argument_pack<char> const &args);
template <typename Format, typename... Params>
- emu_fatalerror(Format const &fmt, Params &&... args)
- : emu_fatalerror(static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...)))
+ emu_fatalerror(Format &&fmt, Params &&... args)
+ : emu_fatalerror(static_cast<util::format_argument_pack<char> const &>(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)))
{
}
template <typename Format, typename... Params>
- emu_fatalerror(int _exitcode, Format const &fmt, Params &&... args)
- : emu_fatalerror(_exitcode, static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...)))
+ emu_fatalerror(int _exitcode, Format &&fmt, Params &&... args)
+ : emu_fatalerror(_exitcode, static_cast<util::format_argument_pack<char> const &>(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)))
{
}
@@ -421,4 +367,11 @@ inline u64 d2u(double d)
return u.vv;
}
+
+//**************************************************************************
+// USEFUL UTILITIES
+//**************************************************************************
+
+using util::make_unique_clear;
+
#endif // MAME_EMU_EMUCORE_H
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index 8b8e59b9250..89e15e4c541 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -14,6 +14,8 @@
#pragma once
+#include "utilfwd.h"
+
#include <type_traits>
@@ -40,24 +42,6 @@ class osd_interface;
//----------------------------------
-// lib/util
-//----------------------------------
-
-// declared in aviio.h
-class avi_file;
-
-// declared in chd.h
-class chd_file;
-
-// declared in unzip.h
-namespace util { class archive_file; }
-
-// declared in xmlfile.h
-namespace util::xml { class data_node; class file; }
-
-
-
-//----------------------------------
// emu
//----------------------------------
@@ -98,6 +82,7 @@ class symbol_table;
class debug_breakpoint;
class debug_watchpoint;
class debug_registerpoint;
+class debug_exceptionpoint;
// declared in debugger.h
class debugger_manager;
@@ -107,6 +92,7 @@ class devcb_base;
template <typename Input, std::make_unsigned_t<Input> DefaultMask> class devcb_write;
// declared in devfind.h
+class device_resolver_base;
class finder_base;
template <class DeviceClass, bool Required> class device_finder;
@@ -129,6 +115,9 @@ class device_image_interface;
// declared in dimemory.h
class device_memory_interface;
+// declared in dinetwork.h
+class device_network_interface;
+
// declared in dipalette.h
class device_palette_interface;
@@ -152,6 +141,12 @@ class memory_view;
// declared in emuopts.h
class emu_options;
+// declared in fileio.h
+class emu_file;
+
+// declared in http.h
+class http_manager;
+
// declared in gamedrv.h
class game_driver;
@@ -181,8 +176,12 @@ class running_machine;
// declared in mconfig.h
namespace emu::detail { class machine_config_replace; }
+struct internal_layout;
class machine_config;
+// declared in main.h
+class machine_manager;
+
// declared in natkeyboard.h
class natural_keyboard;
@@ -198,6 +197,9 @@ class render_manager;
class render_target;
class render_texture;
+// declared in rendertypes.h
+struct render_bounds;
+
// declared in rendfont.h
class render_font;
diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp
index 3982debf2cc..679c2374e78 100644
--- a/src/emu/emumem.cpp
+++ b/src/emu/emumem.cpp
@@ -861,66 +861,98 @@ void address_space_installer::populate_map_entry(const address_map_entry &entry,
install_view(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, *entry.m_view);
break;
}
+
+ if (data.m_type == AMH_VIEW)
+ return;
+
+ offs_t lowbits_mask = (m_config.data_width() >> (3 - m_config.addr_shift())) - 1;
+
+ if (!entry.m_before_time.isnull()) {
+ auto d = entry.m_before_time;
+ d.resolve();
+ if (readorwrite == read_or_write::READ)
+ install_read_before_time(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ else
+ install_write_before_time(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ }
+
+ if (!entry.m_before_delay.isnull()) {
+ auto d = entry.m_before_delay;
+ d.resolve();
+ if (readorwrite == read_or_write::READ)
+ install_read_before_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ else
+ install_write_before_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ }
+
+ if (!entry.m_after_delay.isnull()) {
+ auto d = entry.m_after_delay;
+ d.resolve();
+ if (readorwrite == read_or_write::READ)
+ install_read_after_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ else
+ install_write_after_delay(entry.m_addrstart & ~lowbits_mask, entry.m_addrend | lowbits_mask, entry.m_addrmirror, d);
+ }
}
-memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 8-bits wide bus read tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 16-bits wide bus read tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 32-bits wide bus read tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 64-bits wide bus read tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 8-bits wide bus write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 16-bits wide bus write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 32-bits wide bus write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 64-bits wide bus write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 8-bits wide bus read/write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 16-bits wide bus read/write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph)
{
fatalerror("Tryingw to install a 32-bits wide bus read/write tap in a %d-bits wide bus\n", data_width());
}
-memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph)
+memory_passthrough_handler address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph)
{
fatalerror("Trying to install a 64-bits wide bus read/write tap in a %d-bits wide bus\n", data_width());
}
@@ -984,7 +1016,7 @@ void memory_bank::set_entry(int entrynum)
// validate
if (entrynum < 0 || entrynum >= int(m_entries.size()))
- throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum);
+ throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with out-of-range entry %d", m_tag, entrynum);
if (m_entries[entrynum] == nullptr)
throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag, entrynum);
diff --git a/src/emu/emumem.h b/src/emu/emumem.h
index 3d4d664469e..1b9b6363622 100644
--- a/src/emu/emumem.h
+++ b/src/emu/emumem.h
@@ -17,6 +17,8 @@
#ifndef MAME_EMU_EMUMEM_H
#define MAME_EMU_EMUMEM_H
+#include "notifier.h"
+
#include <optional>
#include <set>
#include <type_traits>
@@ -50,6 +52,14 @@ enum class read_or_write
};
+//**************************************************************************
+// FORWARD DECLARATIONS
+//**************************************************************************
+
+class handler_entry;
+template<int Width, int AddrShift> class handler_entry_read_passthrough;
+template<int Width, int AddrShift> class handler_entry_write_passthrough;
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -90,7 +100,7 @@ struct memory_entry_context {
struct memory_entry {
offs_t start, end;
- class handler_entry *entry;
+ handler_entry *entry;
std::vector<memory_entry_context> context;
};
@@ -163,9 +173,15 @@ using write32smo_delegate = device_delegate<void (u32)>;
using write64smo_delegate = device_delegate<void (u64)>;
+// =====================-> Wait states delegates
+
+using ws_time_delegate = device_delegate<u64 (offs_t, u64)>;
+using ws_delay_delegate = device_delegate<u32 (offs_t)>;
+
+
namespace emu::detail {
-// TODO: replace with std::void_t when we move to C++17
+// TODO: work out why this doesn't work with clang and/or libc++ void_t but works with this C++14 work-alike
template <typename... T> struct void_wrapper { using type = void; };
template <typename... T> using void_t = typename void_wrapper<T...>::type;
@@ -233,15 +249,6 @@ template <typename T> using rw_delegate_type_t = typename rw_delegate_type<T>::t
template <typename T> using rw_delegate_device_class_t = typename rw_delegate_type<T>::device_class;
-template <typename T>
-inline rw_delegate_type_t<T> make_delegate(device_t &base, char const *tag, T &&func, char const *name)
-{ return rw_delegate_type_t<T>(base, tag, std::forward<T>(func), name); }
-
-template <typename T>
-inline rw_delegate_type_t<T> make_delegate(rw_delegate_device_class_t<T> &object, T &&func, char const *name)
-{ return rw_delegate_type_t<T>(object, std::forward<T>(func), name); }
-
-
template <typename L>
inline std::enable_if_t<std::is_constructible<read8_delegate, device_t &, L, const char *>::value, read8_delegate> make_lr8_delegate(device_t &owner, L &&l, const char *name)
{ return read8_delegate(owner, std::forward<L>(l), name); }
@@ -436,14 +443,69 @@ inline std::enable_if_t<std::is_constructible<write64smo_delegate, device_t &, L
{ return write64smo_delegate(owner, std::forward<L>(l), name); }
+// =====================-> delegate -> Width
+
+template <typename Delegate> struct handler_width;
+template <typename Delegate> inline constexpr int handler_width_v = handler_width<Delegate>::value;
+template <> struct handler_width<read8_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read8m_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read8s_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read8sm_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read8mo_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read8smo_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8m_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8s_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8sm_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8mo_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<write8smo_delegate> { static inline constexpr int value = 0; };
+template <> struct handler_width<read16_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read16m_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read16s_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read16sm_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read16mo_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read16smo_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16m_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16s_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16sm_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16mo_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<write16smo_delegate> { static inline constexpr int value = 1; };
+template <> struct handler_width<read32_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read32m_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read32s_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read32sm_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read32mo_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read32smo_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32m_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32s_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32sm_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32mo_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<write32smo_delegate> { static inline constexpr int value = 2; };
+template <> struct handler_width<read64_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<read64m_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<read64s_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<read64sm_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<read64mo_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<read64smo_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64m_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64s_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64sm_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64mo_delegate> { static inline constexpr int value = 3; };
+template <> struct handler_width<write64smo_delegate> { static inline constexpr int value = 3; };
+
+
// =====================-> Width -> types
-template<int Width> struct handler_entry_size {};
-template<> struct handler_entry_size<0> { using uX = u8; };
-template<> struct handler_entry_size<1> { using uX = u16; };
-template<> struct handler_entry_size<2> { using uX = u32; };
-template<> struct handler_entry_size<3> { using uX = u64; };
+template <int Width> struct handler_entry_size;
+template <int Width> using handler_entry_size_t = typename handler_entry_size<Width>::type;
+template<> struct handler_entry_size<0> { using type = u8; };
+template<> struct handler_entry_size<1> { using type = u16; };
+template<> struct handler_entry_size<2> { using type = u32; };
+template<> struct handler_entry_size<3> { using type = u64; };
// =====================-> Address segmentation for the search tree
@@ -465,9 +527,49 @@ constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift
width + ashift;
}
+
+// =====================-> Passthrough handler management structure
+
+class memory_passthrough_handler_impl
+{
+public:
+ memory_passthrough_handler_impl(address_space &space) : m_space(space) {}
+ memory_passthrough_handler_impl(memory_passthrough_handler_impl const &) = delete;
+
+ void remove();
+
+private:
+ address_space &m_space;
+ std::unordered_set<handler_entry *> m_handlers;
+
+ void add_handler(handler_entry *handler) { m_handlers.insert(handler); }
+ void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); }
+
+ friend address_space;
+ template<int Width, int AddrShift> friend class ::handler_entry_read_passthrough;
+ template<int Width, int AddrShift> friend class ::handler_entry_write_passthrough;
+};
+
} // namespace emu::detail
+namespace emu {
+
+template <typename T>
+inline detail::rw_delegate_type_t<T> rw_delegate(device_t &base, char const *tag, T &&func, char const *name)
+{ return detail::rw_delegate_type_t<T>(base, tag, std::forward<T>(func), name); }
+
+template <typename T>
+inline detail::rw_delegate_type_t<T> rw_delegate(detail::rw_delegate_device_class_t<T> &object, T &&func, char const *name)
+{ return detail::rw_delegate_type_t<T>(object, std::forward<T>(func), name); }
+
+template <typename D, bool Reqd, typename T>
+inline detail::rw_delegate_type_t<T> rw_delegate(device_finder<D, Reqd> const &finder, T &&func, char const *name)
+{ return detail::rw_delegate_type_t<T>(finder, std::forward<T>(func), name); }
+
+} // namespace emu
+
+
// ======================> memory_units_descritor forwards declaration
template<int Width, int AddrShift> class memory_units_descriptor;
@@ -485,11 +587,14 @@ class handler_entry
public:
// Typing flags (low 16 bits are for the user)
- static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler
- static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers
- static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support)
- static constexpr u32 F_PASSTHROUGH = 0x00080000; // handler that passes through the request to another handler
- static constexpr u32 F_VIEW = 0x00100000; // handler for a view (kinda like dispatch except not entirely)
+ static constexpr u32 F_UNMAP = 0x00010000; // the unmapped memory accessed handler
+ static constexpr u32 F_DISPATCH = 0x00020000; // handler that forwards the access to other handlers
+ static constexpr u32 F_UNITS = 0x00040000; // handler that merges/splits an access among multiple handlers (unitmask support)
+ static constexpr u32 F_VIEW = 0x00080000; // handler for a view (kinda like dispatch except not entirely)
+ static constexpr u32 F_PT_BITS = 24; // position of the 4-bit priority for a passthrough handler. The highest the priority the earlier it is called in the chain. 0 = not passthrough
+ static constexpr u32 F_PT_REPLACE = 1 << F_PT_BITS; // a passthrough with a odd priority can only happen once in a path
+
+ static constexpr u32 f_pt(u32 priority) { return (priority << F_PT_BITS); }
// Start/end of range flags
static constexpr u8 START = 1;
@@ -519,7 +624,8 @@ public:
inline bool is_dispatch() const { return m_flags & F_DISPATCH; }
inline bool is_view() const { return m_flags & F_VIEW; }
inline bool is_units() const { return m_flags & F_UNITS; }
- inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; }
+ inline bool is_passthrough() const { return f_get_pt() != 0; }
+ inline u32 f_get_pt() const { return (m_flags >> F_PT_BITS) & 15; }
virtual void dump_map(std::vector<memory_entry> &map) const;
@@ -561,12 +667,10 @@ protected:
// Provides the populate/read/get_ptr/lookup API
-template<int Width, int AddrShift> class handler_entry_read_passthrough;
-
template<int Width, int AddrShift> class handler_entry_read : public handler_entry
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0;
@@ -580,7 +684,9 @@ public:
~handler_entry_read() {}
virtual uX read(offs_t offset, uX mem_mask) const = 0;
+ virtual uX read_interruptible(offs_t offset, uX mem_mask) const = 0;
virtual std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const = 0;
+ virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift> *&handler) const;
@@ -596,7 +702,7 @@ public:
virtual void populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift> *handler);
virtual void populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift> *handler);
- inline void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor) {
+ void populate_mismatched(offs_t start, offs_t end, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor) {
start &= ~NATIVE_MASK;
end |= NATIVE_MASK;
std::vector<mapping> mappings;
@@ -609,7 +715,7 @@ public:
virtual void populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift> &descriptor, u8 rkey, std::vector<mapping> &mappings);
virtual void populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor, std::vector<mapping> &mappings);
- inline void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler) {
+ void populate_passthrough(offs_t start, offs_t end, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler) {
start &= ~NATIVE_MASK;
end |= NATIVE_MASK;
std::vector<mapping> mappings;
@@ -636,12 +742,10 @@ public:
// Provides the populate/write/get_ptr/lookup API
-template<int Width, int AddrShift> class handler_entry_write_passthrough;
-
template<int Width, int AddrShift> class handler_entry_write : public handler_entry
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0;
@@ -655,7 +759,9 @@ public:
virtual ~handler_entry_write() {}
virtual void write(offs_t offset, uX data, uX mem_mask) const = 0;
+ virtual void write_interruptible(offs_t offset, uX data, uX mem_mask) const = 0;
virtual u16 write_flags(offs_t offset, uX data, uX mem_mask) const = 0;
+ virtual u16 lookup_flags(offs_t offset, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift> *&handler) const;
@@ -711,20 +817,21 @@ public:
// =====================-> Passthrough handler management structure
class memory_passthrough_handler
{
- template<int Width, int AddrShift> friend class handler_entry_read_passthrough;
- template<int Width, int AddrShift> friend class handler_entry_write_passthrough;
-
public:
- memory_passthrough_handler(address_space &space) : m_space(space) {}
+ memory_passthrough_handler() : m_impl() {}
+ memory_passthrough_handler(std::shared_ptr<emu::detail::memory_passthrough_handler_impl> const &impl) : m_impl(impl) {}
- inline void remove();
+ void remove()
+ {
+ auto impl(m_impl.lock());
+ if (impl)
+ impl->remove();
+ }
private:
- address_space &m_space;
- std::unordered_set<handler_entry *> m_handlers;
+ std::weak_ptr<emu::detail::memory_passthrough_handler_impl> m_impl;
- void add_handler(handler_entry *handler) { m_handlers.insert(handler); }
- void remove_handler(handler_entry *handler) { m_handlers.erase(m_handlers.find(handler)); }
+ friend class address_space;
};
// =====================-> Forward declaration for address_space
@@ -739,10 +846,10 @@ constexpr offs_t memory_offset_to_byte(offs_t offset, int AddrShift) { return Ad
// ======================> generic read/write decomposition routines
// generic direct read
-template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> typename emu::detail::handler_entry_size<TargetWidth>::uX memory_read_generic(T rop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> emu::detail::handler_entry_size_t<TargetWidth> memory_read_generic(T rop, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask)
{
- using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX;
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using TargetType = emu::detail::handler_entry_size_t<TargetWidth>;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
constexpr u32 TARGET_BYTES = 1 << TargetWidth;
constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
@@ -873,9 +980,9 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al
}
// generic direct write
-template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> data, emu::detail::handler_entry_size_t<TargetWidth> mask)
{
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
constexpr u32 TARGET_BYTES = 1 << TargetWidth;
constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
@@ -995,11 +1102,12 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al
}
}
}
+
// generic direct read with flags
-template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> std::pair<typename emu::detail::handler_entry_size<TargetWidth>::uX, u16> memory_read_generic_flags(TF ropf, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> std::pair<emu::detail::handler_entry_size_t<TargetWidth>, u16> memory_read_generic_flags(TF ropf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask)
{
- using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX;
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using TargetType = emu::detail::handler_entry_size_t<TargetWidth>;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
constexpr u32 TARGET_BYTES = 1 << TargetWidth;
constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
@@ -1135,9 +1243,9 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al
}
// generic direct write with flags
-template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 memory_write_generic_flags(TF wopf, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 memory_write_generic_flags(TF wopf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> data, emu::detail::handler_entry_size_t<TargetWidth> mask)
{
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
constexpr u32 TARGET_BYTES = 1 << TargetWidth;
constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
@@ -1264,35 +1372,328 @@ template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Al
}
}
+//##############################################
+// generic direct read flags lookup
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 lookup_memory_read_generic_flags(TF lropf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask)
+{
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
+
+ constexpr u32 TARGET_BYTES = 1 << TargetWidth;
+ constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
+ constexpr u32 NATIVE_BYTES = 1 << Width;
+ constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES;
+ constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift);
+ constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0;
+
+ // equal to native size and aligned; simple pass-through to the native flags lookup
+ if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0))
+ return lropf(address & ~NATIVE_MASK, mask);
+
+ // if native size is larger, see if we can do a single masked flags lookup (guaranteed if we're aligned)
+ if (NATIVE_BYTES > TARGET_BYTES)
+ {
+ u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1)));
+ if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS))
+ {
+ if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits;
+ return lropf(address & ~NATIVE_MASK, (NativeType)mask << offsbits);
+ }
+ }
+
+ // determine our alignment against the native boundaries, and mask the address
+ u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1));
+ address &= ~NATIVE_MASK;
+
+ // if we're here, and native size is larger or equal to the target, we need exactly 2 reads
+ if (NATIVE_BYTES >= TARGET_BYTES)
+ {
+ // little-endian case
+ if (Endian == ENDIANNESS_LITTLE)
+ {
+ // read flags from lower address
+ u16 flags = 0;
+ NativeType curmask = (NativeType)mask << offsbits;
+ if (curmask != 0) flags |= lropf(address, curmask);
+
+ // read flags from upper address
+ offsbits = NATIVE_BITS - offsbits;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask);
+ return flags;
+ }
+
+ // big-endian case
+ else
+ {
+ // left-justify the mask to the target type
+ constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0);
+ u16 flags = 0;
+ NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT;
+ NativeType curmask = ljmask >> offsbits;
+
+ // read flags from lower address
+ if (curmask != 0) flags |= lropf(address, curmask);
+ offsbits = NATIVE_BITS - offsbits;
+
+ // read flags from upper address
+ curmask = ljmask << offsbits;
+ if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask);
+
+ // return the result
+ return flags;
+ }
+ }
+
+ // if we're here, then we have 2 or more reads needed to get our final result
+ else
+ {
+ // compute the maximum number of loops; we do it this way so that there are
+ // a fixed number of loops for the compiler to unroll if it desires
+ constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1;
+ u16 flags = 0;
+
+ // little-endian case
+ if (Endian == ENDIANNESS_LITTLE)
+ {
+ // read flags from first address
+ NativeType curmask = mask << offsbits;
+ if (curmask != 0) flags |= lropf(address, curmask);
+
+ // read flags from subsequent addresses
+ offsbits = NATIVE_BITS - offsbits;
+ for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
+ {
+ address += NATIVE_STEP;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lropf(address, curmask);
+ offsbits += NATIVE_BITS;
+ }
+
+ // if we're not aligned and we still have bits left, read flags from last address
+ if (!Aligned && offsbits < TARGET_BITS)
+ {
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask);
+ }
+ }
+
+ // big-endian case
+ else
+ {
+ // read flags from first address
+ offsbits = TARGET_BITS - (NATIVE_BITS - offsbits);
+ NativeType curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lropf(address, curmask);
+
+ // read flags from subsequent addresses
+ for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
+ {
+ offsbits -= NATIVE_BITS;
+ address += NATIVE_STEP;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lropf(address, curmask);
+ }
+
+ // if we're not aligned and we still have bits left, read flags from the last address
+ if (!Aligned && offsbits != 0)
+ {
+ offsbits = NATIVE_BITS - offsbits;
+ curmask = mask << offsbits;
+ if (curmask != 0) flags |= lropf(address + NATIVE_STEP, curmask);
+ }
+ }
+ return flags;
+ }
+}
+
+// generic direct write flags lookup
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename TF> u16 lookup_memory_write_generic_flags(TF lwopf, offs_t address, emu::detail::handler_entry_size_t<TargetWidth> mask)
+{
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
+
+ constexpr u32 TARGET_BYTES = 1 << TargetWidth;
+ constexpr u32 TARGET_BITS = 8 * TARGET_BYTES;
+ constexpr u32 NATIVE_BYTES = 1 << Width;
+ constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES;
+ constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift);
+ constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
+
+ // equal to native size and aligned; simple pass-through to the native flags lookup
+ if (NATIVE_BYTES == TARGET_BYTES && (Aligned || (address & NATIVE_MASK) == 0))
+ return lwopf(address & ~NATIVE_MASK, mask);
+
+ // if native size is larger, see if we can do a single masked flags lookup (guaranteed if we're aligned)
+ if (NATIVE_BYTES > TARGET_BYTES)
+ {
+ u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - (Aligned ? TARGET_BYTES : 1)));
+ if (Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS))
+ {
+ if (Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits;
+ return lwopf(address & ~NATIVE_MASK, (NativeType)mask << offsbits);
+ }
+ }
+
+ // determine our alignment against the native boundaries, and mask the address
+ u32 offsbits = 8 * (memory_offset_to_byte(address, AddrShift) & (NATIVE_BYTES - 1));
+ address &= ~NATIVE_MASK;
+
+ // if we're here, and native size is larger or equal to the target, we need exactly 2 lookups
+ if (NATIVE_BYTES >= TARGET_BYTES)
+ {
+ // little-endian case
+ if (Endian == ENDIANNESS_LITTLE)
+ {
+ // lookup flags from lower address
+ u16 flags = 0;
+ NativeType curmask = (NativeType)mask << offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+
+ // lookup flags from upper address
+ offsbits = NATIVE_BITS - offsbits;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask);
+ return flags;
+ }
+
+ // big-endian case
+ else
+ {
+ // left-justify the mask to the target type
+ u16 flags = 0;
+ constexpr u32 LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT = ((NATIVE_BITS >= TARGET_BITS) ? (NATIVE_BITS - TARGET_BITS) : 0);
+ NativeType ljmask = (NativeType)mask << LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT;
+
+ // lookup flags from lower address
+ NativeType curmask = ljmask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+
+ // lookup falgs from upper address
+ offsbits = NATIVE_BITS - offsbits;
+ curmask = ljmask << offsbits;
+ if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask);
+ return flags;
+ }
+ }
+
+ // if we're here, then we have 2 or more lookups needed to get our final result
+ else
+ {
+ // compute the maximum number of loops; we do it this way so that there are
+ // a fixed number of loops for the compiler to unroll if it desires
+ constexpr u32 MAX_SPLITS_MINUS_ONE = TARGET_BYTES / NATIVE_BYTES - 1;
+ u16 flags = 0;
+
+ // little-endian case
+ if (Endian == ENDIANNESS_LITTLE)
+ {
+ // lookup flags from first address
+ NativeType curmask = mask << offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+
+ // lookup flags from subsequent addresses
+ offsbits = NATIVE_BITS - offsbits;
+ for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
+ {
+ address += NATIVE_STEP;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+ offsbits += NATIVE_BITS;
+ }
+
+ // if we're not aligned and we still have bits left, lookup flags last address
+ if (!Aligned && offsbits < TARGET_BITS)
+ {
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask);
+ }
+ }
+
+ // big-endian case
+ else
+ {
+ // lookup flags from first address
+ offsbits = TARGET_BITS - (NATIVE_BITS - offsbits);
+ NativeType curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+
+ // lookup flags from subsequent addresses
+ for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
+ {
+ offsbits -= NATIVE_BITS;
+ address += NATIVE_STEP;
+ curmask = mask >> offsbits;
+ if (curmask != 0) flags |= lwopf(address, curmask);
+ }
+
+ // if we're not aligned and we still have bits left, lookup falgs from the last address
+ if (!Aligned && offsbits != 0)
+ {
+ offsbits = NATIVE_BITS - offsbits;
+ curmask = mask << offsbits;
+ if (curmask != 0) flags |= lwopf(address + NATIVE_STEP, curmask);
+ }
+ }
+ return flags;
+ }
+}
+
// ======================> Direct dispatching
-template<int Level, int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX dispatch_read(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
+template<int Level, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> dispatch_read(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
{
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
return dispatch[(offset & mask) >> LowBits]->read(offset, mem_mask);
}
-template<int Level, int Width, int AddrShift> void dispatch_write(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
+template<int Level, int Width, int AddrShift> void dispatch_write(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
{
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
return dispatch[(offset & mask) >> LowBits]->write(offset, data, mem_mask);
}
-template<int Level, int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> dispatch_read_flags(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
+template<int Level, int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> dispatch_read_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
{
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
return dispatch[(offset & mask) >> LowBits]->read_flags(offset, mem_mask);
}
-template<int Level, int Width, int AddrShift> u16 dispatch_write_flags(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
+template<int Level, int Width, int AddrShift> u16 dispatch_write_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
{
static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
return dispatch[(offset & mask) >> LowBits]->write_flags(offset, data, mem_mask);
}
+template<int Level, int Width, int AddrShift> u16 dispatch_lookup_read_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->lookup_flags(offset, mem_mask);
+}
+
+
+template<int Level, int Width, int AddrShift> u16 dispatch_lookup_write_flags(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->lookup_flags(offset, mem_mask);
+}
+
+
+
+template<int Level, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> dispatch_read_interruptible(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_read<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->read_interruptible(offset, mem_mask);
+}
+
+
+template<int Level, int Width, int AddrShift> void dispatch_write_interruptible(offs_t mask, offs_t offset, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mem_mask, const handler_entry_write<Width, AddrShift> *const *dispatch)
+{
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->write_interruptible(offset, data, mem_mask);
+}
+
// ======================> memory_access_specific
@@ -1304,7 +1705,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> class memory_
{
friend class ::address_space;
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
static constexpr u32 NATIVE_BYTES = 1 << Width;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
@@ -1322,10 +1723,12 @@ public:
return *m_space;
}
- auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
- auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; }
- auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
- auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; }
+ auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
+ auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; }
+ auto lropf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_read_native_flags(offset, mask); }; }
+ auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
+ auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; }
+ auto lwopf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_write_native_flags(offset, mask); }; }
u8 read_byte(offs_t address) { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); }
u16 read_word(offs_t address) { if constexpr(Width == 1) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 1, true>(rop(), address, 0xffff); }
@@ -1384,6 +1787,42 @@ public:
u16 write_qword_unaligned_flags(offs_t address, u64 data) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); }
u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); }
+ u16 lookup_read_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(lropf(), address, 0xff); }
+ u16 lookup_read_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, 0xffff); }
+ u16 lookup_read_word_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, mask); }
+ u16 lookup_read_word_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, 0xffff); }
+ u16 lookup_read_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, mask); }
+ u16 lookup_read_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, 0xffffffff); }
+ u16 lookup_read_dword_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, mask); }
+ u16 lookup_read_dword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, 0xffffffff); }
+ u16 lookup_read_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, mask); }
+ u16 lookup_read_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, 0xffffffffffffffffU); }
+ u16 lookup_read_qword_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, mask); }
+ u16 lookup_read_qword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, 0xffffffffffffffffU); }
+ u16 lookup_read_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, mask); }
+
+ u16 lookup_write_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(lwopf(), address, 0xff); }
+ u16 lookup_write_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, 0xffff); }
+ u16 lookup_write_word_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, mask); }
+ u16 lookup_write_word_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, 0xffff); }
+ u16 lookup_write_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, mask); }
+ u16 lookup_write_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, 0xffffffff); }
+ u16 lookup_write_dword_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, mask); }
+ u16 lookup_write_dword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, 0xffffffff); }
+ u16 lookup_write_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, mask); }
+ u16 lookup_write_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(lwopf(), address, 0xffffffffffffffffU); }
+ u16 lookup_write_qword_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wop(), address, mask); }
+ u16 lookup_write_qword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, 0xffffffffffffffffU); }
+ u16 lookup_write_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, mask); }
+
+ NativeType read_interruptible(offs_t address, NativeType mask = ~NativeType(0)) {
+ return dispatch_read_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read);
+ }
+
+ void write_interruptible(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) {
+ dispatch_write_interruptible<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write);
+ }
+
private:
address_space * m_space;
@@ -1408,6 +1847,14 @@ private:
return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, data, mask, m_dispatch_write);
}
+ u16 lookup_read_native_flags(offs_t address, NativeType mask = ~NativeType(0)) {
+ return dispatch_lookup_read_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_read);
+ }
+
+ u16 lookup_write_native_flags(offs_t address, NativeType mask = ~NativeType(0)) {
+ return dispatch_lookup_write_flags<Level, Width, AddrShift>(offs_t(-1), address & m_addrmask, mask, m_dispatch_write);
+ }
+
void set(address_space *space, std::pair<const void *, const void *> rw);
};
@@ -1420,7 +1867,7 @@ template<int Width, int AddrShift, endianness_t Endian> class memory_access_cach
{
friend class ::address_space;
- using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
+ using NativeType = emu::detail::handler_entry_size_t<Width>;
static constexpr u32 NATIVE_BYTES = 1 << Width;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
@@ -1467,10 +1914,12 @@ public:
return m_cache_r->get_ptr(address);
}
- auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
- auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; }
- auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
- auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; }
+ auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
+ auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; }
+ auto lropf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_read_native_flags(offset, mask); }; }
+ auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
+ auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; }
+ auto lwopf() { return [this](offs_t offset, NativeType mask) -> u16 { return lookup_write_native_flags(offset, mask); }; }
u8 read_byte(offs_t address) { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); }
u16 read_word(offs_t address) { if constexpr(Width == 1) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 1, true>(rop(), address, 0xffff); }
@@ -1529,6 +1978,35 @@ public:
u16 write_qword_unaligned_flags(offs_t address, u64 data) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); }
u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); }
+
+ u16 lookup_read_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(lropf(), address, 0xff); }
+ u16 lookup_read_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, 0xffff); }
+ u16 lookup_read_word_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(lropf(), address, mask); }
+ u16 lookup_read_word_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, 0xffff); }
+ u16 lookup_read_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(lropf(), address, mask); }
+ u16 lookup_read_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, 0xffffffff); }
+ u16 lookup_read_dword_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(lropf(), address, mask); }
+ u16 lookup_read_dword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, 0xffffffff); }
+ u16 lookup_read_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(lropf(), address, mask); }
+ u16 lookup_read_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_read_native_flags(address & ~NATIVE_MASK); else return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, 0xffffffffffffffffU); }
+ u16 lookup_read_qword_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(lropf(), address, mask); }
+ u16 lookup_read_qword_unaligned_flags(offs_t address) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, 0xffffffffffffffffU); }
+ u16 lookup_read_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(lropf(), address, mask); }
+
+ u16 lookup_write_byte_flags(offs_t address) { if constexpr(Width == 0) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(lwopf(), address, 0xff); }
+ u16 lookup_write_word_flags(offs_t address) { if constexpr(Width == 1) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, 0xffff); }
+ u16 lookup_write_word_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(lwopf(), address, mask); }
+ u16 lookup_write_word_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, 0xffff); }
+ u16 lookup_write_word_unaligned_flags(offs_t address, u16 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(lwopf(), address, mask); }
+ u16 lookup_write_dword_flags(offs_t address) { if constexpr(Width == 2) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, 0xffffffff); }
+ u16 lookup_write_dword_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(lwopf(), address, mask); }
+ u16 lookup_write_dword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, 0xffffffff); }
+ u16 lookup_write_dword_unaligned_flags(offs_t address, u32 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(lwopf(), address, mask); }
+ u16 lookup_write_qword_flags(offs_t address) { if constexpr(Width == 3) return lookup_write_native_flags(address & ~NATIVE_MASK); else return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(lwopf(), address, 0xffffffffffffffffU); }
+ u16 lookup_write_qword_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wop(), address, mask); }
+ u16 lookup_write_qword_unaligned_flags(offs_t address) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, 0xffffffffffffffffU); }
+ u16 lookup_write_qword_unaligned_flags(offs_t address, u64 mask) { return lookup_memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(lwopf(), address, mask); }
+
private:
address_space * m_space;
@@ -1543,10 +2021,14 @@ private:
handler_entry_read <Width, AddrShift> *m_root_read; // decode tree roots
handler_entry_write<Width, AddrShift> *m_root_write;
+ util::notifier_subscription m_subscription;
+
NativeType read_native(offs_t address, NativeType mask = ~NativeType(0));
void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0));
std::pair<NativeType, u16> read_native_flags(offs_t address, NativeType mask = ~NativeType(0));
u16 write_native_flags(offs_t address, NativeType data, NativeType mask = ~NativeType(0));
+ u16 lookup_read_native_flags(offs_t address, NativeType mask = ~NativeType(0));
+ u16 lookup_write_native_flags(offs_t address, NativeType mask = ~NativeType(0));
void set(address_space *space, std::pair<void *, void *> rw);
};
@@ -1687,194 +2169,132 @@ public:
virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
// install taps without mirroring
- memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
- memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
- memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
- memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
- memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
+ memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_read_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr) { return install_write_tap(addrstart, addrend, 0, name, tap, mph); }
+ memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
+ memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
+ memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
+ memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr) { return install_readwrite_tap(addrstart, addrend, 0, name, tapr, tapw, mph); }
// install taps with mirroring
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tap, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapr, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapr, std::function<void (offs_t offset, u16 &data, u16 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapr, std::function<void (offs_t offset, u32 &data, u32 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapr, std::function<void (offs_t offset, u64 &data, u64 mem_mask)> tapw, memory_passthrough_handler *mph = nullptr);
// install views
void install_view(offs_t addrstart, offs_t addrend, memory_view &view) { install_view(addrstart, addrend, 0, view); }
virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) = 0;
+ // install wait state handlers
+ void install_read_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_read_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_read_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_read_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_read_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+
+ void install_write_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_write_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_write_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_write_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_write_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+
+ void install_readwrite_before_time(offs_t addrstart, offs_t addrend, ws_time_delegate ws) { install_readwrite_before_time(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) = 0;
+ void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_before_delay(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+ void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, ws_delay_delegate ws) { install_readwrite_after_delay(addrstart, addrend, 0, ws); }
+ virtual void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) = 0;
+
// install new-style delegate handlers (short form)
- void install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
-
- void install_read_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
-
- void install_read_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
-
- void install_read_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
-
- void install_read_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
-
- void install_read_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { return install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
- void install_read_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth, flags); }
- void install_write_handler(offs_t addrstart, offs_t addrend, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_write_handler(addrstart, addrend, 0, 0, 0, whandler, unitmask, cswidth, flags); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) { install_readwrite_handler(addrstart, addrend, 0, 0, 0, rhandler, whandler, unitmask, cswidth, flags); }
+ template <typename R>
+ void install_read_handler(offs_t addrstart, offs_t addrend, R &&rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0)
+ { install_read_handler(addrstart, addrend, 0, 0, 0, std::forward<R>(rhandler), unitmask, cswidth, flags); }
+ template <typename W>
+ void install_write_handler(offs_t addrstart, offs_t addrend, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0)
+ { install_write_handler(addrstart, addrend, 0, 0, 0, std::forward<W>(whandler), unitmask, cswidth, flags); }
+ template <typename R, typename W>
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, R &&rhandler, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0)
+ { install_readwrite_handler(addrstart, addrend, 0, 0, 0, std::forward<R>(rhandler), std::forward<W>(whandler), unitmask, cswidth, flags); }
// install new-style delegate handlers (with mirror/mask)
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
- virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) = 0;
+
+ template <typename R, typename W>
+ void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, R &&rhandler, W &&whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0)
+ {
+ static_assert(emu::detail::handler_width_v<std::remove_reference_t<R> > == emu::detail::handler_width_v<std::remove_reference_t<W> >, "handler widths do not match");
+ install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, std::forward<R>(rhandler), unitmask, cswidth, flags);
+ install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, std::forward<W>(whandler), unitmask, cswidth, flags);
+ }
protected:
virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, bool quiet) = 0;
@@ -1918,11 +2338,6 @@ class address_space : public address_space_installer
template<int Width, int AddrShift> friend class handler_entry_read_unmapped;
template<int Width, int AddrShift> friend class handler_entry_write_unmapped;
- struct notifier_t {
- std::function<void (read_or_write)> m_notifier;
- int m_id;
- };
-
protected:
// construction/destruction
address_space(memory_manager &manager, device_memory_interface &memory, int spacenum);
@@ -1962,15 +2377,14 @@ public:
v.set(this, get_specific_info());
}
- int add_change_notifier(std::function<void (read_or_write)> n);
- void remove_change_notifier(int id);
+ util::notifier_subscription add_change_notifier(delegate<void (read_or_write)> &&n);
+ template <typename T> util::notifier_subscription add_change_notifier(T &&n) { return add_change_notifier(delegate<void (read_or_write)>(std::forward<T>(n))); }
void invalidate_caches(read_or_write mode) {
if(u32(mode) & ~m_in_notification) {
u32 old = m_in_notification;
m_in_notification |= u32(mode);
- for(const auto &n : m_notifiers)
- n.m_notifier(mode);
+ m_notifiers(mode);
m_in_notification = old;
}
}
@@ -1980,8 +2394,10 @@ public:
virtual void remove_passthrough(std::unordered_set<handler_entry *> &handlers) = 0;
u64 unmap() const { return m_unmap; }
+ void unmap_value_high() { m_unmap = ~0; }
- memory_passthrough_handler *make_mph();
+ std::shared_ptr<emu::detail::memory_passthrough_handler_impl> make_mph(memory_passthrough_handler *mph);
+ std::shared_ptr<emu::detail::memory_passthrough_handler_impl> get_default_mpl() { return m_default_mpl; }
// debug helpers
virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0;
@@ -2024,36 +2440,6 @@ public:
virtual void write_qword_unaligned(offs_t address, u64 data) = 0;
virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0;
- // read accessors with flags
- virtual std::pair<u8, u16> read_byte_flags(offs_t address) = 0;
- virtual std::pair<u16, u16> read_word_flags(offs_t address) = 0;
- virtual std::pair<u16, u16> read_word_flags(offs_t address, u16 mask) = 0;
- virtual std::pair<u16, u16> read_word_unaligned_flags(offs_t address) = 0;
- virtual std::pair<u16, u16> read_word_unaligned_flags(offs_t address, u16 mask) = 0;
- virtual std::pair<u32, u16> read_dword_flags(offs_t address) = 0;
- virtual std::pair<u32, u16> read_dword_flags(offs_t address, u32 mask) = 0;
- virtual std::pair<u32, u16> read_dword_unaligned_flags(offs_t address) = 0;
- virtual std::pair<u32, u16> read_dword_unaligned_flags(offs_t address, u32 mask) = 0;
- virtual std::pair<u64, u16> read_qword_flags(offs_t address) = 0;
- virtual std::pair<u64, u16> read_qword_flags(offs_t address, u64 mask) = 0;
- virtual std::pair<u64, u16> read_qword_unaligned_flags(offs_t address) = 0;
- virtual std::pair<u64, u16> read_qword_unaligned_flags(offs_t address, u64 mask) = 0;
-
- // write accessors with flags
- virtual u16 write_byte_flags(offs_t address, u8 data) = 0;
- virtual u16 write_word_flags(offs_t address, u16 data) = 0;
- virtual u16 write_word_flags(offs_t address, u16 data, u16 mask) = 0;
- virtual u16 write_word_unaligned_flags(offs_t address, u16 data) = 0;
- virtual u16 write_word_unaligned_flags(offs_t address, u16 data, u16 mask) = 0;
- virtual u16 write_dword_flags(offs_t address, u32 data) = 0;
- virtual u16 write_dword_flags(offs_t address, u32 data, u32 mask) = 0;
- virtual u16 write_dword_unaligned_flags(offs_t address, u32 data) = 0;
- virtual u16 write_dword_unaligned_flags(offs_t address, u32 data, u32 mask) = 0;
- virtual u16 write_qword_flags(offs_t address, u64 data) = 0;
- virtual u16 write_qword_flags(offs_t address, u64 data, u64 mask) = 0;
- virtual u16 write_qword_unaligned_flags(offs_t address, u64 data) = 0;
- virtual u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) = 0;
-
// setup
void prepare_map();
void prepare_device_map(address_map &map);
@@ -2088,11 +2474,13 @@ protected:
handler_entry *m_nop_r;
handler_entry *m_nop_w;
- std::vector<std::unique_ptr<memory_passthrough_handler>> m_mphs;
+ std::vector<std::shared_ptr<emu::detail::memory_passthrough_handler_impl>> m_mphs;
- std::vector<notifier_t> m_notifiers; // notifier list for address map change
- int m_notifier_id; // next notifier id
+ util::notifier<read_or_write> m_notifiers; // notifier list for address map change
u32 m_in_notification; // notification(s) currently being done
+
+ // passthrough handler used for wait states
+ std::shared_ptr<emu::detail::memory_passthrough_handler_impl> m_default_mpl;
};
@@ -2379,9 +2767,9 @@ private:
template<int Width, int AddrShift, endianness_t Endian>
-typename emu::detail::handler_entry_size<Width>::uX
+emu::detail::handler_entry_size_t<Width>
emu::detail::memory_access_cache<Width, AddrShift, Endian>::
-read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX mask)
+read_native(offs_t address, emu::detail::handler_entry_size_t<Width> mask)
{
address &= m_addrmask;
check_address_r(address);
@@ -2390,14 +2778,14 @@ read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX
template<int Width, int AddrShift, endianness_t Endian>
void emu::detail::memory_access_cache<Width, AddrShift, Endian>::
-write_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mask)
+write_native(offs_t address, emu::detail::handler_entry_size_t<Width> data, emu::detail::handler_entry_size_t<Width> mask)
{
address &= m_addrmask;
check_address_w(address);
m_cache_w->write(address, data, mask);
}
-void memory_passthrough_handler::remove()
+inline void emu::detail::memory_passthrough_handler_impl::remove()
{
m_space.remove_passthrough(m_handlers);
}
@@ -2421,18 +2809,19 @@ set(address_space *space, std::pair<void *, void *> rw)
m_space = space;
m_addrmask = space->addrmask();
- space->add_change_notifier([this](read_or_write mode) {
- if(u32(mode) & u32(read_or_write::READ)) {
- m_addrend_r = 0;
- m_addrstart_r = 1;
- m_cache_r = nullptr;
- }
- if(u32(mode) & u32(read_or_write::WRITE)) {
- m_addrend_w = 0;
- m_addrstart_w = 1;
- m_cache_w = nullptr;
- }
- });
+ m_subscription = space->add_change_notifier(
+ [this] (read_or_write mode) {
+ if(u32(mode) & u32(read_or_write::READ)) {
+ m_addrend_r = 0;
+ m_addrstart_r = 1;
+ m_cache_r = nullptr;
+ }
+ if(u32(mode) & u32(read_or_write::WRITE)) {
+ m_addrend_w = 0;
+ m_addrstart_w = 1;
+ m_cache_w = nullptr;
+ }
+ });
m_root_read = (handler_entry_read <Width, AddrShift> *)(rw.first);
m_root_write = (handler_entry_write<Width, AddrShift> *)(rw.second);
diff --git a/src/emu/emumem_aspace.cpp b/src/emu/emumem_aspace.cpp
index 5aeea17c11a..b0d00d6fca8 100644
--- a/src/emu/emumem_aspace.cpp
+++ b/src/emu/emumem_aspace.cpp
@@ -25,6 +25,7 @@
#include "emumem_hedw.h"
#include "emumem_hep.h"
#include "emumem_het.h"
+#include "emumem_hws.h"
//**************************************************************************
@@ -48,58 +49,7 @@ template <typename Format, typename... Params> static void VPRINTF(Format &&, Pa
// CONSTANTS
//**************************************************************************
-namespace {
-
-template <typename Delegate> struct handler_width;
-template <> struct handler_width<read8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; };
-} // anonymous namespace
+using emu::detail::handler_width_v;
//**************************************************************************
@@ -112,7 +62,7 @@ template <> struct handler_width<write64smo_delegate> { static constexpr int val
template<int Level, int Width, int AddrShift, endianness_t Endian>
class address_space_specific : public address_space
{
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
using NativeType = uX;
using this_type = address_space_specific<Level, Width, AddrShift, Endian>;
@@ -138,163 +88,127 @@ public:
void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override;
void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) override;
+ void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+
+ void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+
+ void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
using address_space::install_read_tap;
using address_space::install_write_tap;
using address_space::install_readwrite_tap;
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
// construction/destruction
address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum, int address_width)
@@ -433,48 +347,26 @@ public:
return dispatch_read<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read);
}
- std::pair<NativeType, u16> read_native_flags(offs_t offset, NativeType mask)
- {
- return dispatch_read_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read);
- }
-
// mask-less native read
NativeType read_native(offs_t offset)
{
return dispatch_read<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read);
}
- std::pair<NativeType, u16> read_native_flags(offs_t offset)
- {
- return dispatch_read_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read);
- }
-
// native write
void write_native(offs_t offset, NativeType data, NativeType mask)
{
dispatch_write<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write);
}
- u16 write_native_flags(offs_t offset, NativeType data, NativeType mask)
- {
- return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write);
- }
-
// mask-less native write
void write_native(offs_t offset, NativeType data)
{
dispatch_write<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write);
}
- u16 write_native_flags(offs_t offset, NativeType data)
- {
- return dispatch_write_flags<Level, Width, AddrShift>(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write);
- }
-
- auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
- auto ropf() { return [this](offs_t offset, NativeType mask) -> std::pair<NativeType, u16> { return read_native_flags(offset, mask); }; }
- auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
- auto wopf() { return [this](offs_t offset, NativeType data, NativeType mask) -> u16 { return write_native_flags(offset, data, mask); }; }
+ auto rop() { return [this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }; }
+ auto wop() { return [this](offs_t offset, NativeType data, NativeType mask) -> void { write_native(offset, data, mask); }; }
// virtual access to these functions
u8 read_byte(offs_t address) override { if constexpr(Width == 0) return read_native(address & ~NATIVE_MASK); else return memory_read_generic<Width, AddrShift, Endian, 0, true>(rop(), address, 0xff); }
@@ -505,34 +397,6 @@ public:
void write_qword_unaligned(offs_t address, u64 data) override { memory_write_generic<Width, AddrShift, Endian, 3, false>(wop(), address, data, 0xffffffffffffffffU); }
void write_qword_unaligned(offs_t address, u64 data, u64 mask) override { memory_write_generic<Width, AddrShift, Endian, 3, false>(wop(), address, data, mask); }
- std::pair<u8, u16> read_byte_flags(offs_t address) override { if constexpr(Width == 0) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 0, true>(ropf(), address, 0xff); }
- std::pair<u16, u16> read_word_flags(offs_t address) override { if constexpr(Width == 1) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(ropf(), address, 0xffff); }
- std::pair<u16, u16> read_word_flags(offs_t address, u16 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, true>(ropf(), address, mask); }
- std::pair<u16, u16> read_word_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(ropf(), address, 0xffff); }
- std::pair<u16, u16> read_word_unaligned_flags(offs_t address, u16 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 1, false>(ropf(), address, mask); }
- std::pair<u32, u16> read_dword_flags(offs_t address) override { if constexpr(Width == 2) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(ropf(), address, 0xffffffff); }
- std::pair<u32, u16> read_dword_flags(offs_t address, u32 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, true>(ropf(), address, mask); }
- std::pair<u32, u16> read_dword_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(ropf(), address, 0xffffffff); }
- std::pair<u32, u16> read_dword_unaligned_flags(offs_t address, u32 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 2, false>(ropf(), address, mask); }
- std::pair<u64, u16> read_qword_flags(offs_t address) override { if constexpr(Width == 3) return read_native_flags(address & ~NATIVE_MASK); else return memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(ropf(), address, 0xffffffffffffffffU); }
- std::pair<u64, u16> read_qword_flags(offs_t address, u64 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, true>(ropf(), address, mask); }
- std::pair<u64, u16> read_qword_unaligned_flags(offs_t address) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(ropf(), address, 0xffffffffffffffffU); }
- std::pair<u64, u16> read_qword_unaligned_flags(offs_t address, u64 mask) override { return memory_read_generic_flags<Width, AddrShift, Endian, 3, false>(ropf(), address, mask); }
-
- u16 write_byte_flags(offs_t address, u8 data) override { if constexpr(Width == 0) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 0, true>(wopf(), address, data, 0xff); }
- u16 write_word_flags(offs_t address, u16 data) override { if constexpr(Width == 1) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(wopf(), address, data, 0xffff); }
- u16 write_word_flags(offs_t address, u16 data, u16 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, true>(wopf(), address, data, mask); }
- u16 write_word_unaligned_flags(offs_t address, u16 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(wopf(), address, data, 0xffff); }
- u16 write_word_unaligned_flags(offs_t address, u16 data, u16 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 1, false>(wopf(), address, data, mask); }
- u16 write_dword_flags(offs_t address, u32 data) override { if constexpr(Width == 2) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(wopf(), address, data, 0xffffffff); }
- u16 write_dword_flags(offs_t address, u32 data, u32 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, true>(wopf(), address, data, mask); }
- u16 write_dword_unaligned_flags(offs_t address, u32 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(wopf(), address, data, 0xffffffff); }
- u16 write_dword_unaligned_flags(offs_t address, u32 data, u32 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 2, false>(wopf(), address, data, mask); }
- u16 write_qword_flags(offs_t address, u64 data) override { if constexpr(Width == 3) return write_native_flags(address & ~NATIVE_MASK, data); else return memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wopf(), address, data, 0xffffffffffffffffU); }
- u16 write_qword_flags(offs_t address, u64 data, u64 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, true>(wopf(), address, data, mask); }
- u16 write_qword_unaligned_flags(offs_t address, u64 data) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, 0xffffffffffffffffU); }
- u16 write_qword_unaligned_flags(offs_t address, u64 data, u64 mask) override { return memory_write_generic_flags<Width, AddrShift, Endian, 3, false>(wopf(), address, data, mask); }
-
// static access to these functions
static u8 read_byte_static(this_type &space, offs_t address) { return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); }
@@ -564,7 +428,7 @@ private:
osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
throw;
}
- install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r);
+ install_read_handler_helper<handler_width_v<READ> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r);
}
template<typename WRITE>
@@ -575,24 +439,7 @@ private:
osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
throw;
}
- install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w);
- }
-
- template<typename READ, typename WRITE>
- void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r, WRITE &handler_w)
- {
- static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match");
- try { handler_r.resolve(); }
- catch (const binding_type_exception &) {
- osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
- throw;
- }
- try { handler_w.resolve(); }
- catch (const binding_type_exception &) {
- osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
- throw;
- }
- install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r, handler_w);
+ install_write_handler_helper<handler_width_v<WRITE> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w);
}
template<int AccessWidth, typename READ>
@@ -659,50 +506,6 @@ private:
invalidate_caches(read_or_write::WRITE);
}
}
-
- template<int AccessWidth, typename READ, typename WRITE>
- void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags,
- const READ &handler_r,
- const WRITE &handler_w)
- {
- if constexpr (Width < AccessWidth) {
- fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
- } else {
- VPRINTF("address_space::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n",
- m_addrchars, addrstart, m_addrchars, addrend,
- m_addrchars, addrmask, m_addrchars, addrmirror,
- 8 << Width, 8 << AccessWidth,
- handler_r.name(), handler_w.name(), data_width() / 4, unitmask);
-
- offs_t nstart, nend, nmask, nmirror;
- u64 nunitmask;
- int ncswidth;
- check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth);
-
- if constexpr (Width == AccessWidth) {
- auto hand_r = new handler_entry_read_delegate <Width, AddrShift, READ>(this, flags, handler_r);
- hand_r->set_address_info(nstart, nmask);
- m_root_read ->populate(nstart, nend, nmirror, hand_r);
-
- auto hand_w = new handler_entry_write_delegate<Width, AddrShift, WRITE>(this, flags, handler_w);
- hand_w->set_address_info(nstart, nmask);
- m_root_write->populate(nstart, nend, nmirror, hand_w);
- } else {
- auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, READ>(this, flags, handler_r);
- memory_units_descriptor<Width, AddrShift> descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth);
- hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
- m_root_read ->populate_mismatched(nstart, nend, nmirror, descriptor);
- hand_r->unref();
-
- auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, WRITE>(this, flags, handler_w);
- descriptor.set_subunit_handler(hand_w);
- hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
- m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor);
- hand_w->unref();
- }
- invalidate_caches(read_or_write::READWRITE);
- }
- }
};
@@ -810,8 +613,8 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m
m_spacenum(spacenum),
m_log_unmap(true),
m_name(memory.space_config(spacenum)->name()),
- m_notifier_id(0),
- m_in_notification(0)
+ m_in_notification(0),
+ m_default_mpl(make_mph(nullptr))
{
}
@@ -1084,73 +887,78 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_
view.make_subdispatch(""); // Must be called after populate
}
-memory_passthrough_handler *address_space::make_mph()
+std::shared_ptr<emu::detail::memory_passthrough_handler_impl> address_space::make_mph(memory_passthrough_handler *mph)
{
- m_mphs.emplace_back(std::make_unique<memory_passthrough_handler>(*this));
- return m_mphs.back().get();
+ if (mph)
+ {
+ auto impl(mph->m_impl.lock());
+ if (impl)
+ {
+ assert(&impl->m_space == this);
+ return impl;
+ }
+ }
+ return m_mphs.emplace_back(std::make_shared<emu::detail::memory_passthrough_handler_impl>(*this));
}
//-------------------------------------------------
// install_read_tap - install a read tap on the bus
//-------------------------------------------------
-template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = make_mph();
+ auto impl = make_mph(mph);
- auto handler = new handler_entry_read_tap<Width, AddrShift>(this, *mph, name, tap);
+ auto handler = new handler_entry_read_tap<Width, AddrShift>(this, *impl, name, tap);
m_root_read->populate_passthrough(nstart, nend, nmirror, handler);
handler->unref();
invalidate_caches(read_or_write::READ);
- return mph;
+ return impl;
}
//-------------------------------------------------
// install_write_tap - install a write tap on the bus
//-------------------------------------------------
-template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = make_mph();
+ auto impl = make_mph(mph);
- auto handler = new handler_entry_write_tap<Width, AddrShift>(this, *mph, name, tap);
+ auto handler = new handler_entry_write_tap<Width, AddrShift>(this, *impl, name, tap);
m_root_write->populate_passthrough(nstart, nend, nmirror, handler);
handler->unref();
invalidate_caches(read_or_write::WRITE);
- return mph;
+ return impl;
}
//-------------------------------------------------
// install_write_tap - install a read and a write tap on the bus
//-------------------------------------------------
-template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler *address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passthrough_handler address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = make_mph();
+ auto impl = make_mph(mph);
- auto rhandler = new handler_entry_read_tap <Width, AddrShift>(this, *mph, name, tapr);
+ auto rhandler = new handler_entry_read_tap <Width, AddrShift>(this, *impl, name, tapr);
m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler);
rhandler->unref();
- auto whandler = new handler_entry_write_tap<Width, AddrShift>(this, *mph, name, tapw);
+ auto whandler = new handler_entry_write_tap<Width, AddrShift>(this, *impl, name, tapw);
m_root_write->populate_passthrough(nstart, nend, nmirror, whandler);
whandler->unref();
invalidate_caches(read_or_write::READWRITE);
- return mph;
+ return impl;
}
@@ -1218,6 +1026,194 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> memory_passth
//-------------------------------------------------
+// install the wait state handlers
+//-------------------------------------------------
+
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_read_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_read_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_read_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_write_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_write_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_write_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_readwrite_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_readwrite_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_device.tag());
+
+ VPRINTF("address_space::install_readwrite_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_read->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(this, *m_default_mpl, ws);
+ m_root_write->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+
+
+
+//-------------------------------------------------
// install_bank_generic - install a range as
// mapping to a particular bank
//-------------------------------------------------
@@ -1291,19 +1287,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_
// MEMORY MAPPING HELPERS
//**************************************************************************
-int address_space::add_change_notifier(std::function<void (read_or_write)> n)
+util::notifier_subscription address_space::add_change_notifier(delegate<void (read_or_write)> &&n)
{
- int id = m_notifier_id++;
- m_notifiers.emplace_back(notifier_t{ std::move(n), id });
- return id;
-}
-
-void address_space::remove_change_notifier(int id)
-{
- for(auto i = m_notifiers.begin(); i != m_notifiers.end(); i++)
- if (i->m_id == id) {
- m_notifiers.erase(i);
- return;
- }
- fatalerror("Unknown notifier id %d, double remove?\n", id);
+ return m_notifiers.subscribe(std::move(n));
}
diff --git a/src/emu/emumem_hea.h b/src/emu/emumem_hea.h
index e8308a73960..9ee6f8c8a1e 100644
--- a/src/emu/emumem_hea.h
+++ b/src/emu/emumem_hea.h
@@ -8,7 +8,7 @@
template<int Width, int AddrShift> class handler_entry_read_address : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_address(address_space *space, u32 flags) : handler_entry_read<Width, AddrShift>(space, flags) {}
~handler_entry_read_address() = default;
@@ -25,7 +25,7 @@ protected:
template<int Width, int AddrShift> class handler_entry_write_address : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
diff --git a/src/emu/emumem_hedp.cpp b/src/emu/emumem_hedp.cpp
index e3a58381585..b053f84c592 100644
--- a/src/emu/emumem_hedp.cpp
+++ b/src/emu/emumem_hedp.cpp
@@ -10,7 +10,7 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16_delegate>::value ||
std::is_same<R, read32_delegate>::value ||
std::is_same<R, read64_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate(*this->m_space, ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift), mem_mask);
}
@@ -20,7 +20,7 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16m_delegate>::value ||
std::is_same<R, read32m_delegate>::value ||
std::is_same<R, read64m_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate(*this->m_space, ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift));
}
@@ -30,7 +30,7 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16s_delegate>::value ||
std::is_same<R, read32s_delegate>::value ||
std::is_same<R, read64s_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate(((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift), mem_mask);
}
@@ -40,7 +40,7 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16sm_delegate>::value ||
std::is_same<R, read32sm_delegate>::value ||
std::is_same<R, read64sm_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate(((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift));
}
@@ -50,7 +50,7 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16mo_delegate>::value ||
std::is_same<R, read32mo_delegate>::value ||
std::is_same<R, read64mo_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate(*this->m_space);
}
@@ -60,21 +60,31 @@ template<int Width, int AddrShift, typename READ> template<typename R>
std::is_same<R, read16smo_delegate>::value ||
std::is_same<R, read32smo_delegate>::value ||
std::is_same<R, read64smo_delegate>::value,
- typename emu::detail::handler_entry_size<Width>::uX> handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
+ emu::detail::handler_entry_size_t<Width> > handler_entry_read_delegate<Width, AddrShift, READ>::read_impl(offs_t offset, uX mem_mask) const
{
return m_delegate();
}
-template<int Width, int AddrShift, typename READ> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_delegate<Width, AddrShift, READ>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift, typename READ> emu::detail::handler_entry_size_t<Width> handler_entry_read_delegate<Width, AddrShift, READ>::read(offs_t offset, uX mem_mask) const
{
return read_impl<READ>(offset, mem_mask);
}
-template<int Width, int AddrShift, typename READ> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_delegate<Width, AddrShift, READ>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift, typename READ> emu::detail::handler_entry_size_t<Width> handler_entry_read_delegate<Width, AddrShift, READ>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return read_impl<READ>(offset, mem_mask);
+}
+
+template<int Width, int AddrShift, typename READ> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_delegate<Width, AddrShift, READ>::read_flags(offs_t offset, uX mem_mask) const
{
return std::pair<uX, u16>(read_impl<READ>(offset, mem_mask), this->m_flags);
}
+template<int Width, int AddrShift, typename READ> u16 handler_entry_read_delegate<Width, AddrShift, READ>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift, typename READ> std::string handler_entry_read_delegate<Width, AddrShift, READ>::name() const
{
return m_delegate.name();
@@ -145,12 +155,22 @@ template<int Width, int AddrShift, typename WRITE> void handler_entry_write_dele
write_impl<WRITE>(offset, data, mem_mask);
}
+template<int Width, int AddrShift, typename WRITE> void handler_entry_write_delegate<Width, AddrShift, WRITE>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ write_impl<WRITE>(offset, data, mem_mask);
+}
+
template<int Width, int AddrShift, typename WRITE> u16 handler_entry_write_delegate<Width, AddrShift, WRITE>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
write_impl<WRITE>(offset, data, mem_mask);
return this->m_flags;
}
+template<int Width, int AddrShift, typename WRITE> u16 handler_entry_write_delegate<Width, AddrShift, WRITE>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift, typename WRITE> std::string handler_entry_write_delegate<Width, AddrShift, WRITE>::name() const
{
return m_delegate.name();
@@ -159,16 +179,26 @@ template<int Width, int AddrShift, typename WRITE> std::string handler_entry_wri
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_ioport<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_ioport<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
return m_port->read();
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_ioport<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_ioport<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return m_port->read();
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_ioport<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
return std::pair<uX, u16>(m_port->read(), this->m_flags);
}
+template<int Width, int AddrShift> u16 handler_entry_read_ioport<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_read_ioport<Width, AddrShift>::name() const
{
return m_port->tag();
@@ -179,12 +209,22 @@ template<int Width, int AddrShift> void handler_entry_write_ioport<Width, AddrSh
m_port->write(data, mem_mask);
}
+template<int Width, int AddrShift> void handler_entry_write_ioport<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ m_port->write(data, mem_mask);
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_ioport<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
m_port->write(data, mem_mask);
return this->m_flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_ioport<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_write_ioport<Width, AddrShift>::name() const
{
return m_port->tag();
diff --git a/src/emu/emumem_hedp.h b/src/emu/emumem_hedp.h
index 805521643c8..6b8563bd5b5 100644
--- a/src/emu/emumem_hedp.h
+++ b/src/emu/emumem_hedp.h
@@ -12,13 +12,15 @@
template<int Width, int AddrShift, typename READ> class handler_entry_read_delegate : public handler_entry_read_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_delegate(address_space *space, u16 flags, const READ &delegate) : handler_entry_read_address<Width, AddrShift>(space, flags), m_delegate(delegate) {}
~handler_entry_read_delegate() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -71,13 +73,15 @@ private:
template<int Width, int AddrShift, typename WRITE> class handler_entry_write_delegate : public handler_entry_write_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_delegate(address_space *space, u16 flags, const WRITE &delegate) : handler_entry_write_address<Width, AddrShift>(space, flags), m_delegate(delegate) {}
~handler_entry_write_delegate() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -135,13 +139,15 @@ private:
template<int Width, int AddrShift> class handler_entry_read_ioport : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_ioport(address_space *space, u16 flags, ioport_port *port) : handler_entry_read<Width, AddrShift>(space, flags), m_port(port) {}
~handler_entry_read_ioport() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -152,13 +158,15 @@ private:
template<int Width, int AddrShift> class handler_entry_write_ioport : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_ioport(address_space *space, u16 flags, ioport_port *port) : handler_entry_write<Width, AddrShift>(space, flags), m_port(port) {}
~handler_entry_write_ioport() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
diff --git a/src/emu/emumem_hedr.h b/src/emu/emumem_hedr.h
index 277cb2d1c27..e1e9aa98743 100644
--- a/src/emu/emumem_hedr.h
+++ b/src/emu/emumem_hedr.h
@@ -13,7 +13,7 @@
template<int HighBits, int Width, int AddrShift> class handler_entry_read_dispatch : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
using mapping = typename handler_entry_read<Width, AddrShift>::mapping;
handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift> *handler);
@@ -22,7 +22,9 @@ public:
~handler_entry_read_dispatch();
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift> *&handler) const override;
diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp
index 3a192e33750..9994f251897 100644
--- a/src/emu/emumem_hedr.ipp
+++ b/src/emu/emumem_hedr.ipp
@@ -127,16 +127,26 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc
}
}
-template<int HighBits, int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_dispatch<HighBits, Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
return dispatch_read<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
-template<int HighBits, int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return dispatch_read_interruptible<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
+}
+
+template<int HighBits, int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
return dispatch_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
+template<int HighBits, int Width, int AddrShift> u16 handler_entry_read_dispatch<HighBits, Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return dispatch_lookup_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
+}
+
template<int HighBits, int Width, int AddrShift> void *handler_entry_read_dispatch<HighBits, Width, AddrShift>::get_ptr(offs_t offset) const
{
return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
@@ -196,6 +206,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc
cur->unref();
m_u_dispatch[entry] = subdispatch;
subdispatch->populate_nomirror(start, end, ostart, oend, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
@@ -271,6 +283,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc
cur->unref();
m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
@@ -435,23 +449,64 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatc
}
}
-
template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::passthrough_patch(handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift> *&target)
{
- handler_entry_read<Width, AddrShift> *original = target;
- handler_entry_read<Width, AddrShift> *replacement = nullptr;
+ // Look in cache first
for(const auto &p : mappings)
- if(p.original == original) {
- replacement = p.patched;
- break;
+ if(p.original == target) {
+ p.patched->ref();
+ target->unref();
+ target = p.patched;
+ return;
}
- if(!replacement) {
- replacement = handler->instantiate(original);
+
+ handler_entry_read<Width, AddrShift> *original = target;
+ u32 target_priority = original->f_get_pt();
+ u32 new_priority = handler->f_get_pt();
+
+ // 3 cases: new one on top, new one on bottom, or new one replaces old one
+
+ if(!target_priority || new_priority > target_priority || (new_priority == target_priority && !(new_priority & 1))) {
+ // New one goes over the old one
+ // previous one is not passthrough (target_priority = 0)
+ // new one has higher priority
+ // both have the same priority, and the priority is even which means keep both
+
+ // We instantiate the new one with the old one under it and put it in place and in the cache
+
+ handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(original);
mappings.emplace_back(mapping{ original, replacement });
- } else
- replacement->ref();
- target->unref();
- target = replacement;
+ target->unref();
+ target = replacement;
+
+ } else if(new_priority == target_priority) {
+ // New one replaces the old one
+ // both have the same priority, and the priority is odd which means keep only the new one
+
+ // We instantiate the new one with the old one's subtarget and put it in place and in the cache
+
+ handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler());
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+
+ } else {
+ // New one goes under the old one
+ // both are passthrough and new one has lower priority
+ //
+ // This can be recursive, so do the passthrough patch on the subhandler, then instantiate the old one with the result
+
+ handler_entry_read<Width, AddrShift> *recursive = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler();
+ recursive->ref();
+
+ passthrough_patch(handler, mappings, recursive);
+
+ handler_entry_read<Width, AddrShift> *replacement = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->instantiate(recursive);
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+ recursive->unref();
+ }
}
template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
diff --git a/src/emu/emumem_hedw.h b/src/emu/emumem_hedw.h
index 4c4f0f36037..130293a73a4 100644
--- a/src/emu/emumem_hedw.h
+++ b/src/emu/emumem_hedw.h
@@ -13,7 +13,7 @@
template<int HighBits, int Width, int AddrShift> class handler_entry_write_dispatch : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
using mapping = typename handler_entry_write<Width, AddrShift>::mapping;
handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write<Width, AddrShift> *handler);
@@ -22,7 +22,9 @@ public:
~handler_entry_write_dispatch();
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift> *&handler) const override;
diff --git a/src/emu/emumem_hedw.ipp b/src/emu/emumem_hedw.ipp
index d9c4ced36e4..37c09ccfe11 100644
--- a/src/emu/emumem_hedw.ipp
+++ b/src/emu/emumem_hedw.ipp
@@ -131,11 +131,21 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat
dispatch_write<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch);
}
+template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ dispatch_write_interruptible<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch);
+}
+
template<int HighBits, int Width, int AddrShift> u16 handler_entry_write_dispatch<HighBits, Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
return dispatch_write_flags<Level, Width, AddrShift>(HIGHMASK, offset, data, mem_mask, m_a_dispatch);
}
+template<int HighBits, int Width, int AddrShift> u16 handler_entry_write_dispatch<HighBits, Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return dispatch_lookup_write_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
+}
+
template<int HighBits, int Width, int AddrShift> void *handler_entry_write_dispatch<HighBits, Width, AddrShift>::get_ptr(offs_t offset) const
{
return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
@@ -195,6 +205,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat
cur->unref();
m_u_dispatch[entry] = subdispatch;
subdispatch->populate_nomirror(start, end, ostart, oend, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
@@ -270,6 +282,8 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat
cur->unref();
m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
@@ -437,20 +451,63 @@ template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispat
template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::passthrough_patch(handler_entry_write_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings, handler_entry_write<Width, AddrShift> *&target)
{
- handler_entry_write<Width, AddrShift> *original = target;
- handler_entry_write<Width, AddrShift> *replacement = nullptr;
+ // Look in cache first
for(const auto &p : mappings)
- if(p.original == original) {
- replacement = p.patched;
- break;
+ if(p.original == target) {
+ p.patched->ref();
+ target->unref();
+ target = p.patched;
+ return;
}
- if(!replacement) {
- replacement = handler->instantiate(original);
+
+ handler_entry_write<Width, AddrShift> *original = target;
+ u32 target_priority = original->f_get_pt();
+ u32 new_priority = handler->f_get_pt();
+
+ // 3 cases: new one on top, new one on bottom, or new one replaces old one
+
+ if(!target_priority || new_priority > target_priority || (new_priority == target_priority && !(new_priority & 1))) {
+ // New one goes over the old one
+ // previous one is not passthrough (target_priority = 0)
+ // new one has higher priority
+ // both have the same priority, and the priority is even which means keep both
+
+ // We instantiate the new one with the old one under it and put it in place and in the cache
+
+ handler_entry_write<Width, AddrShift> *replacement = handler->instantiate(original);
mappings.emplace_back(mapping{ original, replacement });
- } else
- replacement->ref();
- target->unref();
- target = replacement;
+ target->unref();
+ target = replacement;
+
+ } else if(new_priority == target_priority) {
+ // New one replaces the old one
+ // both have the same priority, and the priority is odd which means keep only the new one
+
+ // We instantiate the new one with the old one's subtarget and put it in place and in the cache
+
+ handler_entry_write<Width, AddrShift> *replacement = handler->instantiate(static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->get_subhandler());
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+
+ } else {
+ // New one goes under the old one
+ // both are passthrough and new one has lower priority
+ //
+ // This can be recursive, so do the passthrough patch on the subhandler, then instantiate the old one with the result
+
+ handler_entry_write<Width, AddrShift> *recursive = static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->get_subhandler();
+ recursive->ref();
+
+ passthrough_patch(handler, mappings, recursive);
+
+ handler_entry_write<Width, AddrShift> *replacement = static_cast<handler_entry_write_passthrough<Width, AddrShift> *>(original)->instantiate(recursive);
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+ recursive->unref();
+ }
+
}
template<int HighBits, int Width, int AddrShift> void handler_entry_write_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
diff --git a/src/emu/emumem_hem.cpp b/src/emu/emumem_hem.cpp
index b835538c3dd..e69206d7653 100644
--- a/src/emu/emumem_hem.cpp
+++ b/src/emu/emumem_hem.cpp
@@ -5,16 +5,26 @@
#include "emumem_hea.h"
#include "emumem_hem.h"
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_memory<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
return m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)];
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_memory<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)];
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_memory<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
return std::pair<uX, u16>(m_base[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)], this->m_flags);
}
+template<int Width, int AddrShift> u16 handler_entry_read_memory<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> void *handler_entry_read_memory<Width, AddrShift>::get_ptr(offs_t offset) const
{
return m_base + (((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift));
@@ -32,6 +42,12 @@ template<int Width, int AddrShift> void handler_entry_write_memory<Width, AddrSh
m_base[off] = (m_base[off] & ~mem_mask) | (data & mem_mask);
}
+template<int Width, int AddrShift> void handler_entry_write_memory<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift);
+ m_base[off] = (m_base[off] & ~mem_mask) | (data & mem_mask);
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift);
@@ -39,11 +55,21 @@ template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShi
return this->m_flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_memory<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<> void handler_entry_write_memory<0, 0>::write(offs_t offset, u8 data, u8 mem_mask) const
{
m_base[(offset - this->m_address_base) & this->m_address_mask] = data;
}
+template<> void handler_entry_write_memory<0, 0>::write_interruptible(offs_t offset, u8 data, u8 mem_mask) const
+{
+ m_base[(offset - this->m_address_base) & this->m_address_mask] = data;
+}
+
template<> u16 handler_entry_write_memory<0, 0>::write_flags(offs_t offset, u8 data, u8 mem_mask) const
{
m_base[(offset - this->m_address_base) & this->m_address_mask] = data;
@@ -64,16 +90,26 @@ template<int Width, int AddrShift> std::string handler_entry_write_memory<Width,
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_memory_bank<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory_bank<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
return static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)];
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_memory_bank<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_memory_bank<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)];
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_memory_bank<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
return std::pair<uX, u16>(static_cast<uX *>(m_bank.base())[((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift)], this->m_flags);
}
+template<int Width, int AddrShift> u16 handler_entry_read_memory_bank<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> void *handler_entry_read_memory_bank<Width, AddrShift>::get_ptr(offs_t offset) const
{
return static_cast<uX *>(m_bank.base()) + (((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift));
@@ -91,6 +127,12 @@ template<int Width, int AddrShift> void handler_entry_write_memory_bank<Width, A
static_cast<uX *>(m_bank.base())[off] = (static_cast<uX *>(m_bank.base())[off] & ~mem_mask) | (data & mem_mask);
}
+template<int Width, int AddrShift> void handler_entry_write_memory_bank<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift);
+ static_cast<uX *>(m_bank.base())[off] = (static_cast<uX *>(m_bank.base())[off] & ~mem_mask) | (data & mem_mask);
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
offs_t off = ((offset - this->m_address_base) & this->m_address_mask) >> (Width + AddrShift);
@@ -98,11 +140,21 @@ template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, Ad
return this->m_flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_memory_bank<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<> void handler_entry_write_memory_bank<0, 0>::write(offs_t offset, u8 data, u8 mem_mask) const
{
static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data;
}
+template<> void handler_entry_write_memory_bank<0, 0>::write_interruptible(offs_t offset, u8 data, u8 mem_mask) const
+{
+ static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data;
+}
+
template<> u16 handler_entry_write_memory_bank<0, 0>::write_flags(offs_t offset, u8 data, u8 mem_mask) const
{
static_cast<uX *>(m_bank.base())[(offset - this->m_address_base) & this->m_address_mask] = data;
diff --git a/src/emu/emumem_hem.h b/src/emu/emumem_hem.h
index b5edc2c27dc..d4c8c145860 100644
--- a/src/emu/emumem_hem.h
+++ b/src/emu/emumem_hem.h
@@ -12,13 +12,15 @@
template<int Width, int AddrShift> class handler_entry_read_memory : public handler_entry_read_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_memory(address_space *space, u16 flags, void *base) : handler_entry_read_address<Width, AddrShift>(space, flags), m_base(reinterpret_cast<uX *>(base)) {}
~handler_entry_read_memory() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
std::string name() const override;
@@ -30,13 +32,15 @@ private:
template<int Width, int AddrShift> class handler_entry_write_memory : public handler_entry_write_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_memory(address_space *space, u16 flags, void *base) : handler_entry_write_address<Width, AddrShift>(space, flags), m_base(reinterpret_cast<uX *>(base)) {}
~handler_entry_write_memory() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
std::string name() const override;
@@ -53,13 +57,15 @@ private:
template<int Width, int AddrShift> class handler_entry_read_memory_bank : public handler_entry_read_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_memory_bank(address_space *space, u16 flags, memory_bank &bank) : handler_entry_read_address<Width, AddrShift>(space, flags), m_bank(bank) {}
~handler_entry_read_memory_bank() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
std::string name() const override;
@@ -71,13 +77,15 @@ private:
template<int Width, int AddrShift> class handler_entry_write_memory_bank : public handler_entry_write_address<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_memory_bank(address_space *space, u16 flags, memory_bank &bank) : handler_entry_write_address<Width, AddrShift>(space, flags), m_bank(bank) {}
~handler_entry_write_memory_bank() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
void *get_ptr(offs_t offset) const override;
std::string name() const override;
diff --git a/src/emu/emumem_hep.h b/src/emu/emumem_hep.h
index 60fc422b72e..bc8616cea2b 100644
--- a/src/emu/emumem_hep.h
+++ b/src/emu/emumem_hep.h
@@ -8,9 +8,9 @@
template<int Width, int AddrShift> class handler_entry_read_passthrough : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
- handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {}
+ handler_entry_read_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio) : handler_entry_read<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(nullptr) {}
~handler_entry_read_passthrough();
virtual handler_entry_read_passthrough<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const = 0;
@@ -20,18 +20,18 @@ public:
void detach(const std::unordered_set<handler_entry *> &handlers) override;
protected:
- memory_passthrough_handler &m_mph;
+ emu::detail::memory_passthrough_handler_impl &m_mph;
handler_entry_read<Width, AddrShift> *m_next;
- handler_entry_read_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_read<Width, AddrShift> *next) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); }
+ handler_entry_read_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio, handler_entry_read<Width, AddrShift> *next) : handler_entry_read<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); }
};
template<int Width, int AddrShift> class handler_entry_write_passthrough : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
- handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(nullptr) {}
+ handler_entry_write_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio) : handler_entry_write<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(nullptr) {}
~handler_entry_write_passthrough();
virtual handler_entry_write_passthrough<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const = 0;
@@ -41,8 +41,8 @@ public:
void detach(const std::unordered_set<handler_entry *> &handlers) override;
protected:
- memory_passthrough_handler &m_mph;
+ emu::detail::memory_passthrough_handler_impl &m_mph;
handler_entry_write<Width, AddrShift> *m_next;
- handler_entry_write_passthrough(address_space *space, memory_passthrough_handler &mph, handler_entry_write<Width, AddrShift> *next) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_PASSTHROUGH), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); }
+ handler_entry_write_passthrough(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, u32 prio, handler_entry_write<Width, AddrShift> *next) : handler_entry_write<Width, AddrShift>(space, handler_entry::f_pt(prio)), m_mph(mph), m_next(next) { next->ref(); mph.add_handler(this); }
};
diff --git a/src/emu/emumem_het.cpp b/src/emu/emumem_het.cpp
index 1360badd99c..23349659a48 100644
--- a/src/emu/emumem_het.cpp
+++ b/src/emu/emumem_het.cpp
@@ -5,7 +5,7 @@
#include "emumem_hep.h"
#include "emumem_het.h"
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_tap<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_tap<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
this->ref();
@@ -16,7 +16,18 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt
return data;
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_tap<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_tap<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ this->ref();
+
+ uX data = this->m_next->read_interruptible(offset, mem_mask);
+ m_tap(offset, data, mem_mask);
+
+ this->unref();
+ return data;
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_tap<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
this->ref();
@@ -27,6 +38,11 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry
return pack;
}
+template<int Width, int AddrShift> u16 handler_entry_read_tap<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
template<int Width, int AddrShift> std::string handler_entry_read_tap<Width, AddrShift>::name() const
{
return '(' + m_name + ") " + this->m_next->name();
@@ -48,6 +64,16 @@ template<int Width, int AddrShift> void handler_entry_write_tap<Width, AddrShift
this->unref();
}
+template<int Width, int AddrShift> void handler_entry_write_tap<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ this->ref();
+
+ m_tap(offset, data, mem_mask);
+ this->m_next->write_interruptible(offset, data, mem_mask);
+
+ this->unref();
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
this->ref();
@@ -59,6 +85,11 @@ template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift>
return flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_tap<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
template<int Width, int AddrShift> std::string handler_entry_write_tap<Width, AddrShift>::name() const
{
return '(' + m_name + ") " + this->m_next->name();
diff --git a/src/emu/emumem_het.h b/src/emu/emumem_het.h
index 2914605772b..97650c6cbe3 100644
--- a/src/emu/emumem_het.h
+++ b/src/emu/emumem_het.h
@@ -12,13 +12,15 @@
template<int Width, int AddrShift> class handler_entry_read_tap : public handler_entry_read_passthrough<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
- handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph), m_name(name), m_tap(std::move(tap)) {}
+ handler_entry_read_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 4), m_name(name), m_tap(std::move(tap)) {}
~handler_entry_read_tap() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -28,19 +30,21 @@ protected:
std::string m_name;
std::function<void (offs_t offset, uX &data, uX mem_mask)> m_tap;
- handler_entry_read_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_read<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, next), m_name(name), m_tap(tap) {}
+ handler_entry_read_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 4, next), m_name(name), m_tap(tap) {}
};
template<int Width, int AddrShift> class handler_entry_write_tap : public handler_entry_write_passthrough<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
- handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph), m_name(name), m_tap(std::move(tap)) {}
+ handler_entry_write_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 4), m_name(name), m_tap(std::move(tap)) {}
~handler_entry_write_tap() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -50,7 +54,7 @@ protected:
std::string m_name;
std::function<void (offs_t offset, uX &data, uX mem_mask)> m_tap;
- handler_entry_write_tap(address_space *space, memory_passthrough_handler &mph, handler_entry_write<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, next), m_name(name), m_tap(tap) {}
+ handler_entry_write_tap(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 4, next), m_name(name), m_tap(tap) {}
};
#endif // MAME_EMU_EMUMEM_HET_H
diff --git a/src/emu/emumem_heu.cpp b/src/emu/emumem_heu.cpp
index 3c05a1e04da..ada5d56d63a 100644
--- a/src/emu/emumem_heu.cpp
+++ b/src/emu/emumem_heu.cpp
@@ -75,7 +75,7 @@ template<int Width, int AddrShift> void handler_entry_read_units<Width, AddrShif
}
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_units<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_units<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
this->ref();
@@ -104,7 +104,12 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt
return result;
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_units<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_units<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return read(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_units<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
this->ref();
@@ -137,7 +142,36 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry
return std::make_pair(result, flags);
}
-template<int Width, int AddrShift> std::string handler_entry_read_units<Width, AddrShift>::m2r(typename emu::detail::handler_entry_size<Width>::uX mask)
+template<int Width, int AddrShift> u16 handler_entry_read_units<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ this->ref();
+
+ u16 flags = 0;
+ for (int index = 0; index < m_subunits; index++) {
+ const subunit_info &si = m_subunit_infos[index];
+ if (mem_mask & si.m_amask) {
+ offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset;
+ switch(si.m_width) {
+ case 0:
+ flags |= static_cast<handler_entry_read<0, 0> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ case 1:
+ flags |= static_cast<handler_entry_read<1, -1> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ case 2:
+ flags |= static_cast<handler_entry_read<2, -2> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+
+ this->unref();
+ return flags;
+}
+
+template<int Width, int AddrShift> std::string handler_entry_read_units<Width, AddrShift>::m2r(emu::detail::handler_entry_size_t<Width> mask)
{
constexpr u32 mbits = 8*sizeof(uX);
u32 start, end;
@@ -256,6 +290,11 @@ template<int Width, int AddrShift> void handler_entry_write_units<Width, AddrShi
this->unref();
}
+template<int Width, int AddrShift> void handler_entry_write_units<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ write(offset, data, mem_mask);
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
this->ref();
@@ -285,8 +324,37 @@ template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShif
return flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_units<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ this->ref();
+
+ u16 flags = 0;
+ for (int index = 0; index < m_subunits; index++) {
+ const subunit_info &si = m_subunit_infos[index];
+ if (mem_mask & si.m_amask) {
+ offs_t aoffset = (si.m_ashift >= 0 ? offset >> si.m_ashift : offset << si.m_ashift) + si.m_offset;
+ switch(si.m_width) {
+ case 0:
+ flags |= static_cast<handler_entry_write<0, 0> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ case 1:
+ flags |= static_cast<handler_entry_write<1, -1> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ case 2:
+ flags |= static_cast<handler_entry_write<2, -2> *>(si.m_handler)->lookup_flags(aoffset, mem_mask >> si.m_dshift);
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+
+ this->unref();
+ return flags;
+}
+
-template<int Width, int AddrShift> std::string handler_entry_write_units<Width, AddrShift>::m2r(typename emu::detail::handler_entry_size<Width>::uX mask)
+template<int Width, int AddrShift> std::string handler_entry_write_units<Width, AddrShift>::m2r(emu::detail::handler_entry_size_t<Width> mask)
{
constexpr u32 mbits = 8*sizeof(uX);
u32 start, end;
diff --git a/src/emu/emumem_heu.h b/src/emu/emumem_heu.h
index 4b44a72db09..8573cc4e334 100644
--- a/src/emu/emumem_heu.h
+++ b/src/emu/emumem_heu.h
@@ -12,7 +12,7 @@
template<int Width, int AddrShift> class handler_entry_read_units : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, address_space *space);
handler_entry_read_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, const handler_entry_read_units *src);
@@ -20,7 +20,9 @@ public:
~handler_entry_read_units();
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
@@ -54,7 +56,7 @@ private:
template<int Width, int AddrShift> class handler_entry_write_units : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, address_space *space);
handler_entry_write_units(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 ukey, const handler_entry_write_units<Width, AddrShift> *src);
@@ -62,7 +64,9 @@ public:
~handler_entry_write_units();
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
diff --git a/src/emu/emumem_heun.cpp b/src/emu/emumem_heun.cpp
index 4caa177c195..5157c2c35df 100644
--- a/src/emu/emumem_heun.cpp
+++ b/src/emu/emumem_heun.cpp
@@ -5,7 +5,7 @@
#include "emumem_hea.h"
#include "emumem_heun.h"
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_unmapped<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_unmapped<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
this->m_space->device().logerror(this->m_space->is_octal()
@@ -17,7 +17,19 @@ template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Widt
return this->m_space->unmap();
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_unmapped<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_unmapped<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
+ this->m_space->device().logerror(this->m_space->is_octal()
+ ? "%s: unmapped %s memory read from %0*o & %0*o\n"
+ : "%s: unmapped %s memory read from %0*X & %0*X\n",
+ this->m_space->m_manager.machine().describe_context(), this->m_space->name(),
+ this->m_space->addrchars(), offset,
+ 2 << Width, mem_mask);
+ return this->m_space->unmap();
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_unmapped<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
this->m_space->device().logerror(this->m_space->is_octal()
@@ -29,6 +41,18 @@ template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry
return std::pair<uX, u16>(this->m_space->unmap(), this->m_flags);
}
+template<int Width, int AddrShift> u16 handler_entry_read_unmapped<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
+ this->m_space->device().logerror(this->m_space->is_octal()
+ ? "%s: unmapped %s memory read flags lookup from %0*o & %0*o\n"
+ : "%s: unmapped %s memory read flags lookup from %0*X & %0*X\n",
+ this->m_space->m_manager.machine().describe_context(), this->m_space->name(),
+ this->m_space->addrchars(), offset,
+ 2 << Width, mem_mask);
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_read_unmapped<Width, AddrShift>::name() const
{
return "unmapped";
@@ -47,6 +71,18 @@ template<int Width, int AddrShift> void handler_entry_write_unmapped<Width, Addr
2 << Width, mem_mask);
}
+template<int Width, int AddrShift> void handler_entry_write_unmapped<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask)const
+{
+ if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
+ this->m_space->device().logerror(this->m_space->is_octal()
+ ? "%s: unmapped %s memory write to %0*o = %0*o & %0*o\n"
+ : "%s: unmapped %s memory write to %0*X = %0*X & %0*X\n",
+ this->m_space->m_manager.machine().describe_context(), this->m_space->name(),
+ this->m_space->addrchars(), offset,
+ 2 << Width, data,
+ 2 << Width, mem_mask);
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask)const
{
if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
@@ -60,6 +96,18 @@ template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrS
return this->m_flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_unmapped<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask)const
+{
+ if (this->m_space->log_unmap() && !this->m_space->m_manager.machine().side_effects_disabled())
+ this->m_space->device().logerror(this->m_space->is_octal()
+ ? "%s: unmapped %s write flags lookup from %0*o & %0*o\n"
+ : "%s: unmapped %s write flags lookup from %0*X & %0*X\n",
+ this->m_space->m_manager.machine().describe_context(), this->m_space->name(),
+ this->m_space->addrchars(), offset,
+ 2 << Width, mem_mask);
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_write_unmapped<Width, AddrShift>::name() const
{
return "unmapped";
@@ -68,16 +116,26 @@ template<int Width, int AddrShift> std::string handler_entry_write_unmapped<Widt
-template<int Width, int AddrShift> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_nop<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_nop<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
{
return this->m_space->unmap();
}
-template<int Width, int AddrShift> std::pair<typename emu::detail::handler_entry_size<Width>::uX, u16> handler_entry_read_nop<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_nop<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return this->m_space->unmap();
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_nop<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
return std::pair<uX, u16>(this->m_space->unmap(), this->m_flags);
}
+template<int Width, int AddrShift> u16 handler_entry_read_nop<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_read_nop<Width, AddrShift>::name() const
{
return "nop";
@@ -88,11 +146,20 @@ template<int Width, int AddrShift> void handler_entry_write_nop<Width, AddrShift
{
}
+template<int Width, int AddrShift> void handler_entry_write_nop<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+}
+
template<int Width, int AddrShift> u16 handler_entry_write_nop<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
{
return this->m_flags;
}
+template<int Width, int AddrShift> u16 handler_entry_write_nop<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_flags;
+}
+
template<int Width, int AddrShift> std::string handler_entry_write_nop<Width, AddrShift>::name() const
{
return "nop";
diff --git a/src/emu/emumem_heun.h b/src/emu/emumem_heun.h
index e355bbe8177..69a97e84f37 100644
--- a/src/emu/emumem_heun.h
+++ b/src/emu/emumem_heun.h
@@ -12,13 +12,15 @@
template<int Width, int AddrShift> class handler_entry_read_unmapped : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_unmapped(address_space *space, u16 flags) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_UNMAP | flags) {}
~handler_entry_read_unmapped() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
};
@@ -26,13 +28,15 @@ public:
template<int Width, int AddrShift> class handler_entry_write_unmapped : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_unmapped(address_space *space, u16 flags) : handler_entry_write<Width, AddrShift>(space, handler_entry::F_UNMAP | flags) {}
~handler_entry_write_unmapped() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
};
@@ -46,13 +50,15 @@ public:
template<int Width, int AddrShift> class handler_entry_read_nop : public handler_entry_read<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_read_nop(address_space *space, u16 flags) : handler_entry_read<Width, AddrShift>(space, flags) {}
~handler_entry_read_nop() = default;
uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
};
@@ -60,13 +66,15 @@ public:
template<int Width, int AddrShift> class handler_entry_write_nop : public handler_entry_write<Width, AddrShift>
{
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
handler_entry_write_nop(address_space *space, u16 flags) : handler_entry_write<Width, AddrShift>(space, flags) {}
~handler_entry_write_nop() = default;
void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
std::string name() const override;
};
diff --git a/src/emu/emumem_hws.cpp b/src/emu/emumem_hws.cpp
new file mode 100644
index 00000000000..9aae20d9f4c
--- /dev/null
+++ b/src/emu/emumem_hws.cpp
@@ -0,0 +1,311 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+#include "emu.h"
+#include "emumem_hep.h"
+#include "emumem_hws.h"
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_time<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_time<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ u64 tc = m_cpu.total_cycles();
+ u64 ac = m_ws(offset, tc);
+
+ if(ac < tc)
+ ac = tc;
+
+ if(m_cpu.access_before_time(ac, tc))
+ return 0;
+
+ return this->m_next->read_interruptible(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_before_time<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_read_before_time<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_read_before_time<Width, AddrShift>::name() const
+{
+ return util::string_format("(bt %s) %s", m_ws.name(), this->m_next->name());
+}
+
+template<int Width, int AddrShift> handler_entry_read_before_time<Width, AddrShift> *handler_entry_read_before_time<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const
+{
+ return new handler_entry_read_before_time<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+template<int Width, int AddrShift> void handler_entry_write_before_time<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const
+{
+ this->m_next->write(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> void handler_entry_write_before_time<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ u64 tc = m_cpu.total_cycles();
+ u64 ac = m_ws(offset, tc);
+
+ if(ac < tc)
+ ac = tc;
+
+ if(m_cpu.access_before_time(ac, tc))
+ return;
+ this->m_next->write_interruptible(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_before_time<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
+{
+ return this->m_next->write_flags(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_before_time<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_write_before_time<Width, AddrShift>::name() const
+{
+ return util::string_format("(bt %s) %s", m_ws.name(), this->m_next->name());
+}
+
+
+template<int Width, int AddrShift> handler_entry_write_before_time<Width, AddrShift> *handler_entry_write_before_time<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const
+{
+ return new handler_entry_write_before_time<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+
+template class handler_entry_read_before_time<0, 1>;
+template class handler_entry_read_before_time<0, 0>;
+template class handler_entry_read_before_time<1, 3>;
+template class handler_entry_read_before_time<1, 0>;
+template class handler_entry_read_before_time<1, -1>;
+template class handler_entry_read_before_time<2, 3>;
+template class handler_entry_read_before_time<2, 0>;
+template class handler_entry_read_before_time<2, -1>;
+template class handler_entry_read_before_time<2, -2>;
+template class handler_entry_read_before_time<3, 0>;
+template class handler_entry_read_before_time<3, -1>;
+template class handler_entry_read_before_time<3, -2>;
+template class handler_entry_read_before_time<3, -3>;
+
+template class handler_entry_write_before_time<0, 1>;
+template class handler_entry_write_before_time<0, 0>;
+template class handler_entry_write_before_time<1, 3>;
+template class handler_entry_write_before_time<1, 0>;
+template class handler_entry_write_before_time<1, -1>;
+template class handler_entry_write_before_time<2, 3>;
+template class handler_entry_write_before_time<2, 0>;
+template class handler_entry_write_before_time<2, -1>;
+template class handler_entry_write_before_time<2, -2>;
+template class handler_entry_write_before_time<3, 0>;
+template class handler_entry_write_before_time<3, -1>;
+template class handler_entry_write_before_time<3, -2>;
+template class handler_entry_write_before_time<3, -3>;
+
+
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_delay<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_before_delay<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ if(m_cpu.access_before_delay(m_ws(offset), this))
+ return 0;
+
+ return this->m_next->read_interruptible(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_before_delay<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_read_before_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_read_before_delay<Width, AddrShift>::name() const
+{
+ return util::string_format("(bd %s) %s", m_ws.name(), this->m_next->name());
+}
+
+template<int Width, int AddrShift> handler_entry_read_before_delay<Width, AddrShift> *handler_entry_read_before_delay<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const
+{
+ return new handler_entry_read_before_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+template<int Width, int AddrShift> void handler_entry_write_before_delay<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const
+{
+ this->m_next->write(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> void handler_entry_write_before_delay<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ if(m_cpu.access_before_delay(m_ws(offset), this))
+ return;
+ this->m_next->write_interruptible(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_before_delay<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
+{
+ return this->m_next->write_flags(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_before_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_write_before_delay<Width, AddrShift>::name() const
+{
+ return util::string_format("(bd %s) %s", m_ws.name(), this->m_next->name());
+}
+
+
+template<int Width, int AddrShift> handler_entry_write_before_delay<Width, AddrShift> *handler_entry_write_before_delay<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const
+{
+ return new handler_entry_write_before_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+
+template class handler_entry_read_before_delay<0, 1>;
+template class handler_entry_read_before_delay<0, 0>;
+template class handler_entry_read_before_delay<1, 3>;
+template class handler_entry_read_before_delay<1, 0>;
+template class handler_entry_read_before_delay<1, -1>;
+template class handler_entry_read_before_delay<2, 3>;
+template class handler_entry_read_before_delay<2, 0>;
+template class handler_entry_read_before_delay<2, -1>;
+template class handler_entry_read_before_delay<2, -2>;
+template class handler_entry_read_before_delay<3, 0>;
+template class handler_entry_read_before_delay<3, -1>;
+template class handler_entry_read_before_delay<3, -2>;
+template class handler_entry_read_before_delay<3, -3>;
+
+template class handler_entry_write_before_delay<0, 1>;
+template class handler_entry_write_before_delay<0, 0>;
+template class handler_entry_write_before_delay<1, 3>;
+template class handler_entry_write_before_delay<1, 0>;
+template class handler_entry_write_before_delay<1, -1>;
+template class handler_entry_write_before_delay<2, 3>;
+template class handler_entry_write_before_delay<2, 0>;
+template class handler_entry_write_before_delay<2, -1>;
+template class handler_entry_write_before_delay<2, -2>;
+template class handler_entry_write_before_delay<3, 0>;
+template class handler_entry_write_before_delay<3, -1>;
+template class handler_entry_write_before_delay<3, -2>;
+template class handler_entry_write_before_delay<3, -3>;
+
+
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_after_delay<Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_after_delay<Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ auto r = this->m_next->read_interruptible(offset, mem_mask);
+ m_cpu.access_after_delay(m_ws(offset));
+ return r;
+}
+
+template<int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_after_delay<Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->read_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_read_after_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_read_after_delay<Width, AddrShift>::name() const
+{
+ return util::string_format("(ad %s) %s", m_ws.name(), this->m_next->name());
+}
+
+template<int Width, int AddrShift> handler_entry_read_after_delay<Width, AddrShift> *handler_entry_read_after_delay<Width, AddrShift>::instantiate(handler_entry_read<Width, AddrShift> *next) const
+{
+ return new handler_entry_read_after_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+template<int Width, int AddrShift> void handler_entry_write_after_delay<Width, AddrShift>::write(offs_t offset, uX data, uX mem_mask) const
+{
+ this->m_next->write(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> void handler_entry_write_after_delay<Width, AddrShift>::write_interruptible(offs_t offset, uX data, uX mem_mask) const
+{
+ this->m_next->write_interruptible(offset, data, mem_mask);
+ m_cpu.access_after_delay(m_ws(offset));
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_after_delay<Width, AddrShift>::write_flags(offs_t offset, uX data, uX mem_mask) const
+{
+ return this->m_next->write_flags(offset, data, mem_mask);
+}
+
+template<int Width, int AddrShift> u16 handler_entry_write_after_delay<Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
+{
+ return this->m_next->lookup_flags(offset, mem_mask);
+}
+
+template<int Width, int AddrShift> std::string handler_entry_write_after_delay<Width, AddrShift>::name() const
+{
+ return util::string_format("(ad %s) %s", m_ws.name(), this->m_next->name());
+}
+
+
+template<int Width, int AddrShift> handler_entry_write_after_delay<Width, AddrShift> *handler_entry_write_after_delay<Width, AddrShift>::instantiate(handler_entry_write<Width, AddrShift> *next) const
+{
+ return new handler_entry_write_after_delay<Width, AddrShift>(this->m_space, this->m_mph, next, m_ws);
+}
+
+
+
+template class handler_entry_read_after_delay<0, 1>;
+template class handler_entry_read_after_delay<0, 0>;
+template class handler_entry_read_after_delay<1, 3>;
+template class handler_entry_read_after_delay<1, 0>;
+template class handler_entry_read_after_delay<1, -1>;
+template class handler_entry_read_after_delay<2, 3>;
+template class handler_entry_read_after_delay<2, 0>;
+template class handler_entry_read_after_delay<2, -1>;
+template class handler_entry_read_after_delay<2, -2>;
+template class handler_entry_read_after_delay<3, 0>;
+template class handler_entry_read_after_delay<3, -1>;
+template class handler_entry_read_after_delay<3, -2>;
+template class handler_entry_read_after_delay<3, -3>;
+
+template class handler_entry_write_after_delay<0, 1>;
+template class handler_entry_write_after_delay<0, 0>;
+template class handler_entry_write_after_delay<1, 3>;
+template class handler_entry_write_after_delay<1, 0>;
+template class handler_entry_write_after_delay<1, -1>;
+template class handler_entry_write_after_delay<2, 3>;
+template class handler_entry_write_after_delay<2, 0>;
+template class handler_entry_write_after_delay<2, -1>;
+template class handler_entry_write_after_delay<2, -2>;
+template class handler_entry_write_after_delay<3, 0>;
+template class handler_entry_write_after_delay<3, -1>;
+template class handler_entry_write_after_delay<3, -2>;
+template class handler_entry_write_after_delay<3, -3>;
diff --git a/src/emu/emumem_hws.h b/src/emu/emumem_hws.h
new file mode 100644
index 00000000000..baaad6c7a07
--- /dev/null
+++ b/src/emu/emumem_hws.h
@@ -0,0 +1,162 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+#ifndef MAME_EMU_EMUMEM_HWS_H
+#define MAME_EMU_EMUMEM_HWS_H
+
+#pragma once
+
+// handler_entry_read_before_time/handler_entry_write_before_time
+// handler_entry_read_before_delay/handler_entry_write_before_delay
+// handler_entry_read_after_delay/handler_entry_write_after_delay
+
+// handlers which handle the different wait state cases
+
+template<int Width, int AddrShift> class handler_entry_read_before_time : public handler_entry_read_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_read_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_time_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_read_before_time() = default;
+
+ uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
+ std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_read_before_time<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override;
+
+protected:
+ ws_time_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_read_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_time_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+template<int Width, int AddrShift> class handler_entry_write_before_time : public handler_entry_write_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_write_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_time_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_write_before_time() = default;
+
+ void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
+ u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_write_before_time<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override;
+
+protected:
+ ws_time_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_write_before_time(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_time_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+
+
+template<int Width, int AddrShift> class handler_entry_read_before_delay : public handler_entry_read_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_read_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_read_before_delay() = default;
+
+ uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
+ std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_read_before_delay<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override;
+
+protected:
+ ws_delay_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_read_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 13, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+template<int Width, int AddrShift> class handler_entry_write_before_delay : public handler_entry_write_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_write_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 11), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_write_before_delay() = default;
+
+ void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
+ u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_write_before_delay<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override;
+
+protected:
+ ws_delay_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_write_before_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 11, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+
+
+template<int Width, int AddrShift> class handler_entry_read_after_delay : public handler_entry_read_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_read_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 9), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_read_after_delay() = default;
+
+ uX read(offs_t offset, uX mem_mask) const override;
+ uX read_interruptible(offs_t offset, uX mem_mask) const override;
+ std::pair<uX, u16> read_flags(offs_t offset, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_read_after_delay<Width, AddrShift> *instantiate(handler_entry_read<Width, AddrShift> *next) const override;
+
+protected:
+ ws_delay_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_read_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_read<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_read_passthrough<Width, AddrShift>(space, mph, 9, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+template<int Width, int AddrShift> class handler_entry_write_after_delay : public handler_entry_write_passthrough<Width, AddrShift>
+{
+public:
+ using uX = emu::detail::handler_entry_size_t<Width>;
+
+ handler_entry_write_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 9), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+ ~handler_entry_write_after_delay() = default;
+
+ void write(offs_t offset, uX data, uX mem_mask) const override;
+ void write_interruptible(offs_t offset, uX data, uX mem_mask) const override;
+ u16 write_flags(offs_t offset, uX data, uX mem_mask) const override;
+ u16 lookup_flags(offs_t offset, uX mem_mask) const override;
+
+ std::string name() const override;
+
+ handler_entry_write_after_delay<Width, AddrShift> *instantiate(handler_entry_write<Width, AddrShift> *next) const override;
+
+protected:
+ ws_delay_delegate m_ws;
+ cpu_device &m_cpu;
+
+ handler_entry_write_after_delay(address_space *space, emu::detail::memory_passthrough_handler_impl &mph, handler_entry_write<Width, AddrShift> *next, const ws_delay_delegate &ws) : handler_entry_write_passthrough<Width, AddrShift>(space, mph, 9, next), m_ws(ws), m_cpu(downcast<cpu_device &>(space->device())) {}
+};
+
+#endif // MAME_EMU_EMUMEM_HWS_H
diff --git a/src/emu/emumem_mud.cpp b/src/emu/emumem_mud.cpp
index b8fed565eea..4c52b5a1301 100644
--- a/src/emu/emumem_mud.cpp
+++ b/src/emu/emumem_mud.cpp
@@ -35,7 +35,7 @@ template<> u8 mask_to_ukey<u64>(u64 mask)
(mask & 0x00000000000000ff ? 0x01 : 0x00);
}
-template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::memory_units_descriptor(u8 access_width, endianness_t access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, typename emu::detail::handler_entry_size<Width>::uX unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian)
+template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::memory_units_descriptor(u8 access_width, endianness_t access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, emu::detail::handler_entry_size_t<Width> unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian)
{
u32 bits_per_access = 8 << access_width;
constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0;
@@ -86,7 +86,7 @@ template<int Width, int AddrShift> memory_units_descriptor<Width, AddrShift>::me
generate(m_keymap[i], unitmask, umasks[i], cswidth, bits_per_access, base_shift, shift, active_count);
}
-template<int Width, int AddrShift> void memory_units_descriptor<Width, AddrShift>::generate(u8 ukey, typename emu::detail::handler_entry_size<Width>::uX gumask, typename emu::detail::handler_entry_size<Width>::uX umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count)
+template<int Width, int AddrShift> void memory_units_descriptor<Width, AddrShift>::generate(u8 ukey, emu::detail::handler_entry_size_t<Width> gumask, emu::detail::handler_entry_size_t<Width> umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count)
{
auto &entries = m_entries_for_key[ukey];
diff --git a/src/emu/emumem_mud.h b/src/emu/emumem_mud.h
index 12c8cf92eb5..4a8b6509aa0 100644
--- a/src/emu/emumem_mud.h
+++ b/src/emu/emumem_mud.h
@@ -5,7 +5,7 @@
template<int Width, int AddrShift> class memory_units_descriptor {
public:
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
struct entry {
uX m_amask;
diff --git a/src/emu/emumem_mview.cpp b/src/emu/emumem_mview.cpp
index 06007c7d0b5..2456cadc7f9 100644
--- a/src/emu/emumem_mview.cpp
+++ b/src/emu/emumem_mview.cpp
@@ -25,6 +25,7 @@
#include "emumem_hedw.h"
#include "emumem_hep.h"
#include "emumem_het.h"
+#include "emumem_hws.h"
#define VERBOSE 0
@@ -37,58 +38,7 @@ template <typename Format, typename... Params> static void VPRINTF(Format &&fmt,
template <typename Format, typename... Params> static void VPRINTF(Format &&, Params &&...) {}
#endif
-namespace {
-
-template <typename Delegate> struct handler_width;
-template <> struct handler_width<read8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8m_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8s_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8sm_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8mo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<write8smo_delegate> { static constexpr int value = 0; };
-template <> struct handler_width<read16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16m_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16s_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16sm_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16mo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<write16smo_delegate> { static constexpr int value = 1; };
-template <> struct handler_width<read32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32m_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32s_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32sm_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32mo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<write32smo_delegate> { static constexpr int value = 2; };
-template <> struct handler_width<read64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<read64smo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64m_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64s_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; };
-template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; };
-} // anonymous namespace
+using emu::detail::handler_width_v;
address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs_t end)
{
@@ -98,7 +48,7 @@ address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs
template<int Level, int Width, int AddrShift>
class memory_view_entry_specific : public memory_view::memory_view_entry
{
- using uX = typename emu::detail::handler_entry_size<Width>::uX;
+ using uX = emu::detail::handler_entry_size_t<Width>;
using NativeType = uX;
// constants describing the native size
@@ -126,9 +76,9 @@ public:
using address_space_installer::install_write_tap;
using address_space_installer::install_readwrite_tap;
- virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
- virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
- virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph) override;
+ virtual memory_passthrough_handler install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph) override;
virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, bool quiet) override;
virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, read_or_write readorwrite, void *baseptr) override;
@@ -137,156 +87,119 @@ public:
virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, std::string rtag, std::string wtag) override;
virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask, int cswidth, u16 flags) override;
+ void install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+
+ void install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+
+ void install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws) override;
+ void install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
+ void install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws) override;
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler); }
void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
{ install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, whandler); }
- void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0, u16 flags = 0) override
- { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, rhandler, whandler); }
template<typename READ>
void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r)
@@ -296,7 +209,7 @@ public:
osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
throw;
}
- install_read_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r);
+ install_read_handler_helper<handler_width_v<READ> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r);
}
template<typename WRITE>
@@ -307,24 +220,7 @@ public:
osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
throw;
}
- install_write_handler_helper<handler_width<WRITE>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w);
- }
-
- template<typename READ, typename WRITE>
- void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags, READ &handler_r, WRITE &handler_w)
- {
- static_assert(handler_width<READ>::value == handler_width<WRITE>::value, "handler widths do not match");
- try { handler_r.resolve(); }
- catch (const binding_type_exception &) {
- osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
- throw;
- }
- try { handler_w.resolve(); }
- catch (const binding_type_exception &) {
- osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask);
- throw;
- }
- install_readwrite_handler_helper<handler_width<READ>::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_r, handler_w);
+ install_write_handler_helper<handler_width_v<WRITE> >(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, flags, handler_w);
}
template<int AccessWidth, typename READ>
@@ -339,6 +235,9 @@ public:
8 << Width, 8 << AccessWidth,
handler_r.name(), data_width() / 4, unitmask);
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
offs_t nstart, nend, nmask, nmirror;
u64 nunitmask;
int ncswidth;
@@ -372,6 +271,9 @@ public:
8 << Width, 8 << AccessWidth,
handler_w.name(), data_width() / 4, unitmask);
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
offs_t nstart, nend, nmask, nmirror;
u64 nunitmask;
int ncswidth;
@@ -391,50 +293,6 @@ public:
invalidate_caches(read_or_write::WRITE);
}
}
-
- template<int AccessWidth, typename READ, typename WRITE>
- void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, u16 flags,
- const READ &handler_r,
- const WRITE &handler_w)
- {
- if constexpr (Width < AccessWidth) {
- fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width);
- } else {
- VPRINTF("memory_view::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n",
- m_addrchars, addrstart, m_addrchars, addrend,
- m_addrchars, addrmask, m_addrchars, addrmirror,
- 8 << Width, 8 << AccessWidth,
- handler_r.name(), handler_w.name(), data_width() / 4, unitmask);
-
- offs_t nstart, nend, nmask, nmirror;
- u64 nunitmask;
- int ncswidth;
- check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth);
-
- if constexpr (Width == AccessWidth) {
- auto hand_r = new handler_entry_read_delegate <Width, AddrShift, READ>(m_view.m_space, flags, handler_r);
- hand_r->set_address_info(nstart, nmask);
- r() ->populate(nstart, nend, nmirror, hand_r);
-
- auto hand_w = new handler_entry_write_delegate<Width, AddrShift, WRITE>(m_view.m_space, flags, handler_w);
- hand_w->set_address_info(nstart, nmask);
- w()->populate(nstart, nend, nmirror, hand_w);
- } else {
- auto hand_r = new handler_entry_read_delegate <AccessWidth, -AccessWidth, READ>(m_view.m_space, flags, handler_r);
- memory_units_descriptor<Width, AddrShift> descriptor(AccessWidth, endianness(), hand_r, nstart, nend, nmask, nunitmask, ncswidth);
- hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
- r() ->populate_mismatched(nstart, nend, nmirror, descriptor);
- hand_r->unref();
-
- auto hand_w = new handler_entry_write_delegate<AccessWidth, -AccessWidth, WRITE>(m_view.m_space, flags, handler_w);
- descriptor.set_subunit_handler(hand_w);
- hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask());
- w()->populate_mismatched(nstart, nend, nmirror, descriptor);
- hand_w->unref();
- }
- invalidate_caches(read_or_write::READWRITE);
- }
- }
};
namespace {
@@ -578,7 +436,7 @@ void memory_view::memory_view_entry::prepare_map_generic(address_map &map, bool
if (!allow_alloc)
fatalerror("Trying to create memory in range %X-%X too late\n", entry.m_addrstart, entry.m_addrend);
- entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend);
+ entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend, key());
}
}
}
@@ -645,8 +503,8 @@ memory_view::~memory_view()
void memory_view::register_state()
{
- m_device.machine().save().save_item(&m_device, "view", m_name.c_str(), 0, NAME(m_cur_slot));
- m_device.machine().save().save_item(&m_device, "view", m_name.c_str(), 0, NAME(m_cur_id));
+ m_device.machine().save().save_item(&m_device, "view", m_device.subtag(m_name).c_str(), 0, NAME(m_cur_slot));
+ m_device.machine().save().save_item(&m_device, "view", m_device.subtag(m_name).c_str(), 0, NAME(m_cur_id));
m_device.machine().save().register_postload(save_prepost_delegate(NAME([this]() { m_handler_read->select_a(m_cur_id); m_handler_write->select_a(m_cur_id); })));
}
@@ -898,70 +756,71 @@ template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Le
view.make_subdispatch(key()); // Must be called after populate
}
-template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_range_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = m_view.m_space->make_mph();
+ auto impl = m_view.m_space->make_mph(mph);
r()->select_u(m_id);
w()->select_u(m_id);
- auto handler = new handler_entry_read_tap<Width, AddrShift>(m_view.m_space, *mph, name, tap);
+ auto handler = new handler_entry_read_tap<Width, AddrShift>(m_view.m_space, *impl, name, tap);
r()->populate_passthrough(nstart, nend, nmirror, handler);
handler->unref();
invalidate_caches(read_or_write::READ);
- return mph;
+ return impl;
}
-template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tap, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_range_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = m_view.m_space->make_mph();
+ auto impl = m_view.m_space->make_mph(mph);
r()->select_u(m_id);
w()->select_u(m_id);
- auto handler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *mph, name, tap);
+ auto handler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *impl, name, tap);
w()->populate_passthrough(nstart, nend, nmirror, handler);
handler->unref();
invalidate_caches(read_or_write::WRITE);
- return mph;
+ return impl;
}
-template<int Level, int Width, int AddrShift> memory_passthrough_handler *memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph)
+template<int Level, int Width, int AddrShift> memory_passthrough_handler memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapr, std::function<void (offs_t offset, uX &data, uX mem_mask)> tapw, memory_passthrough_handler *mph)
{
offs_t nstart, nend, nmask, nmirror;
check_range_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
- if (!mph)
- mph = m_view.m_space->make_mph();
+ auto impl = m_view.m_space->make_mph(mph);
r()->select_u(m_id);
w()->select_u(m_id);
- auto rhandler = new handler_entry_read_tap <Width, AddrShift>(m_view.m_space, *mph, name, tapr);
+ auto rhandler = new handler_entry_read_tap <Width, AddrShift>(m_view.m_space, *impl, name, tapr);
r() ->populate_passthrough(nstart, nend, nmirror, rhandler);
rhandler->unref();
- auto whandler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *mph, name, tapw);
+ auto whandler = new handler_entry_write_tap<Width, AddrShift>(m_view.m_space, *impl, name, tapw);
w()->populate_passthrough(nstart, nend, nmirror, whandler);
whandler->unref();
invalidate_caches(read_or_write::READWRITE);
- return mph;
+ return impl;
}
template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth, u16 flags)
{
check_range_address("install_device_delegate", addrstart, addrend);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
address_map map(*m_view.m_space, addrstart, addrend, unitmask, cswidth, flags, m_view.m_device, delegate);
map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift());
prepare_device_map(map);
@@ -1008,6 +867,215 @@ template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Le
invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE);
}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_read_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_read_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_read_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_read_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_read_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+}
+
+
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_write_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_write_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_write_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_write_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_write_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_before_time(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_time_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_readwrite_before_time(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_before_time", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_before_time<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_before_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_readwrite_before_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_before_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_before_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_readwrite_after_delay(offs_t addrstart, offs_t addrend, offs_t addrmirror, ws_delay_delegate ws)
+{
+ auto *cpu = dynamic_cast<cpu_device *>(&m_view.m_device);
+ if (!cpu)
+ fatalerror("Attempted to a waitstate handler on non-cpu device '%s'\n", m_view.m_device.tag());
+ if (!cpu->cpu_is_interruptible())
+ fatalerror("Attempted to a waitstate handler on non-interruptible cpu device '%s'\n", m_view.m_device.tag());
+
+ VPRINTF("memory_view::install_readwrite_after_delay(%*x-%*x mirror=%*x ws=%s)\n",
+ m_addrchars, addrstart, m_addrchars, addrend,
+ m_addrchars, addrmirror, ws.name());
+
+ offs_t nstart, nend, nmask, nmirror;
+ check_optimize_mirror("install_readwrite_after_delay", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror);
+
+ r()->select_u(m_id);
+ w()->select_u(m_id);
+
+ auto hand_r = new handler_entry_read_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ r()->populate_passthrough(nstart, nend, nmirror, hand_r);
+ auto hand_w = new handler_entry_write_after_delay<Width, AddrShift>(m_view.m_space, *m_view.m_space->get_default_mpl(), ws);
+ w()->populate_passthrough(nstart, nend, nmirror, hand_w);
+}
+
+
template<int Level, int Width, int AddrShift> void memory_view_entry_specific<Level, Width, AddrShift>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 flags, memory_bank *rbank, memory_bank *wbank)
{
VPRINTF("memory_view::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n",
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp
index 8959c00da03..18b37734465 100644
--- a/src/emu/emuopts.cpp
+++ b/src/emu/emuopts.cpp
@@ -10,11 +10,15 @@
#include "emu.h"
#include "emuopts.h"
+
#include "drivenum.h"
-#include "softlist_dev.h"
#include "hashfile.h"
+#include "main.h"
+#include "softlist_dev.h"
+// lib/util
#include "corestr.h"
+#include "path.h"
#include <stack>
@@ -26,201 +30,202 @@
const options_entry emu_options::s_option_entries[] =
{
// unadorned options - only a single one supported at the moment
- { OPTION_SYSTEMNAME, nullptr, OPTION_STRING, nullptr },
- { OPTION_SOFTWARENAME, nullptr, OPTION_STRING, nullptr },
+ { OPTION_SYSTEMNAME, nullptr, core_options::option_type::STRING, nullptr },
+ { OPTION_SOFTWARENAME, nullptr, core_options::option_type::STRING, nullptr },
// config options
- { nullptr, nullptr, OPTION_HEADER, "CORE CONFIGURATION OPTIONS" },
- { OPTION_READCONFIG ";rc", "1", OPTION_BOOLEAN, "enable loading of configuration files" },
- { OPTION_WRITECONFIG ";wc", "0", OPTION_BOOLEAN, "write configuration to (driver).ini on exit" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE CONFIGURATION OPTIONS" },
+ { OPTION_READCONFIG ";rc", "1", core_options::option_type::BOOLEAN, "enable loading of configuration files" },
+ { OPTION_WRITECONFIG ";wc", "0", core_options::option_type::BOOLEAN, "write configuration to (driver).ini on exit" },
// search path options
- { nullptr, nullptr, OPTION_HEADER, "CORE SEARCH PATH OPTIONS" },
- { OPTION_PLUGINDATAPATH, ".", OPTION_STRING, "path to base folder for plugin data (read/write)" },
- { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", OPTION_STRING, "path to ROM sets and hard disk images" },
- { OPTION_HASHPATH ";hash_directory;hash", "hash", OPTION_STRING, "path to software definition files" },
- { OPTION_SAMPLEPATH ";sp", "samples", OPTION_STRING, "path to audio sample sets" },
- { OPTION_ARTPATH, "artwork", OPTION_STRING, "path to artwork files" },
- { OPTION_CTRLRPATH, "ctrlr", OPTION_STRING, "path to controller definitions" },
- { OPTION_INIPATH, ".;ini;ini/presets", OPTION_STRING, "path to ini files" },
- { OPTION_FONTPATH, ".", OPTION_STRING, "path to font files" },
- { OPTION_CHEATPATH, "cheat", OPTION_STRING, "path to cheat files" },
- { OPTION_CROSSHAIRPATH, "crosshair", OPTION_STRING, "path to crosshair files" },
- { OPTION_PLUGINSPATH, "plugins", OPTION_STRING, "path to plugin files" },
- { OPTION_LANGUAGEPATH, "language", OPTION_STRING, "path to UI translation files" },
- { OPTION_SWPATH, "software", OPTION_STRING, "path to loose software" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE SEARCH PATH OPTIONS" },
+ { OPTION_PLUGINDATAPATH, ".", core_options::option_type::PATH, "path to base folder for plugin data (read/write)" },
+ { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", core_options::option_type::MULTIPATH, "path to ROM sets and hard disk images" },
+ { OPTION_HASHPATH ";hash_directory;hash", "hash", core_options::option_type::MULTIPATH, "path to software definition files" },
+ { OPTION_SAMPLEPATH ";sp", "samples", core_options::option_type::MULTIPATH, "path to audio sample sets" },
+ { OPTION_ARTPATH, "artwork", core_options::option_type::MULTIPATH, "path to artwork files" },
+ { OPTION_CTRLRPATH, "ctrlr", core_options::option_type::MULTIPATH, "path to controller definitions" },
+ { OPTION_INIPATH, ".;ini;ini/presets", core_options::option_type::MULTIPATH, "path to ini files" },
+ { OPTION_FONTPATH, ".", core_options::option_type::MULTIPATH, "path to font files" },
+ { OPTION_CHEATPATH, "cheat", core_options::option_type::MULTIPATH, "path to cheat files" },
+ { OPTION_CROSSHAIRPATH, "crosshair", core_options::option_type::MULTIPATH, "path to crosshair files" },
+ { OPTION_PLUGINSPATH, "plugins", core_options::option_type::MULTIPATH, "path to plugin files" },
+ { OPTION_LANGUAGEPATH, "language", core_options::option_type::MULTIPATH, "path to UI translation files" },
+ { OPTION_SWPATH, "software", core_options::option_type::MULTIPATH, "path to loose software" },
// output directory options
- { nullptr, nullptr, OPTION_HEADER, "CORE OUTPUT DIRECTORY OPTIONS" },
- { OPTION_CFG_DIRECTORY, "cfg", OPTION_STRING, "directory to save configurations" },
- { OPTION_NVRAM_DIRECTORY, "nvram", OPTION_STRING, "directory to save NVRAM contents" },
- { OPTION_INPUT_DIRECTORY, "inp", OPTION_STRING, "directory to save input device logs" },
- { OPTION_STATE_DIRECTORY, "sta", OPTION_STRING, "directory to save states" },
- { OPTION_SNAPSHOT_DIRECTORY, "snap", OPTION_STRING, "directory to save/load screenshots" },
- { OPTION_DIFF_DIRECTORY, "diff", OPTION_STRING, "directory to save hard drive image difference files" },
- { OPTION_COMMENT_DIRECTORY, "comments", OPTION_STRING, "directory to save debugger comments" },
- { OPTION_SHARE_DIRECTORY, "share", OPTION_STRING, "directory to share with emulated machines" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE OUTPUT DIRECTORY OPTIONS" },
+ { OPTION_CFG_DIRECTORY, "cfg", core_options::option_type::PATH, "directory to save configurations" },
+ { OPTION_NVRAM_DIRECTORY, "nvram", core_options::option_type::PATH, "directory to save NVRAM contents" },
+ { OPTION_INPUT_DIRECTORY, "inp", core_options::option_type::PATH, "directory to save input device logs" },
+ { OPTION_STATE_DIRECTORY, "sta", core_options::option_type::PATH, "directory to save states" },
+ { OPTION_SNAPSHOT_DIRECTORY, "snap", core_options::option_type::PATH, "directory to save/load screenshots" },
+ { OPTION_DIFF_DIRECTORY, "diff", core_options::option_type::PATH, "directory to save hard drive image difference files" },
+ { OPTION_COMMENT_DIRECTORY, "comments", core_options::option_type::PATH, "directory to save debugger comments" },
+ { OPTION_SHARE_DIRECTORY, "share", core_options::option_type::PATH, "directory to share with emulated machines" },
// state/playback options
- { nullptr, nullptr, OPTION_HEADER, "CORE STATE/PLAYBACK OPTIONS" },
- { OPTION_STATE, nullptr, OPTION_STRING, "saved state to load" },
- { OPTION_AUTOSAVE, "0", OPTION_BOOLEAN, "automatically restore state on start and save on exit for supported systems" },
- { OPTION_REWIND, "0", OPTION_BOOLEAN, "enable rewind savestates" },
- { OPTION_REWIND_CAPACITY "(1-2048)", "100", OPTION_INTEGER, "rewind buffer size in megabytes" },
- { OPTION_PLAYBACK ";pb", nullptr, OPTION_STRING, "playback an input file" },
- { OPTION_RECORD ";rec", nullptr, OPTION_STRING, "record an input file" },
- { OPTION_EXIT_AFTER_PLAYBACK, "0", OPTION_BOOLEAN, "close the program at the end of playback" },
-
- { OPTION_MNGWRITE, nullptr, OPTION_STRING, "optional filename to write a MNG movie of the current session" },
- { OPTION_AVIWRITE, nullptr, OPTION_STRING, "optional filename to write an AVI movie of the current session" },
- { OPTION_WAVWRITE, nullptr, OPTION_STRING, "optional filename to write a WAV file of the current session" },
- { OPTION_SNAPNAME, "%g/%i", OPTION_STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" },
- { OPTION_SNAPSIZE, "auto", OPTION_STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " },
- { OPTION_SNAPVIEW, "auto", OPTION_STRING, "snapshot/movie view - 'auto' for default, or 'native' for per-screen pixel-aspect views" },
- { OPTION_SNAPBILINEAR, "1", OPTION_BOOLEAN, "specify if the snapshot/movie should have bilinear filtering applied" },
- { OPTION_STATENAME, "%g", OPTION_STRING, "override of the default state subfolder naming; %g == gamename" },
- { OPTION_BURNIN, "0", OPTION_BOOLEAN, "create burn-in snapshots for each screen" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE STATE/PLAYBACK OPTIONS" },
+ { OPTION_STATE, nullptr, core_options::option_type::STRING, "saved state to load" },
+ { OPTION_AUTOSAVE, "0", core_options::option_type::BOOLEAN, "automatically restore state on start and save on exit for supported systems" },
+ { OPTION_REWIND, "0", core_options::option_type::BOOLEAN, "enable rewind savestates" },
+ { OPTION_REWIND_CAPACITY "(1-2048)", "100", core_options::option_type::INTEGER, "rewind buffer size in megabytes" },
+ { OPTION_PLAYBACK ";pb", nullptr, core_options::option_type::STRING, "playback an input file" },
+ { OPTION_RECORD ";rec", nullptr, core_options::option_type::STRING, "record an input file" },
+ { OPTION_EXIT_AFTER_PLAYBACK, "0", core_options::option_type::BOOLEAN, "close the program at the end of playback" },
+
+ { OPTION_MNGWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a MNG movie of the current session" },
+ { OPTION_AVIWRITE, nullptr, core_options::option_type::PATH, "optional filename to write an AVI movie of the current session" },
+ { OPTION_WAVWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a WAV file of the current session" },
+ { OPTION_SNAPNAME, "%g/%i", core_options::option_type::STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" },
+ { OPTION_SNAPSIZE, "auto", core_options::option_type::STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " },
+ { OPTION_SNAPVIEW, "auto", core_options::option_type::STRING, "snapshot/movie view - 'auto' for default, or 'native' for per-screen pixel-aspect views" },
+ { OPTION_SNAPBILINEAR, "1", core_options::option_type::BOOLEAN, "specify if the snapshot/movie should have bilinear filtering applied" },
+ { OPTION_STATENAME, "%g", core_options::option_type::STRING, "override of the default state subfolder naming; %g == gamename" },
+ { OPTION_BURNIN, "0", core_options::option_type::BOOLEAN, "create burn-in snapshots for each screen" },
// performance options
- { nullptr, nullptr, OPTION_HEADER, "CORE PERFORMANCE OPTIONS" },
- { OPTION_AUTOFRAMESKIP ";afs", "0", OPTION_BOOLEAN, "enable automatic frameskip adjustment to maintain emulation speed" },
- { OPTION_FRAMESKIP ";fs(0-10)", "0", OPTION_INTEGER, "set frameskip to fixed value, 0-10 (upper limit with autoframeskip)" },
- { OPTION_SECONDS_TO_RUN ";str", "0", OPTION_INTEGER, "number of emulated seconds to run before automatically exiting" },
- { OPTION_THROTTLE, "1", OPTION_BOOLEAN, "throttle emulation to keep system running in sync with real time" },
- { OPTION_SLEEP, "1", OPTION_BOOLEAN, "enable sleeping, which gives time back to other applications when idle" },
- { OPTION_SPEED "(0.01-100)", "1.0", OPTION_FLOAT, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" },
- { OPTION_REFRESHSPEED ";rs", "0", OPTION_BOOLEAN, "automatically adjust emulation speed to keep the emulated refresh rate slower than the host screen" },
- { OPTION_LOWLATENCY ";lolat", "0", OPTION_BOOLEAN, "draws new frame before throttling to reduce input latency" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE PERFORMANCE OPTIONS" },
+ { OPTION_AUTOFRAMESKIP ";afs", "0", core_options::option_type::BOOLEAN, "enable automatic frameskip adjustment to maintain emulation speed" },
+ { OPTION_FRAMESKIP ";fs(0-10)", "0", core_options::option_type::INTEGER, "set frameskip to fixed value, 0-10 (upper limit with autoframeskip)" },
+ { OPTION_SECONDS_TO_RUN ";str", "0", core_options::option_type::INTEGER, "number of emulated seconds to run before automatically exiting" },
+ { OPTION_THROTTLE, "1", core_options::option_type::BOOLEAN, "throttle emulation to keep system running in sync with real time" },
+ { OPTION_SLEEP, "1", core_options::option_type::BOOLEAN, "enable sleeping, which gives time back to other applications when idle" },
+ { OPTION_SPEED "(0.01-100)", "1.0", core_options::option_type::FLOAT, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" },
+ { OPTION_REFRESHSPEED ";rs", "0", core_options::option_type::BOOLEAN, "automatically adjust emulation speed to keep the emulated refresh rate slower than the host screen" },
+ { OPTION_LOWLATENCY ";lolat", "0", core_options::option_type::BOOLEAN, "draws new frame before throttling to reduce input latency" },
// render options
- { nullptr, nullptr, OPTION_HEADER, "CORE RENDER OPTIONS" },
- { OPTION_KEEPASPECT ";ka", "1", OPTION_BOOLEAN, "maintain aspect ratio when scaling to fill output screen/window" },
- { OPTION_UNEVENSTRETCH ";ues", "1", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally or vertically" },
- { OPTION_UNEVENSTRETCHX ";uesx", "0", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally"},
- { OPTION_UNEVENSTRETCHY ";uesy", "0", OPTION_BOOLEAN, "allow non-integer ratios when scaling to fill otuput screen/window vertially"},
- { OPTION_AUTOSTRETCHXY ";asxy", "0", OPTION_BOOLEAN, "automatically apply -unevenstretchx/y based on source native orientation"},
- { OPTION_INTOVERSCAN ";ios", "0", OPTION_BOOLEAN, "allow overscan on integer scaled targets"},
- { OPTION_INTSCALEX ";sx", "0", OPTION_INTEGER, "set horizontal integer scale factor"},
- { OPTION_INTSCALEY ";sy", "0", OPTION_INTEGER, "set vertical integer scale factor"},
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE RENDER OPTIONS" },
+ { OPTION_KEEPASPECT ";ka", "1", core_options::option_type::BOOLEAN, "maintain aspect ratio when scaling to fill output screen/window" },
+ { OPTION_UNEVENSTRETCH ";ues", "1", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally or vertically" },
+ { OPTION_UNEVENSTRETCHX ";uesx", "0", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill output screen/window horizontally"},
+ { OPTION_UNEVENSTRETCHY ";uesy", "0", core_options::option_type::BOOLEAN, "allow non-integer ratios when scaling to fill otuput screen/window vertially"},
+ { OPTION_AUTOSTRETCHXY ";asxy", "0", core_options::option_type::BOOLEAN, "automatically apply -unevenstretchx/y based on source native orientation"},
+ { OPTION_INTOVERSCAN ";ios", "0", core_options::option_type::BOOLEAN, "allow overscan on integer scaled targets"},
+ { OPTION_INTSCALEX ";sx", "0", core_options::option_type::INTEGER, "set horizontal integer scale factor"},
+ { OPTION_INTSCALEY ";sy", "0", core_options::option_type::INTEGER, "set vertical integer scale factor"},
// rotation options
- { nullptr, nullptr, OPTION_HEADER, "CORE ROTATION OPTIONS" },
- { OPTION_ROTATE, "1", OPTION_BOOLEAN, "rotate the game screen according to the game's orientation when needed" },
- { OPTION_ROR, "0", OPTION_BOOLEAN, "rotate screen clockwise 90 degrees" },
- { OPTION_ROL, "0", OPTION_BOOLEAN, "rotate screen counterclockwise 90 degrees" },
- { OPTION_AUTOROR, "0", OPTION_BOOLEAN, "automatically rotate screen clockwise 90 degrees if vertical" },
- { OPTION_AUTOROL, "0", OPTION_BOOLEAN, "automatically rotate screen counterclockwise 90 degrees if vertical" },
- { OPTION_FLIPX, "0", OPTION_BOOLEAN, "flip screen left-right" },
- { OPTION_FLIPY, "0", OPTION_BOOLEAN, "flip screen upside-down" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE ROTATION OPTIONS" },
+ { OPTION_ROTATE, "1", core_options::option_type::BOOLEAN, "rotate the game screen according to the game's orientation when needed" },
+ { OPTION_ROR, "0", core_options::option_type::BOOLEAN, "rotate screen clockwise 90 degrees" },
+ { OPTION_ROL, "0", core_options::option_type::BOOLEAN, "rotate screen counterclockwise 90 degrees" },
+ { OPTION_AUTOROR, "0", core_options::option_type::BOOLEAN, "automatically rotate screen clockwise 90 degrees if vertical" },
+ { OPTION_AUTOROL, "0", core_options::option_type::BOOLEAN, "automatically rotate screen counterclockwise 90 degrees if vertical" },
+ { OPTION_FLIPX, "0", core_options::option_type::BOOLEAN, "flip screen left-right" },
+ { OPTION_FLIPY, "0", core_options::option_type::BOOLEAN, "flip screen upside-down" },
// artwork options
- { nullptr, nullptr, OPTION_HEADER, "CORE ARTWORK OPTIONS" },
- { OPTION_ARTWORK_CROP ";artcrop", "0", OPTION_BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" },
- { OPTION_FALLBACK_ARTWORK, nullptr, OPTION_STRING, "fallback artwork if no external artwork or internal driver layout defined" },
- { OPTION_OVERRIDE_ARTWORK, nullptr, OPTION_STRING, "override artwork for external artwork and internal driver layout" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE ARTWORK OPTIONS" },
+ { OPTION_ARTWORK_CROP ";artcrop", "0", core_options::option_type::BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" },
+ { OPTION_FALLBACK_ARTWORK, nullptr, core_options::option_type::STRING, "fallback artwork if no external artwork or internal driver layout defined" },
+ { OPTION_OVERRIDE_ARTWORK, nullptr, core_options::option_type::STRING, "override artwork for external artwork and internal driver layout" },
// screen options
- { nullptr, nullptr, OPTION_HEADER, "CORE SCREEN OPTIONS" },
- { OPTION_BRIGHTNESS "(0.1-2.0)", "1.0", OPTION_FLOAT, "default game screen brightness correction" },
- { OPTION_CONTRAST "(0.1-2.0)", "1.0", OPTION_FLOAT, "default game screen contrast correction" },
- { OPTION_GAMMA "(0.1-3.0)", "1.0", OPTION_FLOAT, "default game screen gamma correction" },
- { OPTION_PAUSE_BRIGHTNESS "(0.0-1.0)", "0.65", OPTION_FLOAT, "amount to scale the screen brightness when paused" },
- { OPTION_EFFECT, "none", OPTION_STRING, "name of a PNG file to use for visual effects, or 'none'" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE SCREEN OPTIONS" },
+ { OPTION_BRIGHTNESS "(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "default game screen brightness correction" },
+ { OPTION_CONTRAST "(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "default game screen contrast correction" },
+ { OPTION_GAMMA "(0.1-3.0)", "1.0", core_options::option_type::FLOAT, "default game screen gamma correction" },
+ { OPTION_PAUSE_BRIGHTNESS "(0.0-1.0)", "0.65", core_options::option_type::FLOAT, "amount to scale the screen brightness when paused" },
+ { OPTION_EFFECT, "none", core_options::option_type::STRING, "name of a PNG file to use for visual effects, or 'none'" },
// vector options
- { nullptr, nullptr, OPTION_HEADER, "CORE VECTOR OPTIONS" },
- { OPTION_BEAM_WIDTH_MIN, "1.0", OPTION_FLOAT, "set vector beam width minimum" },
- { OPTION_BEAM_WIDTH_MAX, "1.0", OPTION_FLOAT, "set vector beam width maximum" },
- { OPTION_BEAM_DOT_SIZE, "1.0", OPTION_FLOAT, "set vector beam size for dots" },
- { OPTION_BEAM_INTENSITY_WEIGHT, "0", OPTION_FLOAT, "set vector beam intensity weight " },
- { OPTION_FLICKER, "0", OPTION_FLOAT, "set vector flicker effect" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE VECTOR OPTIONS" },
+ { OPTION_BEAM_WIDTH_MIN, "1.0", core_options::option_type::FLOAT, "set vector beam width minimum" },
+ { OPTION_BEAM_WIDTH_MAX, "1.0", core_options::option_type::FLOAT, "set vector beam width maximum" },
+ { OPTION_BEAM_DOT_SIZE, "1.0", core_options::option_type::FLOAT, "set vector beam size for dots" },
+ { OPTION_BEAM_INTENSITY_WEIGHT, "0", core_options::option_type::FLOAT, "set vector beam intensity weight " },
+ { OPTION_FLICKER, "0", core_options::option_type::FLOAT, "set vector flicker effect" },
// sound options
- { nullptr, nullptr, OPTION_HEADER, "CORE SOUND OPTIONS" },
- { OPTION_SAMPLERATE ";sr(1000-1000000)", "48000", OPTION_INTEGER, "set sound output sample rate" },
- { OPTION_SAMPLES, "1", OPTION_BOOLEAN, "enable the use of external samples if available" },
- { OPTION_VOLUME ";vol", "0", OPTION_INTEGER, "sound volume in decibels (-32 min, 0 max)" },
- { OPTION_COMPRESSOR, "1", OPTION_BOOLEAN, "enable compressor for sound" },
- { OPTION_SPEAKER_REPORT "(0-4)", "0", OPTION_INTEGER, "print report of speaker ouput maxima (0=none, or 1-4 for more detail)" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE SOUND OPTIONS" },
+ { OPTION_SAMPLERATE ";sr(1000-1000000)", "48000", core_options::option_type::INTEGER, "set sound output sample rate" },
+ { OPTION_SAMPLES, "1", core_options::option_type::BOOLEAN, "enable the use of external samples if available" },
+ { OPTION_VOLUME ";vol", "0", core_options::option_type::INTEGER, "sound volume in decibels (-32 min, 0 max)" },
+ { OPTION_COMPRESSOR, "1", core_options::option_type::BOOLEAN, "enable compressor for sound" },
+ { OPTION_SPEAKER_REPORT "(0-4)", "0", core_options::option_type::INTEGER, "print report of speaker ouput maxima (0=none, or 1-4 for more detail)" },
// input options
- { nullptr, nullptr, OPTION_HEADER, "CORE INPUT OPTIONS" },
- { OPTION_COIN_LOCKOUT ";coinlock", "1", OPTION_BOOLEAN, "ignore coin inputs if coin lockout output is active" },
- { OPTION_CTRLR, nullptr, OPTION_STRING, "preconfigure for specified controller" },
- { OPTION_MOUSE, "0", OPTION_BOOLEAN, "enable mouse input" },
- { OPTION_JOYSTICK ";joy", "1", OPTION_BOOLEAN, "enable joystick input" },
- { OPTION_LIGHTGUN ";gun", "0", OPTION_BOOLEAN, "enable lightgun input" },
- { OPTION_MULTIKEYBOARD ";multikey", "0", OPTION_BOOLEAN, "enable separate input from each keyboard device (if present)" },
- { OPTION_MULTIMOUSE, "0", OPTION_BOOLEAN, "enable separate input from each mouse device (if present)" },
- { OPTION_STEADYKEY ";steady", "0", OPTION_BOOLEAN, "enable steadykey support" },
- { OPTION_UI_ACTIVE, "0", OPTION_BOOLEAN, "enable user interface on top of emulated keyboard (if present)" },
- { OPTION_OFFSCREEN_RELOAD ";reload", "0", OPTION_BOOLEAN, "convert lightgun button 2 into offscreen reload" },
- { OPTION_JOYSTICK_MAP ";joymap", "auto", OPTION_STRING, "explicit joystick map, or auto to auto-select" },
- { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz(0.00-1)", "0.3", OPTION_FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" },
- { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat(0.00-1)", "0.85", OPTION_FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" },
- { OPTION_NATURAL_KEYBOARD ";nat", "0", OPTION_BOOLEAN, "specifies whether to use a natural keyboard or not" },
- { OPTION_JOYSTICK_CONTRADICTORY ";joy_contradictory","0", OPTION_BOOLEAN, "enable contradictory direction digital joystick input at the same time" },
- { OPTION_COIN_IMPULSE, "0", OPTION_INTEGER, "set coin impulse time (n<0 disable impulse, n==0 obey driver, 0<n set time n)" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE INPUT OPTIONS" },
+ { OPTION_COIN_LOCKOUT ";coinlock", "1", core_options::option_type::BOOLEAN, "ignore coin inputs if coin lockout output is active" },
+ { OPTION_CTRLR, nullptr, core_options::option_type::STRING, "preconfigure for specified controller" },
+ { OPTION_MOUSE, "0", core_options::option_type::BOOLEAN, "enable mouse input" },
+ { OPTION_JOYSTICK ";joy", "1", core_options::option_type::BOOLEAN, "enable joystick input" },
+ { OPTION_LIGHTGUN ";gun", "0", core_options::option_type::BOOLEAN, "enable lightgun input" },
+ { OPTION_MULTIKEYBOARD ";multikey", "0", core_options::option_type::BOOLEAN, "enable separate input from each keyboard device (if present)" },
+ { OPTION_MULTIMOUSE, "0", core_options::option_type::BOOLEAN, "enable separate input from each mouse device (if present)" },
+ { OPTION_STEADYKEY ";steady", "0", core_options::option_type::BOOLEAN, "enable steadykey support" },
+ { OPTION_UI_ACTIVE, "0", core_options::option_type::BOOLEAN, "enable user interface on top of emulated keyboard (if present)" },
+ { OPTION_OFFSCREEN_RELOAD ";reload", "0", core_options::option_type::BOOLEAN, "convert lightgun button 2 into offscreen reload" },
+ { OPTION_JOYSTICK_MAP ";joymap", "auto", core_options::option_type::STRING, "explicit joystick map, or auto to auto-select" },
+ { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz(0.00-1)", "0.15", core_options::option_type::FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" },
+ { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat(0.00-1)", "0.85", core_options::option_type::FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" },
+ { OPTION_JOYSTICK_THRESHOLD ";joy_threshold;jthresh(0.00-1)", "0.3", core_options::option_type::FLOAT, "threshold for joystick to be considered active as a switch (0.0 center, 1.0 end)" },
+ { OPTION_NATURAL_KEYBOARD ";nat", "0", core_options::option_type::BOOLEAN, "specifies whether to use a natural keyboard or not" },
+ { OPTION_JOYSTICK_CONTRADICTORY ";joy_contradictory","0", core_options::option_type::BOOLEAN, "enable contradictory direction digital joystick input at the same time" },
+ { OPTION_COIN_IMPULSE, "0", core_options::option_type::INTEGER, "set coin impulse time (n<0 disable impulse, n==0 obey driver, 0<n set time n)" },
// input autoenable options
- { nullptr, nullptr, OPTION_HEADER, "CORE INPUT AUTOMATIC ENABLE OPTIONS" },
- { OPTION_PADDLE_DEVICE ";paddle", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a paddle control is present" },
- { OPTION_ADSTICK_DEVICE ";adstick", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if an analog joystick control is present" },
- { OPTION_PEDAL_DEVICE ";pedal", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a pedal control is present" },
- { OPTION_DIAL_DEVICE ";dial", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a dial control is present" },
- { OPTION_TRACKBALL_DEVICE ";trackball", "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a trackball control is present" },
- { OPTION_LIGHTGUN_DEVICE, "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a lightgun control is present" },
- { OPTION_POSITIONAL_DEVICE, "keyboard", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a positional control is present" },
- { OPTION_MOUSE_DEVICE, "mouse", OPTION_STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a mouse control is present" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE INPUT AUTOMATIC ENABLE OPTIONS" },
+ { OPTION_PADDLE_DEVICE ";paddle", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a paddle control is present" },
+ { OPTION_ADSTICK_DEVICE ";adstick", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if an analog joystick control is present" },
+ { OPTION_PEDAL_DEVICE ";pedal", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a pedal control is present" },
+ { OPTION_DIAL_DEVICE ";dial", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a dial control is present" },
+ { OPTION_TRACKBALL_DEVICE ";trackball", "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a trackball control is present" },
+ { OPTION_LIGHTGUN_DEVICE, "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a lightgun control is present" },
+ { OPTION_POSITIONAL_DEVICE, "keyboard", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a positional control is present" },
+ { OPTION_MOUSE_DEVICE, "mouse", core_options::option_type::STRING, "enable (none|keyboard|mouse|lightgun|joystick) if a mouse control is present" },
// debugging options
- { nullptr, nullptr, OPTION_HEADER, "CORE DEBUGGING OPTIONS" },
- { OPTION_VERBOSE ";v", "0", OPTION_BOOLEAN, "display additional diagnostic information" },
- { OPTION_LOG, "0", OPTION_BOOLEAN, "generate an error.log file" },
- { OPTION_OSLOG, "0", OPTION_BOOLEAN, "output error.log data to system diagnostic output (debugger or standard error)" },
- { OPTION_DEBUG ";d", "0", OPTION_BOOLEAN, "enable/disable debugger" },
- { OPTION_UPDATEINPAUSE, "0", OPTION_BOOLEAN, "keep calling video updates while in pause" },
- { OPTION_DEBUGSCRIPT, nullptr, OPTION_STRING, "script for debugger" },
- { OPTION_DEBUGLOG, "0", OPTION_BOOLEAN, "write debug console output to debug.log" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE DEBUGGING OPTIONS" },
+ { OPTION_VERBOSE ";v", "0", core_options::option_type::BOOLEAN, "display additional diagnostic information" },
+ { OPTION_LOG, "0", core_options::option_type::BOOLEAN, "generate an error.log file" },
+ { OPTION_OSLOG, "0", core_options::option_type::BOOLEAN, "output error.log data to system diagnostic output (debugger or standard error)" },
+ { OPTION_DEBUG ";d", "0", core_options::option_type::BOOLEAN, "enable/disable debugger" },
+ { OPTION_UPDATEINPAUSE, "0", core_options::option_type::BOOLEAN, "keep calling video updates while in pause" },
+ { OPTION_DEBUGSCRIPT, nullptr, core_options::option_type::PATH, "script for debugger" },
+ { OPTION_DEBUGLOG, "0", core_options::option_type::BOOLEAN, "write debug console output to debug.log" },
// comm options
- { nullptr, nullptr, OPTION_HEADER, "CORE COMM OPTIONS" },
- { OPTION_COMM_LOCAL_HOST, "0.0.0.0", OPTION_STRING, "local address to bind to" },
- { OPTION_COMM_LOCAL_PORT, "15112", OPTION_STRING, "local port to bind to" },
- { OPTION_COMM_REMOTE_HOST, "127.0.0.1", OPTION_STRING, "remote address to connect to" },
- { OPTION_COMM_REMOTE_PORT, "15112", OPTION_STRING, "remote port to connect to" },
- { OPTION_COMM_FRAME_SYNC, "0", OPTION_BOOLEAN, "sync frames" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE COMM OPTIONS" },
+ { OPTION_COMM_LOCAL_HOST, "0.0.0.0", core_options::option_type::STRING, "local address to bind to" },
+ { OPTION_COMM_LOCAL_PORT, "15112", core_options::option_type::STRING, "local port to bind to" },
+ { OPTION_COMM_REMOTE_HOST, "127.0.0.1", core_options::option_type::STRING, "remote address to connect to" },
+ { OPTION_COMM_REMOTE_PORT, "15112", core_options::option_type::STRING, "remote port to connect to" },
+ { OPTION_COMM_FRAME_SYNC, "0", core_options::option_type::BOOLEAN, "sync frames" },
// misc options
- { nullptr, nullptr, OPTION_HEADER, "CORE MISC OPTIONS" },
- { OPTION_DRC, "1", OPTION_BOOLEAN, "enable DRC CPU core if available" },
- { OPTION_DRC_USE_C, "0", OPTION_BOOLEAN, "force DRC to use C backend" },
- { OPTION_DRC_LOG_UML, "0", OPTION_BOOLEAN, "write DRC UML disassembly log" },
- { OPTION_DRC_LOG_NATIVE, "0", OPTION_BOOLEAN, "write DRC native disassembly log" },
- { OPTION_BIOS, nullptr, OPTION_STRING, "select the system BIOS to use" },
- { OPTION_CHEAT ";c", "0", OPTION_BOOLEAN, "enable cheat subsystem" },
- { OPTION_SKIP_GAMEINFO, "0", OPTION_BOOLEAN, "skip displaying the system information screen at startup" },
- { OPTION_UI_FONT, "default", OPTION_STRING, "specify a font to use" },
- { OPTION_UI, "cabinet", OPTION_STRING, "type of UI (simple|cabinet)" },
- { OPTION_RAMSIZE ";ram", nullptr, OPTION_STRING, "size of RAM (if supported by driver)" },
- { OPTION_CONFIRM_QUIT, "0", OPTION_BOOLEAN, "ask for confirmation before exiting" },
- { OPTION_UI_MOUSE, "1", OPTION_BOOLEAN, "display UI mouse cursor" },
- { OPTION_LANGUAGE ";lang", "", OPTION_STRING, "set UI display language" },
- { OPTION_NVRAM_SAVE ";nvwrite", "1", OPTION_BOOLEAN, "save NVRAM data on exit" },
-
- { nullptr, nullptr, OPTION_HEADER, "SCRIPTING OPTIONS" },
- { OPTION_AUTOBOOT_COMMAND ";ab", nullptr, OPTION_STRING, "command to execute after machine boot" },
- { OPTION_AUTOBOOT_DELAY, "0", OPTION_INTEGER, "delay before executing autoboot command (seconds)" },
- { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, OPTION_STRING, "Lua script to execute after machine boot" },
- { OPTION_CONSOLE, "0", OPTION_BOOLEAN, "enable emulator Lua console" },
- { OPTION_PLUGINS, "1", OPTION_BOOLEAN, "enable Lua plugin support" },
- { OPTION_PLUGIN, nullptr, OPTION_STRING, "list of plugins to enable" },
- { OPTION_NO_PLUGIN, nullptr, OPTION_STRING, "list of plugins to disable" },
-
- { nullptr, nullptr, OPTION_HEADER, "HTTP SERVER OPTIONS" },
- { OPTION_HTTP, "0", OPTION_BOOLEAN, "enable HTTP server" },
- { OPTION_HTTP_PORT, "8080", OPTION_INTEGER, "HTTP server port" },
- { OPTION_HTTP_ROOT, "web", OPTION_STRING, "HTTP server document root" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CORE MISC OPTIONS" },
+ { OPTION_DRC, "1", core_options::option_type::BOOLEAN, "enable DRC CPU core if available" },
+ { OPTION_DRC_USE_C, "0", core_options::option_type::BOOLEAN, "force DRC to use C backend" },
+ { OPTION_DRC_LOG_UML, "0", core_options::option_type::BOOLEAN, "write DRC UML disassembly log" },
+ { OPTION_DRC_LOG_NATIVE, "0", core_options::option_type::BOOLEAN, "write DRC native disassembly log" },
+ { OPTION_BIOS, nullptr, core_options::option_type::STRING, "select the system BIOS to use" },
+ { OPTION_CHEAT ";c", "0", core_options::option_type::BOOLEAN, "enable cheat subsystem" },
+ { OPTION_SKIP_GAMEINFO, "0", core_options::option_type::BOOLEAN, "skip displaying the system information screen at startup" },
+ { OPTION_UI_FONT, "default", core_options::option_type::STRING, "specify a font to use" },
+ { OPTION_UI, "cabinet", core_options::option_type::STRING, "type of UI (simple|cabinet)" },
+ { OPTION_RAMSIZE ";ram", nullptr, core_options::option_type::STRING, "size of RAM (if supported by driver)" },
+ { OPTION_CONFIRM_QUIT, "0", core_options::option_type::BOOLEAN, "ask for confirmation before exiting" },
+ { OPTION_UI_MOUSE, "1", core_options::option_type::BOOLEAN, "display UI mouse cursor" },
+ { OPTION_LANGUAGE ";lang", "", core_options::option_type::STRING, "set UI display language" },
+ { OPTION_NVRAM_SAVE ";nvwrite", "1", core_options::option_type::BOOLEAN, "save NVRAM data on exit" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "SCRIPTING OPTIONS" },
+ { OPTION_AUTOBOOT_COMMAND ";ab", nullptr, core_options::option_type::STRING, "command to execute after machine boot" },
+ { OPTION_AUTOBOOT_DELAY, "0", core_options::option_type::INTEGER, "delay before executing autoboot command (seconds)" },
+ { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, core_options::option_type::PATH, "Lua script to execute after machine boot" },
+ { OPTION_CONSOLE, "0", core_options::option_type::BOOLEAN, "enable emulator Lua console" },
+ { OPTION_PLUGINS, "1", core_options::option_type::BOOLEAN, "enable Lua plugin support" },
+ { OPTION_PLUGIN, nullptr, core_options::option_type::STRING, "list of plugins to enable" },
+ { OPTION_NO_PLUGIN, nullptr, core_options::option_type::STRING, "list of plugins to disable" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "HTTP SERVER OPTIONS" },
+ { OPTION_HTTP, "0", core_options::option_type::BOOLEAN, "enable HTTP server" },
+ { OPTION_HTTP_PORT, "8080", core_options::option_type::INTEGER, "HTTP server port" },
+ { OPTION_HTTP_ROOT, "web", core_options::option_type::PATH, "HTTP server document root" },
{ nullptr }
};
@@ -254,7 +259,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.set_system_name(std::move(newvalue));
}
@@ -274,7 +279,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.set_software(std::move(newvalue));
}
@@ -312,7 +317,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.specify(std::move(newvalue), false);
}
@@ -338,7 +343,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.specify(std::move(newvalue), false);
}
@@ -528,7 +533,7 @@ void emu_options::update_slot_and_image_options()
if (add_and_remove_slot_options())
changed = true;
- // second, we perform an analgous operation with m_image_options
+ // second, we perform an analogous operation with m_image_options
if (add_and_remove_image_options())
changed = true;
@@ -614,8 +619,8 @@ bool emu_options::add_and_remove_slot_options()
//-------------------------------------------------
-// add_and_remove_slot_options - add any missing
-// and/or purge extraneous slot options
+// add_and_remove_image_options - add any missing
+// and/or purge extraneous image options
//-------------------------------------------------
bool emu_options::add_and_remove_image_options()
@@ -718,7 +723,7 @@ bool emu_options::add_and_remove_image_options()
//-------------------------------------------------
// reevaluate_default_card_software - based on recent
-// changes in what images are mounted, give drivers
+// changes in what images are mounted, give devices
// a chance to specify new default slot options
//-------------------------------------------------
@@ -757,6 +762,16 @@ void emu_options::reevaluate_default_card_software()
std::string default_card_software = get_default_card_software(slot);
if (slot_opt.default_card_software() != default_card_software)
{
+ // HACK: prevent option values set from "XXX_default" in software list entries
+ // from getting cleared out, using crude heuristic to distinguish these from
+ // values representing cartridge types and such
+ if (default_card_software.empty())
+ {
+ auto *opt = slot.option(slot_opt.default_card_software().c_str());
+ if (opt && opt->selectable())
+ continue;
+ }
+
slot_opt.set_default_card_software(std::move(default_card_software));
// calling set_default_card_software() can cause a cascade of slot/image
@@ -845,7 +860,8 @@ void emu_options::set_software(std::string &&new_software)
}
// keep any deferred options for the next round
- softlist_opts = std::move(deferred_opts);
+ softlist_opts.slot = std::move(deferred_opts.slot);
+ softlist_opts.image = std::move(deferred_opts.image);
// do we have any pending options after failing to distribute any?
size_t after_size = softlist_opts.slot.size() + softlist_opts.image.size();
@@ -853,6 +869,14 @@ void emu_options::set_software(std::string &&new_software)
throw options_error_exception("Could not assign software option");
}
+ // distribute slot option defaults
+ for (auto &slot_opt : softlist_opts.slot_defaults)
+ {
+ auto iter = m_slot_options.find(slot_opt.first);
+ if (iter != m_slot_options.end())
+ iter->second.set_default_card_software(std::move(slot_opt.second));
+ }
+
// we've succeeded; update the set name
m_software_name = std::move(new_software);
}
@@ -922,9 +946,12 @@ emu_options::software_options emu_options::evaluate_initial_softlist_options(con
// we need to find a mountable image slot, but we need to ensure it is a slot
// for which we have not already distributed a part to
device_image_interface *image = software_list_device::find_mountable_image(
- config,
- swpart,
- [&results](const device_image_interface &candidate) { return results.image.count(candidate.instance_name()) == 0; });
+ config,
+ swpart,
+ [&results] (const device_image_interface &candidate)
+ {
+ return results.image.count(candidate.instance_name()) == 0;
+ });
// did we find a slot to put this part into?
if (image != nullptr)
@@ -957,7 +984,15 @@ emu_options::software_options emu_options::evaluate_initial_softlist_options(con
&& fi.name().compare(fi.name().size() - default_suffix.size(), default_suffix.size(), default_suffix) == 0)
{
std::string slot_name = fi.name().substr(0, fi.name().size() - default_suffix.size());
- results.slot[slot_name] = fi.value();
+
+ // only add defaults if they exist in this configuration
+ device_t *device = config.root_device().subdevice(slot_name.c_str());
+ if (device)
+ {
+ device_slot_interface *intf;
+ if (device->interface(intf) && intf->option(fi.value().c_str()))
+ results.slot_defaults[slot_name] = fi.value();
+ }
}
}
}
@@ -1050,8 +1085,9 @@ image_option &emu_options::image_option(const std::string &device_name)
void emu_options::command_argument_processed()
{
// some command line arguments require that the system name be set, so we can get slot options
- if (command_arguments().size() == 1 && !core_iswildstr(command_arguments()[0].c_str()) &&
- (command() == "listdevices" || (command() == "listslots") || (command() == "listmedia") || (command() == "listsoftware")))
+ // FIXME: having this here is a massively leaky abstraction
+ if (command_arguments().size() == 1 && !core_iswildstr(command_arguments()[0]) &&
+ (command() == "listdevices" || (command() == "listslots") || (command() == "listbios") || (command() == "listmedia") || (command() == "listsoftware")))
{
set_system_name(command_arguments()[0]);
}
@@ -1220,8 +1256,8 @@ void slot_option::set_bios(std::string &&text)
{
if (!m_specified)
{
- m_specified = true;
m_specified_value = value();
+ m_specified = true;
}
m_specified_bios = std::move(text);
}
diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h
index 296e2e46590..0a1b1dcf413 100644
--- a/src/emu/emuopts.h
+++ b/src/emu/emuopts.h
@@ -136,6 +136,7 @@
#define OPTION_JOYSTICK_MAP "joystick_map"
#define OPTION_JOYSTICK_DEADZONE "joystick_deadzone"
#define OPTION_JOYSTICK_SATURATION "joystick_saturation"
+#define OPTION_JOYSTICK_THRESHOLD "joystick_threshold"
#define OPTION_NATURAL_KEYBOARD "natural"
#define OPTION_JOYSTICK_CONTRADICTORY "joystick_contradictory"
#define OPTION_COIN_IMPULSE "coin_impulse"
@@ -426,6 +427,7 @@ public:
const char *joystick_map() const { return value(OPTION_JOYSTICK_MAP); }
float joystick_deadzone() const { return float_value(OPTION_JOYSTICK_DEADZONE); }
float joystick_saturation() const { return float_value(OPTION_JOYSTICK_SATURATION); }
+ float joystick_threshold() const { return float_value(OPTION_JOYSTICK_THRESHOLD); }
bool steadykey() const { return bool_value(OPTION_STEADYKEY); }
bool ui_active() const { return bool_value(OPTION_UI_ACTIVE); }
bool offscreen_reload() const { return bool_value(OPTION_OFFSCREEN_RELOAD); }
@@ -502,6 +504,7 @@ private:
struct software_options
{
std::unordered_map<std::string, std::string> slot;
+ std::unordered_map<std::string, std::string> slot_defaults;
std::unordered_map<std::string, std::string> image;
};
diff --git a/src/emu/emupal.h b/src/emu/emupal.h
index 73ee3809e90..cb4884a72fb 100644
--- a/src/emu/emupal.h
+++ b/src/emu/emupal.h
@@ -373,10 +373,10 @@ protected:
virtual void device_start() override;
// device_palette_interface overrides
- virtual u32 palette_entries() const override { return m_entries; }
- virtual u32 palette_indirect_entries() const override { return m_indirect_entries; }
- virtual bool palette_shadows_enabled() const override { return m_enable_shadows; }
- virtual bool palette_hilights_enabled() const override { return m_enable_hilights; }
+ virtual u32 palette_entries() const noexcept override { return m_entries; }
+ virtual u32 palette_indirect_entries() const noexcept override { return m_indirect_entries; }
+ virtual bool palette_shadows_enabled() const noexcept override { return m_enable_shadows; }
+ virtual bool palette_hilights_enabled() const noexcept override { return m_enable_hilights; }
// generic palette init routines
void palette_init_all_black(palette_device &palette);
diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp
index 6d5d6b8a806..c0341b93368 100644
--- a/src/emu/fileio.cpp
+++ b/src/emu/fileio.cpp
@@ -14,6 +14,8 @@
#include "util/path.h"
#include "util/unzip.h"
+#include <tuple>
+
//#define VERBOSE 1
#define LOG_OUTPUT_FUNC osd_printf_verbose
#include "logmacro.h"
@@ -107,7 +109,7 @@ path_iterator &path_iterator::operator=(path_iterator const &that)
// multipath sequence
//-------------------------------------------------
-bool path_iterator::next(std::string &buffer, const char *name)
+bool path_iterator::next(std::string &buffer)
{
// if none left, return false to indicate we are done
if (!m_is_first && (m_searchpath.cend() == m_current))
@@ -120,10 +122,6 @@ bool path_iterator::next(std::string &buffer, const char *name)
if (m_searchpath.cend() != m_current)
++m_current;
- // append the name if we have one
- if (name)
- util::path_append(buffer, name);
-
// bump the index and return true
m_is_first = false;
return true;
@@ -160,9 +158,13 @@ const osd::directory::entry *file_enumerator::next(const char *subdir)
while (!m_curdir)
{
// if we fail to get anything more, we're done
- if (!m_iterator.next(m_pathbuffer, subdir))
+ if (!m_iterator.next(m_pathbuffer))
return nullptr;
+ // append the subdir if we have one
+ if (subdir)
+ util::path_append(m_pathbuffer, subdir);
+
// open the path
m_curdir = osd::directory::open(m_pathbuffer);
}
@@ -259,7 +261,7 @@ util::hash_collection &emu_file::hashes(std::string_view types)
// determine which hashes we need
std::string needed;
for (char scan : types)
- if (already_have.find_first_of(scan) == -1)
+ if (already_have.find_first_of(scan) == std::string::npos)
needed.push_back(scan);
// if we need nothing, skip it
@@ -279,15 +281,14 @@ util::hash_collection &emu_file::hashes(std::string_view types)
return m_hashes;
}
- // read the data if we can
- const u8 *filedata = (const u8 *)m_file->buffer();
- if (filedata == nullptr)
+ std::uint64_t length;
+ if (m_file->length(length))
return m_hashes;
- // compute the hash
- std::uint64_t length;
- if (!m_file->length(length))
- m_hashes.compute(filedata, length, needed.c_str());
+ // hash the data
+ std::size_t actual;
+ (void)m_hashes.compute(*m_file, 0U, length, actual, needed.c_str()); // FIXME: need better interface to report errors
+
return m_hashes;
}
@@ -532,9 +533,10 @@ u32 emu_file::read(void *buffer, u32 length)
return 0;
// read the data if we can
+ std::error_condition err;
size_t actual = 0;
if (m_file)
- m_file->read(buffer, length, actual);
+ std::tie(err, actual) = util::read(*m_file, buffer, length);
return actual;
}
@@ -602,9 +604,10 @@ u32 emu_file::write(const void *buffer, u32 length)
{
// FIXME: need better interface to report errors
// write the data if we can
+ std::error_condition err;
size_t actual = 0;
if (m_file)
- m_file->write(buffer, length, actual);
+ std::tie(err, actual) = util::write(*m_file, buffer, length);
return actual;
}
@@ -628,7 +631,7 @@ int emu_file::puts(std::string_view s)
// vfprintf - vfprintf to a text file
//-------------------------------------------------
-int emu_file::vprintf(util::format_argument_pack<std::ostream> const &args)
+int emu_file::vprintf(util::format_argument_pack<char> const &args)
{
// write the data if we can
return m_file ? m_file->vprintf(args) : 0;
@@ -805,7 +808,7 @@ std::error_condition emu_file::load_zipped_file()
m_zipdata.resize(m_ziplength);
// read the data into our buffer and return
- auto const ziperr = m_zipfile->decompress(&m_zipdata[0], m_zipdata.size());
+ auto const ziperr = m_zipfile->decompress(m_zipdata.data(), m_zipdata.size());
if (ziperr)
{
m_zipdata.clear();
@@ -813,7 +816,7 @@ std::error_condition emu_file::load_zipped_file()
}
// convert to RAM file
- std::error_condition const filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file);
+ std::error_condition const filerr = util::core_file::open_ram(m_zipdata.data(), m_zipdata.size(), m_openflags, m_file);
if (filerr)
{
m_zipdata.clear();
diff --git a/src/emu/fileio.h b/src/emu/fileio.h
index 91aedad173e..225cebd0a81 100644
--- a/src/emu/fileio.h
+++ b/src/emu/fileio.h
@@ -61,7 +61,7 @@ public:
path_iterator &operator=(path_iterator const &that);
// main interface
- bool next(std::string &buffer, const char *name = nullptr);
+ bool next(std::string &buffer);
void reset();
private:
@@ -182,7 +182,7 @@ public:
// writing
u32 write(const void *buffer, u32 length);
int puts(std::string_view s);
- int vprintf(util::format_argument_pack<std::ostream> const &args);
+ int vprintf(util::format_argument_pack<char> const &args);
template <typename Format, typename... Params> int printf(Format &&fmt, Params &&...args)
{
return vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
diff --git a/src/emu/gamedrv.h b/src/emu/gamedrv.h
index a1cb8a40155..6ab934bc53f 100644
--- a/src/emu/gamedrv.h
+++ b/src/emu/gamedrv.h
@@ -30,44 +30,31 @@ struct machine_flags
{
enum type : u32
{
- MASK_ORIENTATION = 0x00000007,
- MASK_TYPE = 0x00000038,
+ MASK_ORIENTATION = 0x0000'0007,
- FLIP_X = 0x00000001,
- FLIP_Y = 0x00000002,
- SWAP_XY = 0x00000004,
- ROT0 = 0x00000000,
+ FLIP_X = 0x0000'0001,
+ FLIP_Y = 0x0000'0002,
+ SWAP_XY = 0x0000'0004,
+ ROT0 = 0x0000'0000,
ROT90 = FLIP_X | SWAP_XY,
ROT180 = FLIP_X | FLIP_Y,
ROT270 = FLIP_Y | SWAP_XY,
- TYPE_ARCADE = 0x00000008, // coin-operated machine for public use
- TYPE_CONSOLE = 0x00000010, // console system
- TYPE_COMPUTER = 0x00000018, // any kind of computer including home computers, minis, calculators, ...
- TYPE_OTHER = 0x00000038, // any other emulated system (e.g. clock, satellite receiver, ...)
-
- NOT_WORKING = 0x00000040,
- SUPPORTS_SAVE = 0x00000080, // system supports save states
- NO_COCKTAIL = 0x00000100, // screen flip support is missing
- IS_BIOS_ROOT = 0x00000200, // this driver entry is a BIOS root
- REQUIRES_ARTWORK = 0x00000400, // requires external artwork for key game elements
- CLICKABLE_ARTWORK = 0x00000800, // artwork is clickable and requires mouse cursor
- UNOFFICIAL = 0x00001000, // unofficial hardware modification
- NO_SOUND_HW = 0x00002000, // system has no sound output
- MECHANICAL = 0x00004000, // contains mechanical parts (pinball, redemption games, ...)
- IS_INCOMPLETE = 0x00008000 // official system with blatantly incomplete hardware/software
+ NOT_WORKING = 0x0000'0040,
+ SUPPORTS_SAVE = 0x0000'0080, // system supports save states
+ NO_COCKTAIL = 0x0000'0100, // screen flip support is missing
+ IS_BIOS_ROOT = 0x0000'0200, // this driver entry is a BIOS root
+ REQUIRES_ARTWORK = 0x0000'0400, // requires external artwork for key game elements
+ UNOFFICIAL = 0x0000'0800, // unofficial hardware modification
+ NO_SOUND_HW = 0x0000'1000, // system has no sound output
+ MECHANICAL = 0x0000'2000, // contains mechanical parts (pinball, redemption games, ...)
+ IS_INCOMPLETE = 0x0000'4000 // official system with blatantly incomplete hardware/software
};
};
DECLARE_ENUM_BITWISE_OPERATORS(machine_flags::type);
-constexpr u64 MACHINE_TYPE_ARCADE = machine_flags::TYPE_ARCADE;
-constexpr u64 MACHINE_TYPE_CONSOLE = machine_flags::TYPE_CONSOLE;
-constexpr u64 MACHINE_TYPE_COMPUTER = machine_flags::TYPE_COMPUTER;
-constexpr u64 MACHINE_TYPE_OTHER = machine_flags::TYPE_OTHER;
-
-
/// \addtogroup machinedef
/// \{
/// \name System emulation status constants
@@ -83,7 +70,6 @@ constexpr u64 MACHINE_SUPPORTS_SAVE = machine_flags::SUPPORTS_SAVE;
constexpr u64 MACHINE_NO_COCKTAIL = machine_flags::NO_COCKTAIL; ///< The system supports screen flipping for use in a cocktail cabinet, but this feature is not properly emulated
constexpr u64 MACHINE_IS_BIOS_ROOT = machine_flags::IS_BIOS_ROOT; ///< The system represents an empty system board of some kind - clones are treated as separate systems rather than variants
constexpr u64 MACHINE_REQUIRES_ARTWORK = machine_flags::REQUIRES_ARTWORK; ///< The system requires external artwork for key functionality
-constexpr u64 MACHINE_CLICKABLE_ARTWORK = machine_flags::CLICKABLE_ARTWORK; ///< Enables pointer display for the system to facilitate using clickable artwork
constexpr u64 MACHINE_UNOFFICIAL = machine_flags::UNOFFICIAL; ///< The system represents an after-market or end-user modification to a system
constexpr u64 MACHINE_NO_SOUND_HW = machine_flags::NO_SOUND_HW; ///< The system has no sound output capability
constexpr u64 MACHINE_MECHANICAL = machine_flags::MECHANICAL; ///< The system depends on mechanical features for key functionality
@@ -204,11 +190,9 @@ driver_device_creator< \
/// \addtogroup machinedef
/// \{
-/// \brief Define a "game" system
+/// \brief Define a system
///
-/// Use this macro to define most systems intended for public use,
-/// including arcade games, gambling machines, vending machines, and
-/// information kiosks. Muse be used in the global namespace.
+/// Must be used in the global namespace.
///
/// Creates an appropriately named and populated #game_driver structure
/// describing the system.
@@ -252,7 +236,7 @@ driver_device_creator< \
/// unemulated and imperfectly emulated feature flags that apply to
/// all systems implemented using the class in the class itself to
/// avoid repetition.
-/// \sa GAMEL CONS COMP SYST
+/// \sa GAMEL SYST
#define GAME(YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR, COMPANY, FULLNAME, FLAGS) \
GAME_DRIVER_TRAITS(NAME, FULLNAME) \
extern game_driver const GAME_NAME(NAME) \
@@ -267,18 +251,18 @@ extern game_driver const GAME_NAME(NAME) \
ROM_NAME(NAME), \
nullptr, \
nullptr, \
- machine_flags::type(u32((MONITOR) | (FLAGS) | MACHINE_TYPE_ARCADE)),\
+ machine_flags::type(u32((MONITOR) | (FLAGS))), \
#NAME \
};
-/// \brief Define a "game" system with an additional internal layout
+/// \brief Define a system with an additional internal layout
///
/// Equivalent to the #GAME macro, but with the additional ability to
-/// supply system-specific internal artwork layout data. Views from the
+/// supply a system-specific internal artwork layout. Views from the
/// system-specific layout are available in addition to any views from
-/// layout data specified in the machine configuration. Must be used in
-/// the global namespace.
+/// layouts specified in the machine configuration. Must be used in the
+/// global namespace.
///
/// Creates an appropriately named and populated #game_driver structure
/// describing the system.
@@ -324,7 +308,7 @@ extern game_driver const GAME_NAME(NAME) \
/// avoid repetition.
/// \param LAYOUT An #internal_layout structure providing additional
/// internal artwork for the system.
-/// \sa GAME CONS COMP SYST
+/// \sa GAME SYST
#define GAMEL(YEAR, NAME, PARENT, MACHINE, INPUT, CLASS, INIT, MONITOR, COMPANY, FULLNAME, FLAGS, LAYOUT) \
GAME_DRIVER_TRAITS(NAME, FULLNAME) \
extern game_driver const GAME_NAME(NAME) \
@@ -339,15 +323,15 @@ extern game_driver const GAME_NAME(NAME) \
ROM_NAME(NAME), \
nullptr, \
&LAYOUT, \
- machine_flags::type(u32((MONITOR) | (FLAGS) | MACHINE_TYPE_ARCADE)),\
+ machine_flags::type(u32((MONITOR) | (FLAGS))), \
#NAME \
};
-/// \brief Define a "console" system
+/// \brief Define a system with software compatibility grouping
///
-/// Use this macro to define appliance-like entertainment systems
-/// designed for domestic use. Must be used in the global namespace.
+/// Equivalent to the #GAME macro, but allows software-compatible
+/// systems to be grouped.
///
/// Creates an appropriately named and populated #game_driver structure
/// describing the system.
@@ -390,156 +374,31 @@ extern game_driver const GAME_NAME(NAME) \
/// unemulated and imperfectly emulated feature flags that apply to
/// all systems implemented using the class in the class itself to
/// avoid repetition. Screen orientation flags may be included here.
-/// \sa GAME GAMEL COMP SYST
-#define CONS(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
-GAME_DRIVER_TRAITS(NAME, FULLNAME) \
-extern game_driver const GAME_NAME(NAME) \
-{ \
- GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
- #PARENT, \
- #YEAR, \
- COMPANY, \
- [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \
- INPUT_PORTS_NAME(INPUT), \
- [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \
- ROM_NAME(NAME), \
- #COMPAT, \
- nullptr, \
- machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_CONSOLE)), \
- #NAME \
-};
+/// \sa GAME GAMEL
+#define SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
+ GAME_DRIVER_TRAITS(NAME, FULLNAME) \
+ extern game_driver const GAME_NAME(NAME) \
+ { \
+ GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
+ #PARENT, \
+ #YEAR, \
+ COMPANY, \
+ [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \
+ INPUT_PORTS_NAME(INPUT), \
+ [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \
+ ROM_NAME(NAME), \
+ #COMPAT, \
+ nullptr, \
+ machine_flags::type(u32(ROT0 | (FLAGS))), \
+ #NAME \
+ };
-/// \brief Define a "computer" system
-///
-/// Use this macro to define computer-like systems. Must be used in the
-/// global namespace.
-///
-/// Creates an appropriately named and populated #game_driver structure
-/// describing the system.
-/// \param YEAR The year that the system was first made available. Must
-/// be a token containing only the digits zero to nine, question mark
-/// and plus sign.
-/// \param NAME The short name of the system, used for identification,
-/// and in filesystem paths for assets and data. Must be a token no
-/// longer than sixteen characters, containing only ASCII lowercase
-/// letters, digits and underscores. Must be globally unique across
-/// systems and devices.
-/// \param PARENT Short name of the parent or BIOS system if applicable,
-/// or a single digit zero otherwise.
-/// \param COMPAT Short name of a system that this system is compatible
-/// with if applicable, or a single digit zero otherwise.
-/// \param MACHINE Function used to buid machine configuration for the
-/// system. Must be a public member function of the system device
-/// class (\p CLASS argument), returning void and taking a reference
-/// to a #machine_config object as a parameter.
-/// \param INPUT Input port definitions for the root device of the
-/// system, usually defined using #INPUT_PORTS_START and associated
-/// macros.
-/// \param CLASS Class to instantiate as the root device of the system.
-/// Must be an implementation of #driver_device.
-/// \param INIT Initialisation function called after all child devices
-/// have started, but before the driver start functions are called.
-/// Often used for tasks like decrypting ROMs. Must be a public
-/// member function of the system device class (\p CLASS argument),
-/// returning void and accepting no parameters. The function
-/// #driver_device::empty_init is supplied for systems that don't need
-/// to perform additional tasks.
-/// \param COMPANY Name of the developer or distributor of the system.
-/// Must be a string.
-/// \param FULLNAME Display name for the system. Must be a string, and
-/// must be globally unique across systems and devices.
-/// \param FLAGS Bitwise combination of emulation status flags for the
-/// system, in addition to flags supplied by the system device class
-/// (see #device_t::unemulated_features and
-/// #device_t::imperfect_features). It is advisable to supply
-/// unemulated and imperfectly emulated feature flags that apply to
-/// all systems implemented using the class in the class itself to
-/// avoid repetition. Screen orientation flags may be included here.
-/// \sa GAME GAMEL CONS SYST
-#define COMP(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
-GAME_DRIVER_TRAITS(NAME, FULLNAME) \
-extern game_driver const GAME_NAME(NAME) \
-{ \
- GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
- #PARENT, \
- #YEAR, \
- COMPANY, \
- [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \
- INPUT_PORTS_NAME(INPUT), \
- [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \
- ROM_NAME(NAME), \
- #COMPAT, \
- nullptr, \
- machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_COMPUTER)), \
- #NAME \
-};
-
+#define CONS(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
+ SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS)
-/// \brief Define a generic system
-///
-/// Use this macro to define miscellaneous systems that don't fall into
-/// one of the other categories. Must be used in the global namespace.
-///
-/// Creates an appropriately named and populated #game_driver structure
-/// describing the system.
-/// \param YEAR The year that the system was first made available. Must
-/// be a token containing only the digits zero to nine, question mark
-/// and plus sign.
-/// \param NAME The short name of the system, used for identification,
-/// and in filesystem paths for assets and data. Must be a token no
-/// longer than sixteen characters, containing only ASCII lowercase
-/// letters, digits and underscores. Must be globally unique across
-/// systems and devices.
-/// \param PARENT Short name of the parent or BIOS system if applicable,
-/// or a single digit zero otherwise.
-/// \param COMPAT Short name of a system that this system is compatible
-/// with if applicable, or a single digit zero otherwise.
-/// \param MACHINE Function used to buid machine configuration for the
-/// system. Must be a public member function of the system device
-/// class (\p CLASS argument), returning void and taking a reference
-/// to a #machine_config object as a parameter.
-/// \param INPUT Input port definitions for the root device of the
-/// system, usually defined using #INPUT_PORTS_START and associated
-/// macros.
-/// \param CLASS Class to instantiate as the root device of the system.
-/// Must be an implementation of #driver_device.
-/// \param INIT Initialisation function called after all child devices
-/// have started, but before the driver start functions are called.
-/// Often used for tasks like decrypting ROMs. Must be a public
-/// member function of the system device class (\p CLASS argument),
-/// returning void and accepting no parameters. The function
-/// #driver_device::empty_init is supplied for systems that don't need
-/// to perform additional tasks.
-/// \param COMPANY Name of the developer or distributor of the system.
-/// Must be a string.
-/// \param FULLNAME Display name for the system. Must be a string, and
-/// must be globally unique across systems and devices.
-/// \param FLAGS Bitwise combination of emulation status flags for the
-/// system, in addition to flags supplied by the system device class
-/// (see #device_t::unemulated_features and
-/// #device_t::imperfect_features). It is advisable to supply
-/// unemulated and imperfectly emulated feature flags that apply to
-/// all systems implemented using the class in the class itself to
-/// avoid repetition. Screen orientation flags may be included here.
-/// \sa GAME GAMEL CONS COMP
-#define SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
-GAME_DRIVER_TRAITS(NAME, FULLNAME) \
-extern game_driver const GAME_NAME(NAME) \
-{ \
- GAME_DRIVER_TYPE(NAME, CLASS, FLAGS), \
- #PARENT, \
- #YEAR, \
- COMPANY, \
- [] (machine_config &config, device_t &owner) { downcast<CLASS &>(owner).MACHINE(config); }, \
- INPUT_PORTS_NAME(INPUT), \
- [] (device_t &owner) { downcast<CLASS &>(owner).INIT(); }, \
- ROM_NAME(NAME), \
- #COMPAT, \
- nullptr, \
- machine_flags::type(u32(ROT0 | (FLAGS) | MACHINE_TYPE_OTHER)), \
- #NAME \
-};
+#define COMP(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS) \
+ SYST(YEAR, NAME, PARENT, COMPAT, MACHINE, INPUT, CLASS, INIT, COMPANY, FULLNAME, FLAGS)
/// \}
diff --git a/src/emu/hashfile.cpp b/src/emu/hashfile.cpp
index a6107e5e630..8436ad339fb 100644
--- a/src/emu/hashfile.cpp
+++ b/src/emu/hashfile.cpp
@@ -13,6 +13,7 @@
#include "drivenum.h"
#include "emuopts.h"
+#include "fileio.h"
#include "hash.h"
diff --git a/src/emu/http.cpp b/src/emu/http.cpp
index f36244e31ac..2a30a13dba3 100644
--- a/src/emu/http.cpp
+++ b/src/emu/http.cpp
@@ -9,6 +9,9 @@
***************************************************************************/
#include "emu.h"
+#include "http.h"
+#include "server_http.hpp"
+#include "server_ws.hpp"
#ifdef __sun
#define ASIO_DISABLE_DEV_POLL
@@ -141,28 +144,28 @@ public:
virtual ~http_request_impl() = default;
/** Retrieves the requested resource. */
- virtual const std::string get_resource() {
+ virtual const std::string get_resource() override {
// The entire resource: path, query and fragment.
return m_request->path;
}
/** Returns the path part of the requested resource. */
- virtual const std::string get_path() {
+ virtual const std::string get_path() override {
return m_request->path.substr(0, m_path_end);
}
/** Returns the query part of the requested resource. */
- virtual const std::string get_query() {
+ virtual const std::string get_query() override {
return m_query == std::string::npos ? "" : m_request->path.substr(m_query, m_query_end);
}
/** Returns the fragment part of the requested resource. */
- virtual const std::string get_fragment() {
+ virtual const std::string get_fragment() override {
return m_fragment == std::string::npos ? "" : m_request->path.substr(m_fragment);
}
/** Retrieves a header from the HTTP request. */
- virtual const std::string get_header(const std::string &header_name) {
+ virtual const std::string get_header(const std::string &header_name) override {
auto i = m_request->header.find(header_name);
if (i != m_request->header.end()) {
return (*i).second;
@@ -172,7 +175,7 @@ public:
}
/** Retrieves a header from the HTTP request. */
- virtual const std::list<std::string> get_headers(const std::string &header_name) {
+ virtual const std::list<std::string> get_headers(const std::string &header_name) override {
std::list<std::string> result;
auto range = m_request->header.equal_range(header_name);
for (auto i = range.first; i != range.second; i++) {
@@ -182,7 +185,7 @@ public:
}
/** Returns the body that was submitted with the HTTP request. */
- virtual const std::string get_body() {
+ virtual const std::string get_body() override {
// TODO(cbrunschen): What to return here - http_server::Request has a 'content' feld that is never filled in!
return "";
}
@@ -201,23 +204,23 @@ struct http_response_impl : public http_manager::http_response {
virtual ~http_response_impl() = default;
/** Sets the HTTP status to be returned to the client. */
- virtual void set_status(int status) {
+ virtual void set_status(int status) override {
m_status = status;
}
/** Sets the HTTP content type to be returned to the client. */
- virtual void set_content_type(const std::string &content_type) {
+ virtual void set_content_type(const std::string &content_type) override {
m_content_type = content_type;
}
/** Sets the body to be sent to the client. */
- virtual void set_body(const std::string &body) {
+ virtual void set_body(const std::string &body) override {
m_body.str("");
append_body(body);
}
/** Appends something to the body to be sent to the client. */
- virtual void append_body(const std::string &body) {
+ virtual void append_body(const std::string &body) override {
m_body << body;
}
@@ -255,7 +258,7 @@ struct websocket_connection_impl : public http_manager::websocket_connection {
: m_wsserver(server), m_connection(connection) { }
/** Sends a message to the client that is connected on the other end of this Websocket connection. */
- virtual void send_message(const std::string &payload, int opcode) {
+ virtual void send_message(const std::string &payload, int opcode) override {
if (auto connection = m_connection.lock()) {
std::shared_ptr<webpp::ws_server::SendStream> message_stream = std::make_shared<webpp::ws_server::SendStream>();
(*message_stream) << payload;
@@ -264,7 +267,7 @@ struct websocket_connection_impl : public http_manager::websocket_connection {
}
/** Closes this open Websocket connection. */
- virtual void close() {
+ virtual void close() override {
if (auto connection = m_connection.lock()) {
m_wsserver->send_close(connection, 1000 /* normal close */);
}
diff --git a/src/emu/http.h b/src/emu/http.h
index b0adf1e2b3d..e7c26d7980f 100644
--- a/src/emu/http.h
+++ b/src/emu/http.h
@@ -10,18 +10,12 @@
#pragma once
-#ifndef __EMU_H__
-#error Dont include this file directly; include emu.h instead.
-#endif
-
#ifndef MAME_EMU_HTTP_H
#define MAME_EMU_HTTP_H
#include <mutex>
#include <thread>
#include <ctime>
-#include "server_http.hpp"
-#include "server_ws.hpp"
//**************************************************************************
// TYPE DEFINITIONS
@@ -33,6 +27,13 @@ namespace asio
class io_context;
}
+namespace webpp
+{
+ class http_server;
+ class ws_server;
+ struct Connection;
+}
+
class http_manager
{
DISABLE_COPYING(http_manager);
diff --git a/src/emu/image.cpp b/src/emu/image.cpp
index 5e58758eb89..3839a57549b 100644
--- a/src/emu/image.cpp
+++ b/src/emu/image.cpp
@@ -14,8 +14,11 @@
#include "config.h"
#include "drivenum.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "softlist.h"
+// lib/util
#include "corestr.h"
#include "xmlfile.h"
#include "zippath.h"
@@ -37,6 +40,9 @@ image_manager::image_manager(running_machine &machine)
// make sure that any required devices have been allocated
for (device_image_interface &image : image_interface_enumerator(machine.root_device()))
{
+ // see if region-based chds are available
+ image.check_preset_images();
+
// ignore things not user loadable
if (!image.user_loadable())
continue;
@@ -48,27 +54,32 @@ image_manager::image_manager(running_machine &machine)
if (!startup_image.empty())
{
// we do have a startup image specified - load it
- image_init_result result = image_init_result::FAIL;
+ std::pair<std::error_condition, std::string> result(image_error::UNSPECIFIED, std::string());
// try as a softlist
if (software_name_parse(startup_image))
+ {
+ osd_printf_verbose("%s: attempting to load software item %s\n", image.device().tag(), startup_image);
result = image.load_software(startup_image);
+ }
// failing that, try as an image
- if (result != image_init_result::PASS)
+ if (result.first)
+ {
+ osd_printf_verbose("%s: attempting to load media image %s\n", image.device().tag(), startup_image);
result = image.load(startup_image);
+ }
// failing that, try creating it (if appropriate)
- if (result != image_init_result::PASS && image.support_command_line_image_creation())
+ if (result.first && image.support_command_line_image_creation())
+ {
+ osd_printf_verbose("%s: attempting to create media image %s\n", image.device().tag(), startup_image);
result = image.create(startup_image);
+ }
// did the image load fail?
- if (result != image_init_result::PASS)
+ if (result.first)
{
- // retrieve image error message
- std::string image_err = std::string(image.error());
- std::string startup_image_name = startup_image;
-
// unload the bad image
image.unload();
@@ -77,11 +88,18 @@ image_manager::image_manager(running_machine &machine)
if (machine.options().write_config())
write_config(machine.options(), nullptr, &machine.system());
- throw emu_fatalerror(EMU_ERR_DEVICE, "Device %s load (-%s %s) failed: %s",
+ // retrieve image error message
+ throw emu_fatalerror(EMU_ERR_DEVICE,
+ !result.second.empty()
+ ? "Device %1$s load (-%2$s %3$s) failed: %4$s (%5$s:%6$d %7$s)"
+ : "Device %1$s load (-%2$s %3$s) failed: %7$s (%5$s:%6$d)",
image.device().name(),
image.instance_name(),
- startup_image_name,
- image_err);
+ startup_image,
+ result.second,
+ result.first.category().name(),
+ result.first.value(),
+ result.first.message());
}
}
}
@@ -240,13 +258,14 @@ void image_manager::postdevice_init()
/* make sure that any required devices have been allocated */
for (device_image_interface &image : image_interface_enumerator(machine().root_device()))
{
- image_init_result result = image.finish_load();
+ auto [result, image_err] = image.finish_load();
/* did the image load fail? */
- if (result != image_init_result::PASS)
+ if (result)
{
/* retrieve image error message */
- std::string image_err = std::string(image.error());
+ if (image_err.empty())
+ image_err = result.message();
/* unload all images */
unload_all();
diff --git a/src/emu/image.h b/src/emu/image.h
index daf48b1f21d..95dca8a92b9 100644
--- a/src/emu/image.h
+++ b/src/emu/image.h
@@ -36,7 +36,7 @@ private:
void options_extract();
int write_config(emu_options &options, const char *filename, const game_driver *gamedrv);
- bool try_change_working_directory(std::string &working_directory, const std::string &subdir);;
+ bool try_change_working_directory(std::string &working_directory, const std::string &subdir);
// internal state
running_machine & m_machine; // reference to our machine
diff --git a/src/emu/inpttype.h b/src/emu/inpttype.h
new file mode 100644
index 00000000000..fa711b7eabd
--- /dev/null
+++ b/src/emu/inpttype.h
@@ -0,0 +1,353 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inpttype.ipp
+
+ Core-defined input types.
+
+***************************************************************************/
+#ifndef MAME_EMU_INPTTYPE_H
+#define MAME_EMU_INPTTYPE_H
+
+#pragma once
+
+#include "interface/inputfwd.h"
+#include "osdcomm.h"
+
+
+enum ioport_type : osd::u32
+{
+ // pseudo-port types
+ IPT_INVALID = 0,
+ IPT_UNUSED,
+ IPT_END,
+ IPT_UNKNOWN,
+ IPT_PORT,
+ IPT_DIPSWITCH,
+ IPT_CONFIG,
+
+ // start buttons
+ IPT_START1,
+ IPT_START2,
+ IPT_START3,
+ IPT_START4,
+ IPT_START5,
+ IPT_START6,
+ IPT_START7,
+ IPT_START8,
+ IPT_START9,
+ IPT_START10,
+
+ // coin slots
+ IPT_COIN1,
+ IPT_COIN2,
+ IPT_COIN3,
+ IPT_COIN4,
+ IPT_COIN5,
+ IPT_COIN6,
+ IPT_COIN7,
+ IPT_COIN8,
+ IPT_COIN9,
+ IPT_COIN10,
+ IPT_COIN11,
+ IPT_COIN12,
+ IPT_BILL1,
+
+ // service coin
+ IPT_SERVICE1,
+ IPT_SERVICE2,
+ IPT_SERVICE3,
+ IPT_SERVICE4,
+
+ // tilt inputs
+ IPT_TILT1,
+ IPT_TILT2,
+ IPT_TILT3,
+ IPT_TILT4,
+
+ // misc other digital inputs
+ IPT_POWER_ON,
+ IPT_POWER_OFF,
+ IPT_SERVICE,
+ IPT_TILT,
+ IPT_INTERLOCK,
+ IPT_MEMORY_RESET,
+ IPT_VOLUME_UP,
+ IPT_VOLUME_DOWN,
+ IPT_START, // use the numbered start button(s) for coin-ops
+ IPT_SELECT,
+ IPT_KEYPAD,
+ IPT_KEYBOARD,
+
+ // digital joystick inputs
+ IPT_DIGITAL_JOYSTICK_FIRST,
+
+ // use IPT_JOYSTICK for panels where the player has one single joystick
+ IPT_JOYSTICK_UP,
+ IPT_JOYSTICK_DOWN,
+ IPT_JOYSTICK_LEFT,
+ IPT_JOYSTICK_RIGHT,
+
+ // use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels
+ IPT_JOYSTICKRIGHT_UP,
+ IPT_JOYSTICKRIGHT_DOWN,
+ IPT_JOYSTICKRIGHT_LEFT,
+ IPT_JOYSTICKRIGHT_RIGHT,
+ IPT_JOYSTICKLEFT_UP,
+ IPT_JOYSTICKLEFT_DOWN,
+ IPT_JOYSTICKLEFT_LEFT,
+ IPT_JOYSTICKLEFT_RIGHT,
+
+ IPT_DIGITAL_JOYSTICK_LAST,
+
+ // action buttons
+ IPT_BUTTON1,
+ IPT_BUTTON2,
+ IPT_BUTTON3,
+ IPT_BUTTON4,
+ IPT_BUTTON5,
+ IPT_BUTTON6,
+ IPT_BUTTON7,
+ IPT_BUTTON8,
+ IPT_BUTTON9,
+ IPT_BUTTON10,
+ IPT_BUTTON11,
+ IPT_BUTTON12,
+ IPT_BUTTON13,
+ IPT_BUTTON14,
+ IPT_BUTTON15,
+ IPT_BUTTON16,
+
+ // mahjong inputs
+ IPT_MAHJONG_FIRST,
+
+ IPT_MAHJONG_A,
+ IPT_MAHJONG_B,
+ IPT_MAHJONG_C,
+ IPT_MAHJONG_D,
+ IPT_MAHJONG_E,
+ IPT_MAHJONG_F,
+ IPT_MAHJONG_G,
+ IPT_MAHJONG_H,
+ IPT_MAHJONG_I,
+ IPT_MAHJONG_J,
+ IPT_MAHJONG_K,
+ IPT_MAHJONG_L,
+ IPT_MAHJONG_M,
+ IPT_MAHJONG_N,
+ IPT_MAHJONG_O,
+ IPT_MAHJONG_P,
+ IPT_MAHJONG_Q,
+ IPT_MAHJONG_KAN,
+ IPT_MAHJONG_PON,
+ IPT_MAHJONG_CHI,
+ IPT_MAHJONG_REACH,
+ IPT_MAHJONG_RON,
+ IPT_MAHJONG_FLIP_FLOP,
+ IPT_MAHJONG_BET,
+ IPT_MAHJONG_SCORE,
+ IPT_MAHJONG_DOUBLE_UP,
+ IPT_MAHJONG_BIG,
+ IPT_MAHJONG_SMALL,
+ IPT_MAHJONG_LAST_CHANCE,
+
+ IPT_MAHJONG_LAST,
+
+ // hanafuda inputs
+ IPT_HANAFUDA_FIRST,
+
+ IPT_HANAFUDA_A,
+ IPT_HANAFUDA_B,
+ IPT_HANAFUDA_C,
+ IPT_HANAFUDA_D,
+ IPT_HANAFUDA_E,
+ IPT_HANAFUDA_F,
+ IPT_HANAFUDA_G,
+ IPT_HANAFUDA_H,
+ IPT_HANAFUDA_YES,
+ IPT_HANAFUDA_NO,
+
+ IPT_HANAFUDA_LAST,
+
+ // gambling inputs
+ IPT_GAMBLING_FIRST,
+
+ IPT_GAMBLE_KEYIN, // attendant
+ IPT_GAMBLE_KEYOUT, // attendant
+ IPT_GAMBLE_SERVICE, // attendant
+ IPT_GAMBLE_BOOK, // attendant
+ IPT_GAMBLE_DOOR, // attendant
+ // IPT_GAMBLE_DOOR2, // many gambling games have several doors.
+ // IPT_GAMBLE_DOOR3,
+ // IPT_GAMBLE_DOOR4,
+ // IPT_GAMBLE_DOOR5,
+
+ IPT_GAMBLE_PAYOUT, // player
+ IPT_GAMBLE_BET, // player
+ IPT_GAMBLE_DEAL, // player
+ IPT_GAMBLE_STAND, // player
+ IPT_GAMBLE_TAKE, // player
+ IPT_GAMBLE_D_UP, // player
+ IPT_GAMBLE_HALF, // player
+ IPT_GAMBLE_HIGH, // player
+ IPT_GAMBLE_LOW, // player
+
+ // poker-specific inputs
+ IPT_POKER_HOLD1,
+ IPT_POKER_HOLD2,
+ IPT_POKER_HOLD3,
+ IPT_POKER_HOLD4,
+ IPT_POKER_HOLD5,
+ IPT_POKER_CANCEL,
+
+ // slot-specific inputs
+ IPT_SLOT_STOP1,
+ IPT_SLOT_STOP2,
+ IPT_SLOT_STOP3,
+ IPT_SLOT_STOP4,
+ IPT_SLOT_STOP_ALL,
+
+ IPT_GAMBLING_LAST,
+
+ // analog inputs
+ IPT_ANALOG_FIRST,
+
+ IPT_ANALOG_ABSOLUTE_FIRST,
+
+ IPT_AD_STICK_X, // absolute // autocenter
+ IPT_AD_STICK_Y, // absolute // autocenter
+ IPT_AD_STICK_Z, // absolute // autocenter
+ IPT_PADDLE, // absolute // autocenter
+ IPT_PADDLE_V, // absolute // autocenter
+ IPT_PEDAL, // absolute // autocenter
+ IPT_PEDAL2, // absolute // autocenter
+ IPT_PEDAL3, // absolute // autocenter
+ IPT_LIGHTGUN_X, // absolute
+ IPT_LIGHTGUN_Y, // absolute
+ IPT_POSITIONAL, // absolute // autocenter if not wraps
+ IPT_POSITIONAL_V, // absolute // autocenter if not wraps
+
+ IPT_ANALOG_ABSOLUTE_LAST,
+
+ IPT_DIAL, // relative
+ IPT_DIAL_V, // relative
+ IPT_TRACKBALL_X, // relative
+ IPT_TRACKBALL_Y, // relative
+ IPT_MOUSE_X, // relative
+ IPT_MOUSE_Y, // relative
+
+ IPT_ANALOG_LAST,
+
+ // analog adjuster support
+ IPT_ADJUSTER,
+
+ // the following are special codes for user interface handling - not to be used by drivers!
+ IPT_UI_FIRST,
+
+ IPT_UI_MENU,
+ IPT_UI_SELECT,
+ IPT_UI_BACK,
+ IPT_UI_CANCEL,
+ IPT_UI_CLEAR,
+ IPT_UI_HELP,
+ IPT_UI_UP,
+ IPT_UI_DOWN,
+ IPT_UI_LEFT,
+ IPT_UI_RIGHT,
+ IPT_UI_HOME,
+ IPT_UI_END,
+ IPT_UI_PAGE_UP,
+ IPT_UI_PAGE_DOWN,
+ IPT_UI_PREV_GROUP,
+ IPT_UI_NEXT_GROUP,
+ IPT_UI_ON_SCREEN_DISPLAY,
+ IPT_UI_TOGGLE_UI,
+ IPT_UI_DEBUG_BREAK,
+ IPT_UI_PAUSE,
+ IPT_UI_PAUSE_SINGLE,
+ IPT_UI_REWIND_SINGLE,
+ IPT_UI_SAVE_STATE,
+ IPT_UI_SAVE_STATE_QUICK,
+ IPT_UI_LOAD_STATE,
+ IPT_UI_LOAD_STATE_QUICK,
+ IPT_UI_RESET_MACHINE,
+ IPT_UI_SOFT_RESET,
+ IPT_UI_SHOW_GFX,
+ IPT_UI_FRAMESKIP_DEC,
+ IPT_UI_FRAMESKIP_INC,
+ IPT_UI_THROTTLE,
+ IPT_UI_FAST_FORWARD,
+ IPT_UI_SHOW_FPS,
+ IPT_UI_SNAPSHOT,
+ IPT_UI_RECORD_MNG,
+ IPT_UI_RECORD_AVI,
+ IPT_UI_TOGGLE_CHEAT,
+ IPT_UI_DISPLAY_COMMENT,
+ IPT_UI_ZOOM_IN,
+ IPT_UI_ZOOM_OUT,
+ IPT_UI_ZOOM_DEFAULT,
+ IPT_UI_ROTATE,
+ IPT_UI_SHOW_PROFILER,
+ IPT_UI_RELEASE_POINTER,
+ IPT_UI_PASTE,
+ IPT_UI_TAPE_START,
+ IPT_UI_TAPE_STOP,
+ IPT_UI_FOCUS_NEXT,
+ IPT_UI_FOCUS_PREV,
+ IPT_UI_DATS,
+ IPT_UI_FAVORITES,
+ IPT_UI_EXPORT,
+ IPT_UI_AUDIT,
+
+ // additional OSD-specified UI port types (up to 16)
+ IPT_OSD_1,
+ IPT_OSD_2,
+ IPT_OSD_3,
+ IPT_OSD_4,
+ IPT_OSD_5,
+ IPT_OSD_6,
+ IPT_OSD_7,
+ IPT_OSD_8,
+ IPT_OSD_9,
+ IPT_OSD_10,
+ IPT_OSD_11,
+ IPT_OSD_12,
+ IPT_OSD_13,
+ IPT_OSD_14,
+ IPT_OSD_15,
+ IPT_OSD_16,
+
+ IPT_UI_LAST,
+
+ IPT_OTHER, // not mapped to standard defaults
+
+ IPT_SPECIAL, // uninterpreted characters
+ IPT_CUSTOM, // handled by custom code
+ IPT_OUTPUT,
+
+ IPT_COUNT,
+
+ // aliases for some types
+ IPT_PADDLE_H = IPT_PADDLE,
+ IPT_PEDAL1 = IPT_PEDAL,
+ IPT_POSITIONAL_H = IPT_POSITIONAL,
+ IPT_DIAL_H = IPT_DIAL
+};
+
+DECLARE_ENUM_INCDEC_OPERATORS(ioport_type)
+
+
+// sequence types for input_port_seq() call
+enum input_seq_type : int
+{
+ SEQ_TYPE_INVALID = -1,
+ SEQ_TYPE_STANDARD = 0,
+ SEQ_TYPE_INCREMENT,
+ SEQ_TYPE_DECREMENT,
+ SEQ_TYPE_TOTAL
+};
+
+DECLARE_ENUM_INCDEC_OPERATORS(input_seq_type)
+
+#endif // MAME_EMU_INPTTYPE_H
diff --git a/src/emu/inpttype.ipp b/src/emu/inpttype.ipp
index aca3973673a..8c217a1d39c 100644
--- a/src/emu/inpttype.ipp
+++ b/src/emu/inpttype.ipp
@@ -19,83 +19,83 @@ namespace {
#define CORE_INPUT_TYPES_P1 \
CORE_INPUT_TYPES_BEGIN(p1) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_UP, N_p("input-name", "P1 Up"), input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_DOWN, N_p("input-name", "P1 Down"), input_seq(KEYCODE_DOWN, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_LEFT, N_p("input-name", "P1 Left"), input_seq(KEYCODE_LEFT, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_RIGHT, N_p("input-name", "P1 Right"), input_seq(KEYCODE_RIGHT, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_UP, N_p("input-name", "P1 Right Stick/Up"), input_seq(KEYCODE_I, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_DOWN, N_p("input-name", "P1 Right Stick/Down"), input_seq(KEYCODE_K, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_LEFT, N_p("input-name", "P1 Right Stick/Left"), input_seq(KEYCODE_J, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P1 Right Stick/Right"), input_seq(KEYCODE_L, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_UP, N_p("input-name", "P1 Left Stick/Up"), input_seq(KEYCODE_E, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_DOWN, N_p("input-name", "P1 Left Stick/Down"), input_seq(KEYCODE_D, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_LEFT, N_p("input-name", "P1 Left Stick/Left"), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_RIGHT, N_p("input-name", "P1 Left Stick/Right"), input_seq(KEYCODE_F, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON1, N_p("input-name", "P1 Button 1"), input_seq(KEYCODE_LCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON2, N_p("input-name", "P1 Button 2"), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON3, N_p("input-name", "P1 Button 3"), input_seq(KEYCODE_SPACE, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0), input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON4, N_p("input-name", "P1 Button 4"), input_seq(KEYCODE_LSHIFT, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON5, N_p("input-name", "P1 Button 5"), input_seq(KEYCODE_Z, input_seq::or_code, JOYCODE_BUTTON5_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON6, N_p("input-name", "P1 Button 6"), input_seq(KEYCODE_X, input_seq::or_code, JOYCODE_BUTTON6_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON7, N_p("input-name", "P1 Button 7"), input_seq(KEYCODE_C, input_seq::or_code, JOYCODE_BUTTON7_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON8, N_p("input-name", "P1 Button 8"), input_seq(KEYCODE_V, input_seq::or_code, JOYCODE_BUTTON8_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON9, N_p("input-name", "P1 Button 9"), input_seq(KEYCODE_B, input_seq::or_code, JOYCODE_BUTTON9_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON10, N_p("input-name", "P1 Button 10"), input_seq(KEYCODE_N, input_seq::or_code, JOYCODE_BUTTON10_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON11, N_p("input-name", "P1 Button 11"), input_seq(KEYCODE_M, input_seq::or_code, JOYCODE_BUTTON11_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON12, N_p("input-name", "P1 Button 12"), input_seq(KEYCODE_COMMA, input_seq::or_code, JOYCODE_BUTTON12_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON13, N_p("input-name", "P1 Button 13"), input_seq(KEYCODE_STOP, input_seq::or_code, JOYCODE_BUTTON13_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON14, N_p("input-name", "P1 Button 14"), input_seq(KEYCODE_SLASH, input_seq::or_code, JOYCODE_BUTTON14_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON15, N_p("input-name", "P1 Button 15"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON15_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON16, N_p("input-name", "P1 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, START, N_p("input-name", "P1 Start"), input_seq(KEYCODE_1, input_seq::or_code, JOYCODE_START_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, SELECT, N_p("input-name", "P1 Select"), input_seq(KEYCODE_5, input_seq::or_code, JOYCODE_SELECT_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_UP) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_LEFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq(KEYCODE_I) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq(KEYCODE_J) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq(KEYCODE_E) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq(KEYCODE_D) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq(KEYCODE_S) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_LCONTROL, input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_LALT, input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(0), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_SPACE, input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON4, N_p("input-name", "%p Button 4"), input_seq(KEYCODE_LSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON5, N_p("input-name", "%p Button 5"), input_seq(KEYCODE_Z) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON6, N_p("input-name", "%p Button 6"), input_seq(KEYCODE_X) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON7, N_p("input-name", "%p Button 7"), input_seq(KEYCODE_C) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON8, N_p("input-name", "%p Button 8"), input_seq(KEYCODE_V) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON9, N_p("input-name", "%p Button 9"), input_seq(KEYCODE_B) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON10, N_p("input-name", "%p Button 10"), input_seq(KEYCODE_N) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON11, N_p("input-name", "%p Button 11"), input_seq(KEYCODE_M) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON12, N_p("input-name", "%p Button 12"), input_seq(KEYCODE_COMMA) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON13, N_p("input-name", "%p Button 13"), input_seq(KEYCODE_STOP) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON14, N_p("input-name", "%p Button 14"), input_seq(KEYCODE_SLASH) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON15, N_p("input-name", "%p Button 15"), input_seq(KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_1) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_5) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P1_MAHJONG \
CORE_INPUT_TYPES_BEGIN(p1_mahjong) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_A, N_p("input-name", "P1 Mahjong A"), input_seq(KEYCODE_A) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_B, N_p("input-name", "P1 Mahjong B"), input_seq(KEYCODE_B) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_C, N_p("input-name", "P1 Mahjong C"), input_seq(KEYCODE_C) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_D, N_p("input-name", "P1 Mahjong D"), input_seq(KEYCODE_D) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_E, N_p("input-name", "P1 Mahjong E"), input_seq(KEYCODE_E) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_F, N_p("input-name", "P1 Mahjong F"), input_seq(KEYCODE_F) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_G, N_p("input-name", "P1 Mahjong G"), input_seq(KEYCODE_G) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_H, N_p("input-name", "P1 Mahjong H"), input_seq(KEYCODE_H) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_I, N_p("input-name", "P1 Mahjong I"), input_seq(KEYCODE_I) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_J, N_p("input-name", "P1 Mahjong J"), input_seq(KEYCODE_J) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_K, N_p("input-name", "P1 Mahjong K"), input_seq(KEYCODE_K) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_L, N_p("input-name", "P1 Mahjong L"), input_seq(KEYCODE_L) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_M, N_p("input-name", "P1 Mahjong M"), input_seq(KEYCODE_M) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_N, N_p("input-name", "P1 Mahjong N"), input_seq(KEYCODE_N) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_O, N_p("input-name", "P1 Mahjong O"), input_seq(KEYCODE_O) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_P, N_p("input-name", "P1 Mahjong P"), input_seq(KEYCODE_COLON) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_Q, N_p("input-name", "P1 Mahjong Q"), input_seq(KEYCODE_Q) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_KAN, N_p("input-name", "P1 Mahjong Kan"), input_seq(KEYCODE_LCONTROL) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_PON, N_p("input-name", "P1 Mahjong Pon"), input_seq(KEYCODE_LALT) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_CHI, N_p("input-name", "P1 Mahjong Chi"), input_seq(KEYCODE_SPACE) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_REACH, N_p("input-name", "P1 Mahjong Reach"), input_seq(KEYCODE_LSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_RON, N_p("input-name", "P1 Mahjong Ron"), input_seq(KEYCODE_Z) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_FLIP_FLOP, N_p("input-name", "P1 Mahjong Flip Flop"), input_seq(KEYCODE_Y) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BET, N_p("input-name", "P1 Mahjong Bet"), input_seq(KEYCODE_3) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SCORE, N_p("input-name", "P1 Mahjong Take Score"), input_seq(KEYCODE_RCONTROL) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_DOUBLE_UP, N_p("input-name", "P1 Mahjong Double Up"), input_seq(KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BIG, N_p("input-name", "P1 Mahjong Big"), input_seq(KEYCODE_ENTER) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SMALL, N_p("input-name", "P1 Mahjong Small"), input_seq(KEYCODE_BACKSPACE) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_LAST_CHANCE, N_p("input-name", "P1 Mahjong Last Chance"), input_seq(KEYCODE_RALT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(0)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P1_HANAFUDA \
CORE_INPUT_TYPES_BEGIN(p1_hanafuda) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_A, N_p("input-name", "P1 Hanafuda A/1"), input_seq(KEYCODE_A) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_B, N_p("input-name", "P1 Hanafuda B/2"), input_seq(KEYCODE_B) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_C, N_p("input-name", "P1 Hanafuda C/3"), input_seq(KEYCODE_C) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_D, N_p("input-name", "P1 Hanafuda D/4"), input_seq(KEYCODE_D) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_E, N_p("input-name", "P1 Hanafuda E/5"), input_seq(KEYCODE_E) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_F, N_p("input-name", "P1 Hanafuda F/6"), input_seq(KEYCODE_F) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_G, N_p("input-name", "P1 Hanafuda G/7"), input_seq(KEYCODE_G) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_H, N_p("input-name", "P1 Hanafuda H/8"), input_seq(KEYCODE_H) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_YES, N_p("input-name", "P1 Hanafuda Yes"), input_seq(KEYCODE_M) ) \
- INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_NO, N_p("input-name", "P1 Hanafuda No"), input_seq(KEYCODE_N) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_A, N_p("input-name", "%p Hanafuda A/1"), input_seq(KEYCODE_A_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_B, N_p("input-name", "%p Hanafuda B/2"), input_seq(KEYCODE_B_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_C, N_p("input-name", "%p Hanafuda C/3"), input_seq(KEYCODE_C_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_D, N_p("input-name", "%p Hanafuda D/4"), input_seq(KEYCODE_D_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_E, N_p("input-name", "%p Hanafuda E/5"), input_seq(KEYCODE_E_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_F, N_p("input-name", "%p Hanafuda F/6"), input_seq(KEYCODE_F_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_G, N_p("input-name", "%p Hanafuda G/7"), input_seq(KEYCODE_G_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_H, N_p("input-name", "%p Hanafuda H/8"), input_seq(KEYCODE_H_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_YES, N_p("input-name", "%p Hanafuda Yes"), input_seq(KEYCODE_M_INDEXED(0)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, HANAFUDA_NO, N_p("input-name", "%p Hanafuda No"), input_seq(KEYCODE_N_INDEXED(0)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_GAMBLE \
@@ -137,355 +137,421 @@ namespace {
#define CORE_INPUT_TYPES_P2 \
CORE_INPUT_TYPES_BEGIN(p2) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_UP, N_p("input-name", "P2 Up"), input_seq(KEYCODE_R, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_DOWN, N_p("input-name", "P2 Down"), input_seq(KEYCODE_F, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_LEFT, N_p("input-name", "P2 Left"), input_seq(KEYCODE_D, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_RIGHT, N_p("input-name", "P2 Right"), input_seq(KEYCODE_G, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_UP, N_p("input-name", "P2 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_DOWN, N_p("input-name", "P2 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_LEFT, N_p("input-name", "P2 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P2 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_UP, N_p("input-name", "P2 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_DOWN, N_p("input-name", "P2 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_LEFT, N_p("input-name", "P2 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_RIGHT, N_p("input-name", "P2 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON1, N_p("input-name", "P2 Button 1"), input_seq(KEYCODE_A, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON2, N_p("input-name", "P2 Button 2"), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON3, N_p("input-name", "P2 Button 3"), input_seq(KEYCODE_Q, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(1), input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON4, N_p("input-name", "P2 Button 4"), input_seq(KEYCODE_W, input_seq::or_code, JOYCODE_BUTTON4_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON5, N_p("input-name", "P2 Button 5"), input_seq(KEYCODE_E, input_seq::or_code, JOYCODE_BUTTON5_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON6, N_p("input-name", "P2 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON7, N_p("input-name", "P2 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON8, N_p("input-name", "P2 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON9, N_p("input-name", "P2 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON10, N_p("input-name", "P2 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON11, N_p("input-name", "P2 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON12, N_p("input-name", "P2 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON13, N_p("input-name", "P2 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON14, N_p("input-name", "P2 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON15, N_p("input-name", "P2 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON16, N_p("input-name", "P2 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, START, N_p("input-name", "P2 Start"), input_seq(KEYCODE_2, input_seq::or_code, JOYCODE_START_INDEXED(1)) ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, SELECT, N_p("input-name", "P2 Select"), input_seq(KEYCODE_6, input_seq::or_code, JOYCODE_SELECT_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_R) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_D) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_A, input_seq::or_code, MOUSECODE_BUTTON1_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_S, input_seq::or_code, MOUSECODE_BUTTON3_INDEXED(1), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_Q, input_seq::or_code, MOUSECODE_BUTTON2_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON4, N_p("input-name", "%p Button 4"), input_seq(KEYCODE_W) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON5, N_p("input-name", "%p Button 5"), input_seq(KEYCODE_E) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_2) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_6) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P2_MAHJONG \
CORE_INPUT_TYPES_BEGIN(p2_mahjong) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_A, N_p("input-name", "P2 Mahjong A"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_B, N_p("input-name", "P2 Mahjong B"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_C, N_p("input-name", "P2 Mahjong C"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_D, N_p("input-name", "P2 Mahjong D"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_E, N_p("input-name", "P2 Mahjong E"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_F, N_p("input-name", "P2 Mahjong F"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_G, N_p("input-name", "P2 Mahjong G"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_H, N_p("input-name", "P2 Mahjong H"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_I, N_p("input-name", "P2 Mahjong I"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_J, N_p("input-name", "P2 Mahjong J"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_K, N_p("input-name", "P2 Mahjong K"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_L, N_p("input-name", "P2 Mahjong L"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_M, N_p("input-name", "P2 Mahjong M"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_N, N_p("input-name", "P2 Mahjong N"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_O, N_p("input-name", "P2 Mahjong O"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_P, N_p("input-name", "P2 Mahjong P"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_Q, N_p("input-name", "P2 Mahjong Q"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_KAN, N_p("input-name", "P2 Mahjong Kan"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_PON, N_p("input-name", "P2 Mahjong Pon"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_CHI, N_p("input-name", "P2 Mahjong Chi"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_REACH, N_p("input-name", "P2 Mahjong Reach"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_RON, N_p("input-name", "P2 Mahjong Ron"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BET, N_p("input-name", "P2 Mahjong Bet"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_LAST_CHANCE, N_p("input-name", "P2 Mahjong Last Chance"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SCORE, N_p("input-name", "P2 Mahjong Take Score"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_DOUBLE_UP, N_p("input-name", "P2 Mahjong Double Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_FLIP_FLOP, N_p("input-name", "P2 Mahjong Flip Flop"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BIG, N_p("input-name", "P2 Mahjong Big"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SMALL, N_p("input-name", "P2 Mahjong Small"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(1)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P2_HANAFUDA \
CORE_INPUT_TYPES_BEGIN(p2_hanafuda) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_A, N_p("input-name", "P2 Hanafuda A/1"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_B, N_p("input-name", "P2 Hanafuda B/2"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_C, N_p("input-name", "P2 Hanafuda C/3"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_D, N_p("input-name", "P2 Hanafuda D/4"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_E, N_p("input-name", "P2 Hanafuda E/5"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_F, N_p("input-name", "P2 Hanafuda F/6"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_G, N_p("input-name", "P2 Hanafuda G/7"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_H, N_p("input-name", "P2 Hanafuda H/8"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_YES, N_p("input-name", "P2 Hanafuda Yes"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_NO, N_p("input-name", "P2 Hanafuda No"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_A, N_p("input-name", "%p Hanafuda A/1"), input_seq(KEYCODE_A_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_B, N_p("input-name", "%p Hanafuda B/2"), input_seq(KEYCODE_B_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_C, N_p("input-name", "%p Hanafuda C/3"), input_seq(KEYCODE_C_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_D, N_p("input-name", "%p Hanafuda D/4"), input_seq(KEYCODE_D_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_E, N_p("input-name", "%p Hanafuda E/5"), input_seq(KEYCODE_E_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_F, N_p("input-name", "%p Hanafuda F/6"), input_seq(KEYCODE_F_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_G, N_p("input-name", "%p Hanafuda G/7"), input_seq(KEYCODE_G_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_H, N_p("input-name", "%p Hanafuda H/8"), input_seq(KEYCODE_H_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_YES, N_p("input-name", "%p Hanafuda Yes"), input_seq(KEYCODE_M_INDEXED(1)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 2, PLAYER2, HANAFUDA_NO, N_p("input-name", "%p Hanafuda No"), input_seq(KEYCODE_N_INDEXED(1)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P3 \
CORE_INPUT_TYPES_BEGIN(p3) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_UP, N_p("input-name", "P3 Up"), input_seq(KEYCODE_I, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_DOWN, N_p("input-name", "P3 Down"), input_seq(KEYCODE_K, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_LEFT, N_p("input-name", "P3 Left"), input_seq(KEYCODE_J, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_RIGHT, N_p("input-name", "P3 Right"), input_seq(KEYCODE_L, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_UP, N_p("input-name", "P3 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_DOWN, N_p("input-name", "P3 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_LEFT, N_p("input-name", "P3 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P3 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_UP, N_p("input-name", "P3 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_DOWN, N_p("input-name", "P3 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_LEFT, N_p("input-name", "P3 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_RIGHT, N_p("input-name", "P3 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON1, N_p("input-name", "P3 Button 1"), input_seq(KEYCODE_RCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(2), input_seq::or_code, GUNCODE_BUTTON1_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON2, N_p("input-name", "P3 Button 2"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2), input_seq::or_code, GUNCODE_BUTTON2_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON3, N_p("input-name", "P3 Button 3"), input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON4, N_p("input-name", "P3 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON5, N_p("input-name", "P3 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON6, N_p("input-name", "P3 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON7, N_p("input-name", "P3 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON8, N_p("input-name", "P3 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON9, N_p("input-name", "P3 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON10, N_p("input-name", "P3 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON11, N_p("input-name", "P3 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON12, N_p("input-name", "P3 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON13, N_p("input-name", "P3 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON14, N_p("input-name", "P3 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON15, N_p("input-name", "P3 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON16, N_p("input-name", "P3 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, START, N_p("input-name", "P3 Start"), input_seq(KEYCODE_3, input_seq::or_code, JOYCODE_START_INDEXED(2)) ) \
- INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, SELECT, N_p("input-name", "P3 Select"), input_seq(KEYCODE_7, input_seq::or_code, JOYCODE_SELECT_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_I) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_J) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_RCONTROL, input_seq::or_code, GUNCODE_BUTTON1_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_RSHIFT, input_seq::or_code, GUNCODE_BUTTON2_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_ENTER) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_3) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_7) ) \
+ CORE_INPUT_TYPES_END()
+
+#define CORE_INPUT_TYPES_P3_MAHJONG \
+ CORE_INPUT_TYPES_BEGIN(p3_mahjong) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(2)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 3, PLAYER3, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(2)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P4 \
CORE_INPUT_TYPES_BEGIN(p4) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_UP, N_p("input-name", "P4 Up"), input_seq(KEYCODE_8_PAD, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_DOWN, N_p("input-name", "P4 Down"), input_seq(KEYCODE_2_PAD, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_LEFT, N_p("input-name", "P4 Left"), input_seq(KEYCODE_4_PAD, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_RIGHT, N_p("input-name", "P4 Right"), input_seq(KEYCODE_6_PAD, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_UP, N_p("input-name", "P4 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_DOWN, N_p("input-name", "P4 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_LEFT, N_p("input-name", "P4 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P4 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_UP, N_p("input-name", "P4 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_DOWN, N_p("input-name", "P4 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_LEFT, N_p("input-name", "P4 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_RIGHT, N_p("input-name", "P4 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON1, N_p("input-name", "P4 Button 1"), input_seq(KEYCODE_0_PAD, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON2, N_p("input-name", "P4 Button 2"), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON3, N_p("input-name", "P4 Button 3"), input_seq(KEYCODE_ENTER_PAD, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON4, N_p("input-name", "P4 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON5, N_p("input-name", "P4 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON6, N_p("input-name", "P4 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON7, N_p("input-name", "P4 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON8, N_p("input-name", "P4 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON9, N_p("input-name", "P4 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON10, N_p("input-name", "P4 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON11, N_p("input-name", "P4 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON12, N_p("input-name", "P4 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON13, N_p("input-name", "P4 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON14, N_p("input-name", "P4 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON15, N_p("input-name", "P4 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON16, N_p("input-name", "P4 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, START, N_p("input-name", "P4 Start"), input_seq(KEYCODE_4, input_seq::or_code, JOYCODE_START_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, SELECT, N_p("input-name", "P4 Select"), input_seq(KEYCODE_8, input_seq::or_code, JOYCODE_SELECT_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq(KEYCODE_8_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq(KEYCODE_2_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq(KEYCODE_4_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq(KEYCODE_6_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON1, N_p("input-name", "%p Button 1"), input_seq(KEYCODE_0_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON2, N_p("input-name", "%p Button 2"), input_seq(KEYCODE_DEL_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON3, N_p("input-name", "%p Button 3"), input_seq(KEYCODE_ENTER_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, START, N_p("input-name", "%p Start"), input_seq(KEYCODE_4) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, SELECT, N_p("input-name", "%p Select"), input_seq(KEYCODE_8) ) \
+ CORE_INPUT_TYPES_END()
+
+#define CORE_INPUT_TYPES_P4_MAHJONG \
+ CORE_INPUT_TYPES_BEGIN(p4_mahjong) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_A, N_p("input-name", "%p Mahjong A"), input_seq(KEYCODE_A_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_B, N_p("input-name", "%p Mahjong B"), input_seq(KEYCODE_B_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_C, N_p("input-name", "%p Mahjong C"), input_seq(KEYCODE_C_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_D, N_p("input-name", "%p Mahjong D"), input_seq(KEYCODE_D_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_E, N_p("input-name", "%p Mahjong E"), input_seq(KEYCODE_E_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_F, N_p("input-name", "%p Mahjong F"), input_seq(KEYCODE_F_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_G, N_p("input-name", "%p Mahjong G"), input_seq(KEYCODE_G_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_H, N_p("input-name", "%p Mahjong H"), input_seq(KEYCODE_H_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_I, N_p("input-name", "%p Mahjong I"), input_seq(KEYCODE_I_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_J, N_p("input-name", "%p Mahjong J"), input_seq(KEYCODE_J_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_K, N_p("input-name", "%p Mahjong K"), input_seq(KEYCODE_K_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_L, N_p("input-name", "%p Mahjong L"), input_seq(KEYCODE_L_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_M, N_p("input-name", "%p Mahjong M"), input_seq(KEYCODE_M_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_N, N_p("input-name", "%p Mahjong N"), input_seq(KEYCODE_N_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_O, N_p("input-name", "%p Mahjong O"), input_seq(KEYCODE_O_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_P, N_p("input-name", "%p Mahjong P"), input_seq(KEYCODE_COLON_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_Q, N_p("input-name", "%p Mahjong Q"), input_seq(KEYCODE_Q_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_KAN, N_p("input-name", "%p Mahjong Kan"), input_seq(KEYCODE_LCONTROL_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_PON, N_p("input-name", "%p Mahjong Pon"), input_seq(KEYCODE_LALT_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_CHI, N_p("input-name", "%p Mahjong Chi"), input_seq(KEYCODE_SPACE_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_REACH, N_p("input-name", "%p Mahjong Reach"), input_seq(KEYCODE_LSHIFT_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_RON, N_p("input-name", "%p Mahjong Ron"), input_seq(KEYCODE_Z_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_FLIP_FLOP, N_p("input-name", "%p Mahjong Flip Flop"), input_seq(KEYCODE_Y_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_BET, N_p("input-name", "%p Mahjong Bet"), input_seq(KEYCODE_3_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_SCORE, N_p("input-name", "%p Mahjong Take Score"), input_seq(KEYCODE_RCONTROL_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_DOUBLE_UP, N_p("input-name", "%p Mahjong Double Up"), input_seq(KEYCODE_RSHIFT_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_BIG, N_p("input-name", "%p Mahjong Big"), input_seq(KEYCODE_ENTER_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_SMALL, N_p("input-name", "%p Mahjong Small"), input_seq(KEYCODE_BACKSPACE_INDEXED(3)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 4, PLAYER4, MAHJONG_LAST_CHANCE, N_p("input-name", "%p Mahjong Last Chance"), input_seq(KEYCODE_RALT_INDEXED(3)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P5 \
CORE_INPUT_TYPES_BEGIN(p5) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_UP, N_p("input-name", "P5 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_DOWN, N_p("input-name", "P5 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_LEFT, N_p("input-name", "P5 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_RIGHT, N_p("input-name", "P5 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_UP, N_p("input-name", "P5 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_DOWN, N_p("input-name", "P5 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_LEFT, N_p("input-name", "P5 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P5 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_UP, N_p("input-name", "P5 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_DOWN, N_p("input-name", "P5 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_LEFT, N_p("input-name", "P5 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_RIGHT, N_p("input-name", "P5 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON1, N_p("input-name", "P5 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON2, N_p("input-name", "P5 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON3, N_p("input-name", "P5 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON4, N_p("input-name", "P5 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON5, N_p("input-name", "P5 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON6, N_p("input-name", "P5 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON7, N_p("input-name", "P5 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON8, N_p("input-name", "P5 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON9, N_p("input-name", "P5 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON10, N_p("input-name", "P5 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON11, N_p("input-name", "P5 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON12, N_p("input-name", "P5 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON13, N_p("input-name", "P5 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON14, N_p("input-name", "P5 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON15, N_p("input-name", "P5 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON16, N_p("input-name", "P5 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(4)) ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, START, N_p("input-name", "P5 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, SELECT, N_p("input-name", "P5 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 5, PLAYER5, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P6 \
CORE_INPUT_TYPES_BEGIN(p6) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_UP, N_p("input-name", "P6 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_DOWN, N_p("input-name", "P6 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_LEFT, N_p("input-name", "P6 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_RIGHT, N_p("input-name", "P6 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_UP, N_p("input-name", "P6 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_DOWN, N_p("input-name", "P6 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_LEFT, N_p("input-name", "P6 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P6 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_UP, N_p("input-name", "P6 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_DOWN, N_p("input-name", "P6 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_LEFT, N_p("input-name", "P6 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_RIGHT, N_p("input-name", "P6 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON1, N_p("input-name", "P6 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON2, N_p("input-name", "P6 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON3, N_p("input-name", "P6 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON4, N_p("input-name", "P6 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON5, N_p("input-name", "P6 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON6, N_p("input-name", "P6 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON7, N_p("input-name", "P6 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON8, N_p("input-name", "P6 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON9, N_p("input-name", "P6 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON10, N_p("input-name", "P6 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON11, N_p("input-name", "P6 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON12, N_p("input-name", "P6 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON13, N_p("input-name", "P6 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON14, N_p("input-name", "P6 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON15, N_p("input-name", "P6 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON16, N_p("input-name", "P6 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(5)) ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, START, N_p("input-name", "P6 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, SELECT, N_p("input-name", "P6 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 6, PLAYER6, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P7 \
CORE_INPUT_TYPES_BEGIN(p7) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_UP, N_p("input-name", "P7 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_DOWN, N_p("input-name", "P7 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_LEFT, N_p("input-name", "P7 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_RIGHT, N_p("input-name", "P7 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_UP, N_p("input-name", "P7 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_DOWN, N_p("input-name", "P7 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_LEFT, N_p("input-name", "P7 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P7 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_UP, N_p("input-name", "P7 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_DOWN, N_p("input-name", "P7 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_LEFT, N_p("input-name", "P7 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_RIGHT, N_p("input-name", "P7 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON1, N_p("input-name", "P7 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON2, N_p("input-name", "P7 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON3, N_p("input-name", "P7 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON4, N_p("input-name", "P7 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON5, N_p("input-name", "P7 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON6, N_p("input-name", "P7 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON7, N_p("input-name", "P7 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON8, N_p("input-name", "P7 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON9, N_p("input-name", "P7 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON10, N_p("input-name", "P7 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON11, N_p("input-name", "P7 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON12, N_p("input-name", "P7 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON13, N_p("input-name", "P7 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON14, N_p("input-name", "P7 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON15, N_p("input-name", "P7 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON16, N_p("input-name", "P7 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(6)) ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, START, N_p("input-name", "P7 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, SELECT, N_p("input-name", "P7 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 7, PLAYER7, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P8 \
CORE_INPUT_TYPES_BEGIN(p8) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_UP, N_p("input-name", "P8 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_DOWN, N_p("input-name", "P8 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_LEFT, N_p("input-name", "P8 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_RIGHT, N_p("input-name", "P8 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_UP, N_p("input-name", "P8 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_DOWN, N_p("input-name", "P8 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_LEFT, N_p("input-name", "P8 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P8 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_UP, N_p("input-name", "P8 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_DOWN, N_p("input-name", "P8 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_LEFT, N_p("input-name", "P8 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_RIGHT, N_p("input-name", "P8 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON1, N_p("input-name", "P8 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON2, N_p("input-name", "P8 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON3, N_p("input-name", "P8 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON4, N_p("input-name", "P8 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON5, N_p("input-name", "P8 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON6, N_p("input-name", "P8 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON7, N_p("input-name", "P8 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON8, N_p("input-name", "P8 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON9, N_p("input-name", "P8 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON10, N_p("input-name", "P8 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON11, N_p("input-name", "P8 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON12, N_p("input-name", "P8 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON13, N_p("input-name", "P8 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON14, N_p("input-name", "P8 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON15, N_p("input-name", "P8 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON16, N_p("input-name", "P8 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(7)) ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, START, N_p("input-name", "P8 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, SELECT, N_p("input-name", "P8 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 8, PLAYER8, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P9 \
CORE_INPUT_TYPES_BEGIN(p9) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_UP, N_p("input-name", "P9 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_DOWN, N_p("input-name", "P9 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_LEFT, N_p("input-name", "P9 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_RIGHT, N_p("input-name", "P9 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_UP, N_p("input-name", "P9 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_DOWN, N_p("input-name", "P9 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_LEFT, N_p("input-name", "P9 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P9 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_UP, N_p("input-name", "P9 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_DOWN, N_p("input-name", "P9 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_LEFT, N_p("input-name", "P9 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_RIGHT, N_p("input-name", "P9 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON1, N_p("input-name", "P9 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON2, N_p("input-name", "P9 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON3, N_p("input-name", "P9 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON4, N_p("input-name", "P9 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON5, N_p("input-name", "P9 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON6, N_p("input-name", "P9 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON7, N_p("input-name", "P9 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON8, N_p("input-name", "P9 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON9, N_p("input-name", "P9 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON10, N_p("input-name", "P9 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON11, N_p("input-name", "P9 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON12, N_p("input-name", "P9 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON13, N_p("input-name", "P9 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON14, N_p("input-name", "P9 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON15, N_p("input-name", "P9 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON16, N_p("input-name", "P9 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(8)) ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, START, N_p("input-name", "P9 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, SELECT, N_p("input-name", "P9 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 9, PLAYER9, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_P10 \
CORE_INPUT_TYPES_BEGIN(p10) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_UP, N_p("input-name", "P10 Up"), input_seq(JOYCODE_Y_UP_SWITCH_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_DOWN, N_p("input-name", "P10 Down"), input_seq(JOYCODE_Y_DOWN_SWITCH_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_LEFT, N_p("input-name", "P10 Left"), input_seq(JOYCODE_X_LEFT_SWITCH_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_RIGHT, N_p("input-name", "P10 Right"), input_seq(JOYCODE_X_RIGHT_SWITCH_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_UP, N_p("input-name", "P10 Right Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_DOWN, N_p("input-name", "P10 Right Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_LEFT, N_p("input-name", "P10 Right Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_RIGHT, N_p("input-name", "P10 Right Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_UP, N_p("input-name", "P10 Left Stick/Up"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_DOWN, N_p("input-name", "P10 Left Stick/Down"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_LEFT, N_p("input-name", "P10 Left Stick/Left"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_RIGHT, N_p("input-name", "P10 Left Stick/Right"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON1, N_p("input-name", "P10 Button 1"), input_seq(JOYCODE_BUTTON1_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON2, N_p("input-name", "P10 Button 2"), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON3, N_p("input-name", "P10 Button 3"), input_seq(JOYCODE_BUTTON3_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON4, N_p("input-name", "P10 Button 4"), input_seq(JOYCODE_BUTTON4_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON5, N_p("input-name", "P10 Button 5"), input_seq(JOYCODE_BUTTON5_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON6, N_p("input-name", "P10 Button 6"), input_seq(JOYCODE_BUTTON6_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON7, N_p("input-name", "P10 Button 7"), input_seq(JOYCODE_BUTTON7_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON8, N_p("input-name", "P10 Button 8"), input_seq(JOYCODE_BUTTON8_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON9, N_p("input-name", "P10 Button 9"), input_seq(JOYCODE_BUTTON9_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON10, N_p("input-name", "P10 Button 10"), input_seq(JOYCODE_BUTTON10_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON11, N_p("input-name", "P10 Button 11"), input_seq(JOYCODE_BUTTON11_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON12, N_p("input-name", "P10 Button 12"), input_seq(JOYCODE_BUTTON12_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON13, N_p("input-name", "P10 Button 13"), input_seq(JOYCODE_BUTTON13_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON14, N_p("input-name", "P10 Button 14"), input_seq(JOYCODE_BUTTON14_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON15, N_p("input-name", "P10 Button 15"), input_seq(JOYCODE_BUTTON15_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON16, N_p("input-name", "P10 Button 16"), input_seq(JOYCODE_BUTTON16_INDEXED(9)) ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, START, N_p("input-name", "P10 Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, SELECT, N_p("input-name", "P10 Select"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_UP, N_p("input-name", "%p Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_DOWN, N_p("input-name", "%p Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_LEFT, N_p("input-name", "%p Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICK_RIGHT, N_p("input-name", "%p Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_UP, N_p("input-name", "%p Right Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_DOWN, N_p("input-name", "%p Right Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_LEFT, N_p("input-name", "%p Right Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKRIGHT_RIGHT, N_p("input-name", "%p Right Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_UP, N_p("input-name", "%p Left Stick/Up"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_DOWN, N_p("input-name", "%p Left Stick/Down"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_LEFT, N_p("input-name", "%p Left Stick/Left"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, JOYSTICKLEFT_RIGHT, N_p("input-name", "%p Left Stick/Right"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON1, N_p("input-name", "%p Button 1"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON2, N_p("input-name", "%p Button 2"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON3, N_p("input-name", "%p Button 3"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON4, N_p("input-name", "%p Button 4"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON5, N_p("input-name", "%p Button 5"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON6, N_p("input-name", "%p Button 6"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON7, N_p("input-name", "%p Button 7"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON8, N_p("input-name", "%p Button 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON9, N_p("input-name", "%p Button 9"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON10, N_p("input-name", "%p Button 10"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON11, N_p("input-name", "%p Button 11"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON12, N_p("input-name", "%p Button 12"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON13, N_p("input-name", "%p Button 13"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON14, N_p("input-name", "%p Button 14"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON15, N_p("input-name", "%p Button 15"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, BUTTON16, N_p("input-name", "%p Button 16"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, START, N_p("input-name", "%p Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 10, PLAYER10, SELECT, N_p("input-name", "%p Select"), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_START \
@@ -494,10 +560,10 @@ namespace {
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START2, N_p("input-name", "2 Players Start"), input_seq(KEYCODE_2, input_seq::or_code, JOYCODE_START_INDEXED(1)) ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START3, N_p("input-name", "3 Players Start"), input_seq(KEYCODE_3, input_seq::or_code, JOYCODE_START_INDEXED(2)) ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START4, N_p("input-name", "4 Players Start"), input_seq(KEYCODE_4, input_seq::or_code, JOYCODE_START_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START5, N_p("input-name", "5 Players Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START6, N_p("input-name", "6 Players Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START7, N_p("input-name", "7 Players Start"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START8, N_p("input-name", "8 Players Start"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START5, N_p("input-name", "5 Players Start"), input_seq(JOYCODE_START_INDEXED(4)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START6, N_p("input-name", "6 Players Start"), input_seq(JOYCODE_START_INDEXED(5)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START7, N_p("input-name", "7 Players Start"), input_seq(JOYCODE_START_INDEXED(6)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, START8, N_p("input-name", "8 Players Start"), input_seq(JOYCODE_START_INDEXED(7)) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_COIN \
@@ -506,15 +572,15 @@ namespace {
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN2, N_p("input-name", "Coin 2"), input_seq(KEYCODE_6, input_seq::or_code, JOYCODE_SELECT_INDEXED(1)) ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN3, N_p("input-name", "Coin 3"), input_seq(KEYCODE_7, input_seq::or_code, JOYCODE_SELECT_INDEXED(2)) ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN4, N_p("input-name", "Coin 4"), input_seq(KEYCODE_8, input_seq::or_code, JOYCODE_SELECT_INDEXED(3)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN5, N_p("input-name", "Coin 5"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN6, N_p("input-name", "Coin 6"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN7, N_p("input-name", "Coin 7"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN8, N_p("input-name", "Coin 8"), input_seq() ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN5, N_p("input-name", "Coin 5"), input_seq(JOYCODE_SELECT_INDEXED(4)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN6, N_p("input-name", "Coin 6"), input_seq(JOYCODE_SELECT_INDEXED(5)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN7, N_p("input-name", "Coin 7"), input_seq(JOYCODE_SELECT_INDEXED(6)) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN8, N_p("input-name", "Coin 8"), input_seq(JOYCODE_SELECT_INDEXED(7)) ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN9, N_p("input-name", "Coin 9"), input_seq() ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN10, N_p("input-name", "Coin 10"), input_seq() ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN11, N_p("input-name", "Coin 11"), input_seq() ) \
INPUT_PORT_DIGITAL_TYPE( 0, OTHER, COIN12, N_p("input-name", "Coin 12"), input_seq() ) \
- INPUT_PORT_DIGITAL_TYPE( 0, OTHER, BILL1, N_p("input-name", "Bill 1"), input_seq(KEYCODE_BACKSPACE) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, OTHER, BILL1, N_p("input-name", "Banknote 1"), input_seq(KEYCODE_BACKSPACE) ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_SERVICE \
@@ -547,226 +613,226 @@ namespace {
#define CORE_INPUT_TYPES_PEDAL \
CORE_INPUT_TYPES_BEGIN(pedal) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL, N_p("input-name", "P1 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0)) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL, N_p("input-name", "P2 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_A, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(1)) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL, N_p("input-name", "P3 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RCONTROL, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(2)) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL, N_p("input-name", "P4 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_0_PAD, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(3)) ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL, N_p("input-name", "P5 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(4)) ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL, N_p("input-name", "P6 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(5)) ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL, N_p("input-name", "P7 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(6)) ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL, N_p("input-name", "P8 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(7)) ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL, N_p("input-name", "P9 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(8)) ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL, N_p("input-name", "P10 Pedal 1"), input_seq(JOYCODE_Z_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON1_INDEXED(9)) ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_LCONTROL) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_A) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_RCONTROL) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq(KEYCODE_0_PAD) ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL, N_p("input-name", "%p Pedal 1"), input_seq(), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_PEDAL2 \
CORE_INPUT_TYPES_BEGIN(pedal2) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, N_p("input-name", "P1 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, N_p("input-name", "P2 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, N_p("input-name", "P3 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, N_p("input-name", "P4 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, N_p("input-name", "P5 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, N_p("input-name", "P6 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, N_p("input-name", "P7 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, N_p("input-name", "P8 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, N_p("input-name", "P9 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, N_p("input-name", "P10 Pedal 2"), input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_LALT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_S) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_RSHIFT) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq(KEYCODE_DEL_PAD) ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, N_p("input-name", "%p Pedal 2"), input_seq(), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_PEDAL3 \
CORE_INPUT_TYPES_BEGIN(pedal3) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL3, N_p("input-name", "P1 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_SPACE, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(0)) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL3, N_p("input-name", "P2 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_Q, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(1)) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL3, N_p("input-name", "P3 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(2)) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL3, N_p("input-name", "P4 Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER_PAD, input_seq::or_code, JOYCODE_BUTTON3_INDEXED(3)) ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL3, N_p("input-name", "P5 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(4)) ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL3, N_p("input-name", "P6 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(5)) ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL3, N_p("input-name", "P7 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(6)) ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL3, N_p("input-name", "P8 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(7)) ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL3, N_p("input-name", "P9 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(8)) ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL3, N_p("input-name", "P10 Pedal 3"), input_seq(), input_seq(), input_seq(JOYCODE_BUTTON3_INDEXED(9)) ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_SPACE) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_Q) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq(KEYCODE_ENTER_PAD) ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL3, N_p("input-name", "%p Pedal 3"), input_seq(), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_PADDLE \
CORE_INPUT_TYPES_BEGIN(paddle) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE, N_p("input-name", "Paddle"), input_seq(JOYCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE, N_p("input-name", "Paddle 2"), input_seq(JOYCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE, N_p("input-name", "Paddle 3"), input_seq(JOYCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE, N_p("input-name", "Paddle 4"), input_seq(JOYCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE, N_p("input-name", "Paddle 5"), input_seq(JOYCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE, N_p("input-name", "Paddle 6"), input_seq(JOYCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE, N_p("input-name", "Paddle 7"), input_seq(JOYCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE, N_p("input-name", "Paddle 8"), input_seq(JOYCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE, N_p("input-name", "Paddle 9"), input_seq(JOYCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE, N_p("input-name", "Paddle 10"), input_seq(JOYCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE, N_p("input-name", "Paddle"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE, N_p("input-name", "Paddle 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE, N_p("input-name", "Paddle 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE, N_p("input-name", "Paddle 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE, N_p("input-name", "Paddle 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE, N_p("input-name", "Paddle 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE, N_p("input-name", "Paddle 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE, N_p("input-name", "Paddle 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE, N_p("input-name", "Paddle 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE, N_p("input-name", "Paddle 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_PADDLE_V \
CORE_INPUT_TYPES_BEGIN(paddle_v) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE_V, N_p("input-name", "Paddle V"), input_seq(JOYCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE_V, N_p("input-name", "Paddle V 2"), input_seq(JOYCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE_V, N_p("input-name", "Paddle V 3"), input_seq(JOYCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE_V, N_p("input-name", "Paddle V 4"), input_seq(JOYCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE_V, N_p("input-name", "Paddle V 5"), input_seq(JOYCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE_V, N_p("input-name", "Paddle V 6"), input_seq(JOYCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, N_p("input-name", "Paddle V 7"), input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, N_p("input-name", "Paddle V 8"), input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, N_p("input-name", "Paddle V 9"), input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, N_p("input-name", "Paddle V 10"), input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PADDLE_V, N_p("input-name", "Paddle V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PADDLE_V, N_p("input-name", "Paddle V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PADDLE_V, N_p("input-name", "Paddle V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PADDLE_V, N_p("input-name", "Paddle V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PADDLE_V, N_p("input-name", "Paddle V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PADDLE_V, N_p("input-name", "Paddle V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, N_p("input-name", "Paddle V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, N_p("input-name", "Paddle V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, N_p("input-name", "Paddle V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, N_p("input-name", "Paddle V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_POSITIONAL \
CORE_INPUT_TYPES_BEGIN(positional) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL, N_p("input-name", "Positional"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL, N_p("input-name", "Positional 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL, N_p("input-name", "Positional 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL, N_p("input-name", "Positional 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL, N_p("input-name", "Positional 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL, N_p("input-name", "Positional 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL, N_p("input-name", "Positional 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL, N_p("input-name", "Positional 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL, N_p("input-name", "Positional 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL, N_p("input-name", "Positional 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL, N_p("input-name", "Positional"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL, N_p("input-name", "Positional 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL, N_p("input-name", "Positional 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL, N_p("input-name", "Positional 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL, N_p("input-name", "Positional 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL, N_p("input-name", "Positional 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL, N_p("input-name", "Positional 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL, N_p("input-name", "Positional 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL, N_p("input-name", "Positional 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL, N_p("input-name", "Positional 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_POSITIONAL_V \
CORE_INPUT_TYPES_BEGIN(positional_v) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL_V, N_p("input-name", "Positional V"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL_V, N_p("input-name", "Positional V 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL_V, N_p("input-name", "Positional V 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL_V, N_p("input-name", "Positional V 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL_V, N_p("input-name", "Positional V 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL_V, N_p("input-name", "Positional V 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL_V, N_p("input-name", "Positional V 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL_V, N_p("input-name", "Positional V 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL_V, N_p("input-name", "Positional V 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL_V, N_p("input-name", "Positional V 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, POSITIONAL_V, N_p("input-name", "Positional V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, POSITIONAL_V, N_p("input-name", "Positional V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, POSITIONAL_V, N_p("input-name", "Positional V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, POSITIONAL_V, N_p("input-name", "Positional V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, POSITIONAL_V, N_p("input-name", "Positional V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, POSITIONAL_V, N_p("input-name", "Positional V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, POSITIONAL_V, N_p("input-name", "Positional V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, POSITIONAL_V, N_p("input-name", "Positional V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, POSITIONAL_V, N_p("input-name", "Positional V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, POSITIONAL_V, N_p("input-name", "Positional V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_DIAL \
CORE_INPUT_TYPES_BEGIN(dial) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL, N_p("input-name", "Dial"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL, N_p("input-name", "Dial 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL, N_p("input-name", "Dial 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL, N_p("input-name", "Dial 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL, N_p("input-name", "Dial 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL, N_p("input-name", "Dial 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL, N_p("input-name", "Dial 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL, N_p("input-name", "Dial 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL, N_p("input-name", "Dial 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL, N_p("input-name", "Dial 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL, N_p("input-name", "Dial"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL, N_p("input-name", "Dial 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL, N_p("input-name", "Dial 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL, N_p("input-name", "Dial 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL, N_p("input-name", "Dial 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL, N_p("input-name", "Dial 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL, N_p("input-name", "Dial 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL, N_p("input-name", "Dial 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL, N_p("input-name", "Dial 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL, N_p("input-name", "Dial 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_DIAL_V \
CORE_INPUT_TYPES_BEGIN(dial_v) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL_V, N_p("input-name", "Dial V"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL_V, N_p("input-name", "Dial V 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL_V, N_p("input-name", "Dial V 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL_V, N_p("input-name", "Dial V 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL_V, N_p("input-name", "Dial V 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL_V, N_p("input-name", "Dial V 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL_V, N_p("input-name", "Dial V 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL_V, N_p("input-name", "Dial V 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL_V, N_p("input-name", "Dial V 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL_V, N_p("input-name", "Dial V 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, DIAL_V, N_p("input-name", "Dial V"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, DIAL_V, N_p("input-name", "Dial V 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, DIAL_V, N_p("input-name", "Dial V 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, DIAL_V, N_p("input-name", "Dial V 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, DIAL_V, N_p("input-name", "Dial V 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, DIAL_V, N_p("input-name", "Dial V 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, DIAL_V, N_p("input-name", "Dial V 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, DIAL_V, N_p("input-name", "Dial V 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, DIAL_V, N_p("input-name", "Dial V 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, DIAL_V, N_p("input-name", "Dial V 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_TRACKBALL_X \
CORE_INPUT_TYPES_BEGIN(trackball_x) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_X, N_p("input-name", "Track X"), input_seq(MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_X, N_p("input-name", "Track X 2"), input_seq(MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_X, N_p("input-name", "Track X 3"), input_seq(MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_X, N_p("input-name", "Track X 4"), input_seq(MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_X, N_p("input-name", "Track X 5"), input_seq(MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_X, N_p("input-name", "Track X 6"), input_seq(MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_X, N_p("input-name", "Track X 7"), input_seq(MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_X, N_p("input-name", "Track X 8"), input_seq(MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_X, N_p("input-name", "Track X 9"), input_seq(MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_X, N_p("input-name", "Track X 10"), input_seq(MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_X, N_p("input-name", "Trackball X"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_X, N_p("input-name", "Trackball X 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_X, N_p("input-name", "Trackball X 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_X, N_p("input-name", "Trackball X 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_X, N_p("input-name", "Trackball X 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_X, N_p("input-name", "Trackball X 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_X, N_p("input-name", "Trackball X 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_X, N_p("input-name", "Trackball X 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_X, N_p("input-name", "Trackball X 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_X, N_p("input-name", "Trackball X 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_TRACKBALL_Y \
CORE_INPUT_TYPES_BEGIN(trackball_y) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_Y, N_p("input-name", "Track Y"), input_seq(MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_Y, N_p("input-name", "Track Y 2"), input_seq(MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_Y, N_p("input-name", "Track Y 3"), input_seq(MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_Y, N_p("input-name", "Track Y 4"), input_seq(MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_Y, N_p("input-name", "Track Y 5"), input_seq(MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_Y, N_p("input-name", "Track Y 6"), input_seq(MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_Y, N_p("input-name", "Track Y 7"), input_seq(MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_Y, N_p("input-name", "Track Y 8"), input_seq(MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_Y, N_p("input-name", "Track Y 9"), input_seq(MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_Y, N_p("input-name", "Track Y 10"), input_seq(MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, TRACKBALL_Y, N_p("input-name", "Trackball Y"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, TRACKBALL_Y, N_p("input-name", "Trackball Y 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, TRACKBALL_Y, N_p("input-name", "Trackball Y 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, TRACKBALL_Y, N_p("input-name", "Trackball Y 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, TRACKBALL_Y, N_p("input-name", "Trackball Y 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, TRACKBALL_Y, N_p("input-name", "Trackball Y 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, TRACKBALL_Y, N_p("input-name", "Trackball Y 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, TRACKBALL_Y, N_p("input-name", "Trackball Y 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, TRACKBALL_Y, N_p("input-name", "Trackball Y 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, TRACKBALL_Y, N_p("input-name", "Trackball Y 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_AD_STICK_X \
CORE_INPUT_TYPES_BEGIN(ad_stick_x) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_X, N_p("input-name", "AD Stick X"), input_seq(JOYCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_X, N_p("input-name", "AD Stick X 2"), input_seq(JOYCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_X, N_p("input-name", "AD Stick X 3"), input_seq(JOYCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_X, N_p("input-name", "AD Stick X 4"), input_seq(JOYCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_X, N_p("input-name", "AD Stick X 5"), input_seq(JOYCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_X, N_p("input-name", "AD Stick X 6"), input_seq(JOYCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_X, N_p("input-name", "AD Stick X 7"), input_seq(JOYCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_X, N_p("input-name", "AD Stick X 8"), input_seq(JOYCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_X, N_p("input-name", "AD Stick X 9"), input_seq(JOYCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_X, N_p("input-name", "AD Stick X 10"), input_seq(JOYCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_X, N_p("input-name", "AD Stick X"), input_seq(MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_X, N_p("input-name", "AD Stick X 2"), input_seq(MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_X, N_p("input-name", "AD Stick X 3"), input_seq(MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_X, N_p("input-name", "AD Stick X 4"), input_seq(MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_X, N_p("input-name", "AD Stick X 5"), input_seq(MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_X, N_p("input-name", "AD Stick X 6"), input_seq(MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_X, N_p("input-name", "AD Stick X 7"), input_seq(MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_X, N_p("input-name", "AD Stick X 8"), input_seq(MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_X, N_p("input-name", "AD Stick X 9"), input_seq(MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_X, N_p("input-name", "AD Stick X 10"), input_seq(MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_AD_STICK_Y \
CORE_INPUT_TYPES_BEGIN(ad_stick_y) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Y, N_p("input-name", "AD Stick Y"), input_seq(JOYCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Y, N_p("input-name", "AD Stick Y 2"), input_seq(JOYCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Y, N_p("input-name", "AD Stick Y 3"), input_seq(JOYCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Y, N_p("input-name", "AD Stick Y 4"), input_seq(JOYCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Y, N_p("input-name", "AD Stick Y 5"), input_seq(JOYCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Y, N_p("input-name", "AD Stick Y 6"), input_seq(JOYCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Y, N_p("input-name", "AD Stick Y 7"), input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Y, N_p("input-name", "AD Stick Y 8"), input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Y, N_p("input-name", "AD Stick Y 9"), input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Y, N_p("input-name", "AD Stick Y 10"), input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Y, N_p("input-name", "AD Stick Y"), input_seq(MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Y, N_p("input-name", "AD Stick Y 2"), input_seq(MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Y, N_p("input-name", "AD Stick Y 3"), input_seq(MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Y, N_p("input-name", "AD Stick Y 4"), input_seq(MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Y, N_p("input-name", "AD Stick Y 5"), input_seq(MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Y, N_p("input-name", "AD Stick Y 6"), input_seq(MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Y, N_p("input-name", "AD Stick Y 7"), input_seq(MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Y, N_p("input-name", "AD Stick Y 8"), input_seq(MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Y, N_p("input-name", "AD Stick Y 9"), input_seq(MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Y, N_p("input-name", "AD Stick Y 10"), input_seq(MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_AD_STICK_Z \
CORE_INPUT_TYPES_BEGIN(ad_stick_z) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Z, N_p("input-name", "AD Stick Z"), input_seq(JOYCODE_Z_INDEXED(0)), input_seq(KEYCODE_A), input_seq(KEYCODE_Z) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Z, N_p("input-name", "AD Stick Z 2"), input_seq(JOYCODE_Z_INDEXED(1)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Z, N_p("input-name", "AD Stick Z 3"), input_seq(JOYCODE_Z_INDEXED(2)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Z, N_p("input-name", "AD Stick Z 4"), input_seq(JOYCODE_Z_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Z, N_p("input-name", "AD Stick Z 5"), input_seq(JOYCODE_Z_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Z, N_p("input-name", "AD Stick Z 6"), input_seq(JOYCODE_Z_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Z, N_p("input-name", "AD Stick Z 7"), input_seq(JOYCODE_Z_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Z, N_p("input-name", "AD Stick Z 8"), input_seq(JOYCODE_Z_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Z, N_p("input-name", "AD Stick Z 9"), input_seq(JOYCODE_Z_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Z, N_p("input-name", "AD Stick Z 10"), input_seq(JOYCODE_Z_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, AD_STICK_Z, N_p("input-name", "AD Stick Z"), input_seq(), input_seq(KEYCODE_A), input_seq(KEYCODE_Z) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, AD_STICK_Z, N_p("input-name", "AD Stick Z 2"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, AD_STICK_Z, N_p("input-name", "AD Stick Z 3"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, AD_STICK_Z, N_p("input-name", "AD Stick Z 4"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, AD_STICK_Z, N_p("input-name", "AD Stick Z 5"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, AD_STICK_Z, N_p("input-name", "AD Stick Z 6"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, AD_STICK_Z, N_p("input-name", "AD Stick Z 7"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, AD_STICK_Z, N_p("input-name", "AD Stick Z 8"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, AD_STICK_Z, N_p("input-name", "AD Stick Z 9"), input_seq(), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, AD_STICK_Z, N_p("input-name", "AD Stick Z 10"), input_seq(), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_LIGHTGUN_X \
CORE_INPUT_TYPES_BEGIN(lightgun_x) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_X, N_p("input-name", "Lightgun X"), input_seq(GUNCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0), input_seq::or_code, JOYCODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_X, N_p("input-name", "Lightgun X 2"), input_seq(GUNCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1), input_seq::or_code, JOYCODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_X, N_p("input-name", "Lightgun X 3"), input_seq(GUNCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2), input_seq::or_code, JOYCODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_X, N_p("input-name", "Lightgun X 4"), input_seq(GUNCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3), input_seq::or_code, JOYCODE_X_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_X, N_p("input-name", "Lightgun X 5"), input_seq(GUNCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4), input_seq::or_code, JOYCODE_X_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_X, N_p("input-name", "Lightgun X 6"), input_seq(GUNCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5), input_seq::or_code, JOYCODE_X_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_X, N_p("input-name", "Lightgun X 7"), input_seq(GUNCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6), input_seq::or_code, JOYCODE_X_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_X, N_p("input-name", "Lightgun X 8"), input_seq(GUNCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7), input_seq::or_code, JOYCODE_X_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_X, N_p("input-name", "Lightgun X 9"), input_seq(GUNCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8), input_seq::or_code, JOYCODE_X_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_X, N_p("input-name", "Lightgun X 10"), input_seq(GUNCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9), input_seq::or_code, JOYCODE_X_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_X, N_p("input-name", "Lightgun X"), input_seq(GUNCODE_X_INDEXED(0), input_seq::or_code, MOUSECODE_X_INDEXED(0)), input_seq(KEYCODE_LEFT), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_X, N_p("input-name", "Lightgun X 2"), input_seq(GUNCODE_X_INDEXED(1), input_seq::or_code, MOUSECODE_X_INDEXED(1)), input_seq(KEYCODE_D), input_seq(KEYCODE_G) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_X, N_p("input-name", "Lightgun X 3"), input_seq(GUNCODE_X_INDEXED(2), input_seq::or_code, MOUSECODE_X_INDEXED(2)), input_seq(KEYCODE_J), input_seq(KEYCODE_L) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_X, N_p("input-name", "Lightgun X 4"), input_seq(GUNCODE_X_INDEXED(3), input_seq::or_code, MOUSECODE_X_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_X, N_p("input-name", "Lightgun X 5"), input_seq(GUNCODE_X_INDEXED(4), input_seq::or_code, MOUSECODE_X_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_X, N_p("input-name", "Lightgun X 6"), input_seq(GUNCODE_X_INDEXED(5), input_seq::or_code, MOUSECODE_X_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_X, N_p("input-name", "Lightgun X 7"), input_seq(GUNCODE_X_INDEXED(6), input_seq::or_code, MOUSECODE_X_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_X, N_p("input-name", "Lightgun X 8"), input_seq(GUNCODE_X_INDEXED(7), input_seq::or_code, MOUSECODE_X_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_X, N_p("input-name", "Lightgun X 9"), input_seq(GUNCODE_X_INDEXED(8), input_seq::or_code, MOUSECODE_X_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_X, N_p("input-name", "Lightgun X 10"), input_seq(GUNCODE_X_INDEXED(9), input_seq::or_code, MOUSECODE_X_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_LIGHTGUN_Y \
CORE_INPUT_TYPES_BEGIN(lightgun_y) \
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_Y, N_p("input-name", "Lightgun Y"), input_seq(GUNCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0), input_seq::or_code, JOYCODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 2"), input_seq(GUNCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1), input_seq::or_code, JOYCODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 3"), input_seq(GUNCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2), input_seq::or_code, JOYCODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 4"), input_seq(GUNCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3), input_seq::or_code, JOYCODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 5"), input_seq(GUNCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4), input_seq::or_code, JOYCODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 6"), input_seq(GUNCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5), input_seq::or_code, JOYCODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 7"), input_seq(GUNCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6), input_seq::or_code, JOYCODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 8"), input_seq(GUNCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7), input_seq::or_code, JOYCODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 9"), input_seq(GUNCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8), input_seq::or_code, JOYCODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 10"), input_seq(GUNCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9), input_seq::or_code, JOYCODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, LIGHTGUN_Y, N_p("input-name", "Lightgun Y"), input_seq(GUNCODE_Y_INDEXED(0), input_seq::or_code, MOUSECODE_Y_INDEXED(0)), input_seq(KEYCODE_UP), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 2"), input_seq(GUNCODE_Y_INDEXED(1), input_seq::or_code, MOUSECODE_Y_INDEXED(1)), input_seq(KEYCODE_R), input_seq(KEYCODE_F) ) \
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 3"), input_seq(GUNCODE_Y_INDEXED(2), input_seq::or_code, MOUSECODE_Y_INDEXED(2)), input_seq(KEYCODE_I), input_seq(KEYCODE_K) ) \
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 4"), input_seq(GUNCODE_Y_INDEXED(3), input_seq::or_code, MOUSECODE_Y_INDEXED(3)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 5"), input_seq(GUNCODE_Y_INDEXED(4), input_seq::or_code, MOUSECODE_Y_INDEXED(4)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 6"), input_seq(GUNCODE_Y_INDEXED(5), input_seq::or_code, MOUSECODE_Y_INDEXED(5)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 7"), input_seq(GUNCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 8"), input_seq(GUNCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 9"), input_seq(GUNCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() ) \
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, LIGHTGUN_Y, N_p("input-name", "Lightgun Y 10"), input_seq(GUNCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() ) \
CORE_INPUT_TYPES_END()
#define CORE_INPUT_TYPES_MOUSE_X \
@@ -805,16 +871,36 @@ namespace {
#define CORE_INPUT_TYPES_UI \
CORE_INPUT_TYPES_BEGIN(ui) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY, N_p("input-name", "On Screen Display"), input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, N_p("input-name", "Break in Debugger"), input_seq(KEYCODE_TILDE, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CONFIGURE, N_p("input-name", "Config Menu"), input_seq(KEYCODE_TAB) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE, N_p("input-name", "Pause"), input_seq(KEYCODE_P, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, N_p("input-name", "Pause - Single Step"), input_seq(KEYCODE_P, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_P, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_REWIND_SINGLE, N_p("input-name", "Rewind - Single Step"), input_seq(KEYCODE_TILDE, KEYCODE_LSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_MENU, N_p("input-name", "Show/Hide Menu"), input_seq(KEYCODE_TAB) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT, input_seq::or_code, KEYCODE_ENTER_PAD) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_BACK, N_p("input-name", "UI Back"), input_seq(KEYCODE_ESC) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, N_p("input-name", "UI Cancel"), input_seq(KEYCODE_ESC) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CLEAR, N_p("input-name", "UI Clear"), input_seq(KEYCODE_DEL) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HELP, N_p("input-name", "UI Help"), input_seq(KEYCODE_F1) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_UP, N_p("input-name", "UI Up"), input_seq(KEYCODE_UP) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DOWN, N_p("input-name", "UI Down"), input_seq(KEYCODE_DOWN) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LEFT, N_p("input-name", "UI Left"), input_seq(KEYCODE_LEFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RIGHT, N_p("input-name", "UI Right"), input_seq(KEYCODE_RIGHT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HOME, N_p("input-name", "UI Home"), input_seq(KEYCODE_HOME) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_END, N_p("input-name", "UI End"), input_seq(KEYCODE_END) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_UP, N_p("input-name", "UI Page Up"), input_seq(KEYCODE_PGUP) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, N_p("input-name", "UI Page Down"), input_seq(KEYCODE_PGDN) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PREV_GROUP, N_p("input-name", "UI Previous Group"), input_seq(KEYCODE_OPENBRACE) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_NEXT_GROUP, N_p("input-name", "UI Next Group"), input_seq(KEYCODE_CLOSEBRACE) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ON_SCREEN_DISPLAY, N_p("input-name", "On Screen Display"), input_seq(KEYCODE_TILDE) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "Toggle UI Controls"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DEBUG_BREAK, N_p("input-name", "Break in Debugger"), input_seq(KEYCODE_TILDE) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE, N_p("input-name", "Pause"), input_seq(KEYCODE_F5, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAUSE_SINGLE, N_p("input-name", "Pause - Single Step"), input_seq(KEYCODE_F5, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F5, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_REWIND_SINGLE, N_p("input-name", "Rewind - Single Step"), input_seq(KEYCODE_F4, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F4, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F6, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE_QUICK, N_p("input-name", "Quick Save State"), input_seq(KEYCODE_F6, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F6, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE_QUICK, N_p("input-name", "Quick Load State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RESET_MACHINE, N_p("input-name", "Reset Machine"), input_seq(KEYCODE_F3, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F3, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SOFT_RESET, N_p("input-name", "Soft Reset"), input_seq(KEYCODE_F3, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_GFX, N_p("input-name", "Show Decoded Graphics"), input_seq(KEYCODE_F4) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_DEC, N_p("input-name", "Frameskip Dec"), input_seq(KEYCODE_F8) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_GFX, N_p("input-name", "Show Decoded Graphics"), input_seq(KEYCODE_F4, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_DEC, N_p("input-name", "Frameskip Dec"), input_seq(KEYCODE_F8, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FRAMESKIP_INC, N_p("input-name", "Frameskip Inc"), input_seq(KEYCODE_F9) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_THROTTLE, N_p("input-name", "Throttle"), input_seq(KEYCODE_F10) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAST_FORWARD, N_p("input-name", "Fast Forward"), input_seq(KEYCODE_INSERT) ) \
@@ -822,37 +908,21 @@ namespace {
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SNAPSHOT, N_p("input-name", "Save Snapshot"), input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_MNG, N_p("input-name", "Record MNG"), input_seq(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LCONTROL) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RECORD_AVI, N_p("input-name", "Record AVI"), input_seq(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_CHEAT, N_p("input-name", "Toggle Cheat"), input_seq(KEYCODE_F6) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_UP, N_p("input-name", "UI Up"), input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DOWN, N_p("input-name", "UI Down"), input_seq(KEYCODE_DOWN, input_seq::or_code, JOYCODE_Y_DOWN_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LEFT, N_p("input-name", "UI Left"), input_seq(KEYCODE_LEFT, input_seq::or_code, JOYCODE_X_LEFT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RIGHT, N_p("input-name", "UI Right"), input_seq(KEYCODE_RIGHT, input_seq::or_code, JOYCODE_X_RIGHT_SWITCH_INDEXED(0)) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_HOME, N_p("input-name", "UI Home"), input_seq(KEYCODE_HOME) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_END, N_p("input-name", "UI End"), input_seq(KEYCODE_END) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_UP, N_p("input-name", "UI Page Up"), input_seq(KEYCODE_PGUP) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PAGE_DOWN, N_p("input-name", "UI Page Down"), input_seq(KEYCODE_PGDN) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, N_p("input-name", "UI Focus Next"), input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, N_p("input-name", "UI Focus Previous"), input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SELECT, N_p("input-name", "UI Select"), input_seq(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT, input_seq::or_code, JOYCODE_BUTTON1_INDEXED(0), input_seq::or_code, KEYCODE_ENTER_PAD) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CANCEL, N_p("input-name", "UI Cancel"), input_seq(KEYCODE_ESC) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_CHEAT, N_p("input-name", "Toggle Cheat"), input_seq(KEYCODE_F8, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F8, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DISPLAY_COMMENT, N_p("input-name", "UI Display Comment"), input_seq(KEYCODE_SPACE) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_CLEAR, N_p("input-name", "UI Clear"), input_seq(KEYCODE_DEL) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_IN, N_p("input-name", "UI Zoom In"), input_seq(KEYCODE_EQUALS) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_OUT, N_p("input-name", "UI Zoom Out"), input_seq(KEYCODE_MINUS) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ZOOM_DEFAULT, N_p("input-name", "UI Default Zoom"), input_seq(KEYCODE_0) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PREV_GROUP, N_p("input-name", "UI Previous Group"), input_seq(KEYCODE_OPENBRACE) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_NEXT_GROUP, N_p("input-name", "UI Next Group"), input_seq(KEYCODE_CLOSEBRACE) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ROTATE, N_p("input-name", "UI Rotate"), input_seq(KEYCODE_R) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_PROFILER, N_p("input-name", "Show Profiler"), input_seq(KEYCODE_F11, KEYCODE_LSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "UI Toggle"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RELEASE_POINTER, N_p("input-name", "UI Release Pointer"), input_seq(KEYCODE_RCONTROL, KEYCODE_RALT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_SCRLOCK, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_START, N_p("input-name", "UI (First) Tape Start"), input_seq(KEYCODE_F2, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_STOP, N_p("input-name", "UI (First) Tape Stop"), input_seq(KEYCODE_F2, KEYCODE_LSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_NEXT, N_p("input-name", "UI Focus Next"), input_seq(KEYCODE_TAB, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FOCUS_PREV, N_p("input-name", "UI Focus Previous"), input_seq(KEYCODE_TAB, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_TAB, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DATS, N_p("input-name", "UI External DAT View"), input_seq(KEYCODE_LALT, KEYCODE_D) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAVORITES, N_p("input-name", "UI Add/Remove favorite"), input_seq(KEYCODE_LALT, KEYCODE_F) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAVORITES, N_p("input-name", "UI Add/Remove Favorite"), input_seq(KEYCODE_LALT, KEYCODE_F) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_EXPORT, N_p("input-name", "UI Export List"), input_seq(KEYCODE_LALT, KEYCODE_E) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_AUDIT, N_p("input-name", "UI Audit Media"), input_seq(KEYCODE_F1, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
CORE_INPUT_TYPES_END()
@@ -920,7 +990,9 @@ CORE_INPUT_TYPES_P2
CORE_INPUT_TYPES_P2_MAHJONG
CORE_INPUT_TYPES_P2_HANAFUDA
CORE_INPUT_TYPES_P3
+CORE_INPUT_TYPES_P3_MAHJONG
CORE_INPUT_TYPES_P4
+CORE_INPUT_TYPES_P4_MAHJONG
CORE_INPUT_TYPES_P5
CORE_INPUT_TYPES_P6
CORE_INPUT_TYPES_P7
@@ -978,7 +1050,9 @@ constexpr size_t core_input_types_count()
CORE_INPUT_TYPES_P2_MAHJONG
CORE_INPUT_TYPES_P2_HANAFUDA
CORE_INPUT_TYPES_P3
+ CORE_INPUT_TYPES_P3_MAHJONG
CORE_INPUT_TYPES_P4
+ CORE_INPUT_TYPES_P4_MAHJONG
CORE_INPUT_TYPES_P5
CORE_INPUT_TYPES_P6
CORE_INPUT_TYPES_P7
@@ -1034,7 +1108,9 @@ ATTR_COLD inline void emplace_core_types(std::vector<input_type_entry> &typelist
emplace_core_types_p2_mahjong(typelist);
emplace_core_types_p2_hanafuda(typelist);
emplace_core_types_p3(typelist);
+ emplace_core_types_p3_mahjong(typelist);
emplace_core_types_p4(typelist);
+ emplace_core_types_p4_mahjong(typelist);
emplace_core_types_p5(typelist);
emplace_core_types_p6(typelist);
emplace_core_types_p7(typelist);
diff --git a/src/emu/input.cpp b/src/emu/input.cpp
index 5c49d1c2dab..9e82f290bf7 100644
--- a/src/emu/input.cpp
+++ b/src/emu/input.cpp
@@ -24,20 +24,7 @@
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// additional expanded input codes for sequences
-constexpr input_code input_seq::end_code;
-constexpr input_code input_seq::default_code;
-constexpr input_code input_seq::not_code;
-constexpr input_code input_seq::or_code;
-
-// constant sequences
-const input_seq input_seq::empty_seq;
-
-
+namespace {
//**************************************************************************
// TYPE DEFINITIONS
@@ -64,8 +51,8 @@ struct code_string_table
return nullptr;
}
- u32 m_code;
- const char * m_string;
+ u32 m_code;
+ const char * m_string;
};
@@ -75,7 +62,7 @@ struct code_string_table
//**************************************************************************
// token strings for device classes
-static const code_string_table devclass_token_table[] =
+const code_string_table devclass_token_table[] =
{
{ DEVICE_CLASS_KEYBOARD, "KEYCODE" },
{ DEVICE_CLASS_MOUSE, "MOUSECODE" },
@@ -85,7 +72,7 @@ static const code_string_table devclass_token_table[] =
};
// friendly strings for device classes
-static const code_string_table devclass_string_table[] =
+const code_string_table devclass_string_table[] =
{
{ DEVICE_CLASS_KEYBOARD, "Kbd" },
{ DEVICE_CLASS_MOUSE, "Mouse" },
@@ -95,7 +82,7 @@ static const code_string_table devclass_string_table[] =
};
// token strings for item modifiers
-static const code_string_table modifier_token_table[] =
+const code_string_table modifier_token_table[] =
{
{ ITEM_MODIFIER_REVERSE, "REVERSE" },
{ ITEM_MODIFIER_POS, "POS" },
@@ -108,7 +95,7 @@ static const code_string_table modifier_token_table[] =
};
// friendly strings for item modifiers
-static const code_string_table modifier_string_table[] =
+const code_string_table modifier_string_table[] =
{
{ ITEM_MODIFIER_REVERSE, "Reverse" },
{ ITEM_MODIFIER_POS, "+" },
@@ -121,7 +108,7 @@ static const code_string_table modifier_string_table[] =
};
// token strings for item classes
-static const code_string_table itemclass_token_table[] =
+const code_string_table itemclass_token_table[] =
{
{ ITEM_CLASS_SWITCH, "SWITCH" },
{ ITEM_CLASS_ABSOLUTE, "ABSOLUTE" },
@@ -130,7 +117,7 @@ static const code_string_table itemclass_token_table[] =
};
// token strings for standard item ids
-static const code_string_table itemid_token_table[] =
+const code_string_table itemid_token_table[] =
{
// standard keyboard codes
{ ITEM_ID_A, "A" },
@@ -370,183 +357,44 @@ static const code_string_table itemid_token_table[] =
//**************************************************************************
-// INPUT SEQ
+// UTILITY FUNCTIONS
//**************************************************************************
-//-------------------------------------------------
-// operator+= - append a code to the end of an
-// input sequence
-//-------------------------------------------------
-
-input_seq &input_seq::operator+=(input_code code) noexcept
-{
- // if not enough room, return false
- const int curlength = length();
- if (curlength < m_code.size())
- {
- m_code[curlength] = code;
- if ((curlength + 1) < m_code.size())
- m_code[curlength + 1] = end_code;
- }
- return *this;
-}
-
-
-//-------------------------------------------------
-// operator|= - append a code to a sequence; if
-// the sequence is non-empty, insert an OR
-// before the new code
-//-------------------------------------------------
-
-input_seq &input_seq::operator|=(input_code code) noexcept
+inline void accumulate_axis_value(
+ s32 &result,
+ input_item_class &resultclass,
+ input_item_class &resultclasszero,
+ s32 value,
+ input_item_class valueclass,
+ input_item_class valueclasszero)
{
- // overwrite end/default with the new code
- if (m_code[0] == default_code)
+ if (!value)
{
- m_code[0] = code;
- m_code[1] = end_code;
+ // track the highest-priority zero
+ if ((ITEM_CLASS_ABSOLUTE == valueclasszero) || (ITEM_CLASS_INVALID == resultclasszero))
+ resultclasszero = valueclasszero;
}
- else
+ else if (ITEM_CLASS_ABSOLUTE == valueclass)
{
- // otherwise, append an OR token and then the new code
- const int curlength = length();
- if ((curlength + 1) < m_code.size())
- {
- m_code[curlength] = or_code;
- m_code[curlength + 1] = code;
- if ((curlength + 2) < m_code.size())
- m_code[curlength + 2] = end_code;
- }
+ // absolute values override relative values
+ if (ITEM_CLASS_ABSOLUTE == resultclass)
+ result += value;
+ else
+ result = value;
+ resultclass = ITEM_CLASS_ABSOLUTE;
}
- return *this;
-}
-
-
-//-------------------------------------------------
-// length - return the length of the sequence
-//-------------------------------------------------
-
-int input_seq::length() const noexcept
-{
- // find the end token; error if none found
- for (int seqnum = 0; seqnum < m_code.size(); seqnum++)
- if (m_code[seqnum] == end_code)
- return seqnum;
- return m_code.size();
-}
-
-
-//-------------------------------------------------
-// is_valid - return true if a given sequence is
-// valid
-//-------------------------------------------------
-
-bool input_seq::is_valid() const noexcept
-{
- // "default" can only be of length 1
- if (m_code[0] == default_code)
- return m_code[1] == end_code;
-
- // scan the sequence for valid codes
- input_item_class lastclass = ITEM_CLASS_INVALID;
- input_code lastcode = INPUT_CODE_INVALID;
- decltype(m_code) positive_codes;
- decltype(m_code) negative_codes;
- auto positive_codes_end = positive_codes.begin();
- auto negative_codes_end = negative_codes.begin();
- for (input_code code : m_code)
+ else if (ITEM_CLASS_RELATIVE == valueclass)
{
- // invalid codes are never permitted
- if (code == INPUT_CODE_INVALID)
- return false;
-
- // if we hit an OR or the end, validate the previous chunk
- if (code == or_code || code == end_code)
+ // relative values accumulate
+ if (resultclass != ITEM_CLASS_ABSOLUTE)
{
- // must be at least one positive code
- if (positive_codes.begin() == positive_codes_end)
- return false;
-
- // last code must not have been an internal code
- if (lastcode.internal())
- return false;
-
- // if this is the end, we're OK
- if (code == end_code)
- return true;
-
- // reset the state for the next chunk
- positive_codes_end = positive_codes.begin();
- negative_codes_end = negative_codes.begin();
- lastclass = ITEM_CLASS_INVALID;
- }
- else if (code == not_code)
- {
- // if we hit a NOT, make sure we don't have a double
- if (lastcode == not_code)
- return false;
- }
- else
- {
- // track positive codes, and don't allow positive and negative for the same code
- if (lastcode != not_code)
- {
- *positive_codes_end++ = code;
- if (std::find(negative_codes.begin(), negative_codes_end, code) != negative_codes_end)
- return false;
- }
- else
- {
- *negative_codes_end++ = code;
- if (std::find(positive_codes.begin(), positive_codes_end, code) != positive_codes_end)
- return false;
- }
-
- // non-switch items can't have a NOT
- input_item_class itemclass = code.item_class();
- if (itemclass != ITEM_CLASS_SWITCH && lastcode == not_code)
- return false;
-
- // absolute/relative items must all be the same class
- if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) ||
- (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE))
- return false;
+ result += value;
+ resultclass = ITEM_CLASS_RELATIVE;
}
-
- // remember the last code
- lastcode = code;
}
-
- // if we got here, we were missing an END token; fail
- return false;
-}
-
-
-//-------------------------------------------------
-// backspace - "backspace" over the last entry in
-// a sequence
-//-------------------------------------------------
-
-void input_seq::backspace() noexcept
-{
- // if we have at least one entry, remove it
- const int curlength = length();
- if (curlength > 0)
- m_code[curlength - 1] = end_code;
}
-
-//-------------------------------------------------
-// replace - replace all instances of oldcode
-// with newcode in a sequence
-//-------------------------------------------------
-
-void input_seq::replace(input_code oldcode, input_code newcode) noexcept
-{
- for (input_code &elem : m_code)
- if (elem == oldcode)
- elem = newcode;
-}
+} // anonymous namespace
@@ -589,48 +437,67 @@ input_manager::~input_manager()
//-------------------------------------------------
+// class_enabled - return whether input device
+// class is enabled
+//-------------------------------------------------
+
+bool input_manager::class_enabled(input_device_class devclass) const
+{
+ assert(devclass >= DEVICE_CLASS_FIRST_VALID && devclass <= DEVICE_CLASS_LAST_VALID);
+ return m_class[devclass]->enabled();
+}
+
+
+//-------------------------------------------------
+// add_device - add a representation of a host
+// input device
+//-------------------------------------------------
+
+osd::input_device &input_manager::add_device(input_device_class devclass, std::string_view name, std::string_view id, void *internal)
+{
+ return device_class(devclass).add_device(name, id, internal);
+}
+
+
+//-------------------------------------------------
// code_value - return the value of a given
// input code
//-------------------------------------------------
s32 input_manager::code_value(input_code code)
{
- g_profiler.start(PROFILER_INPUT);
- s32 result = 0;
-
- // dummy loop to allow clean early exits
- do
+ auto profile = g_profiler.start(PROFILER_INPUT);
+
+ // return 0 for any invalid devices
+ input_device *const device = device_from_code(code);
+ if (!device)
+ return 0;
+
+ // also return 0 if the device class is disabled
+ input_class &devclass = *m_class[code.device_class()];
+ if (!devclass.enabled())
+ return 0;
+
+ // if this is not a multi device, only return data for item 0 and iterate over all
+ int startindex = code.device_index();
+ int stopindex = startindex;
+ if (!devclass.multi())
{
- // return 0 for any invalid devices
- input_device *device = device_from_code(code);
- if (device == nullptr)
- break;
-
- // also return 0 if the device class is disabled
- input_class &devclass = *m_class[code.device_class()];
- if (!devclass.enabled())
- break;
-
- // if this is not a multi device, only return data for item 0 and iterate over all
- int startindex = code.device_index();
- int stopindex = startindex;
- if (!devclass.multi())
- {
- if (startindex != 0)
- break;
- stopindex = devclass.maxindex();
- }
+ if (startindex != 0)
+ return 0;
+ stopindex = devclass.maxindex();
+ }
- // iterate over all device indices
- input_item_class targetclass = code.item_class();
- for (int curindex = startindex; curindex <= stopindex; curindex++)
+ // iterate over all device indices
+ s32 result = 0;
+ input_item_class targetclass = code.item_class();
+ for (int curindex = startindex; curindex <= stopindex; curindex++)
+ {
+ // lookup the item for the appropriate index
+ code.set_device_index(curindex);
+ input_device_item *const item = item_from_code(code);
+ if (item)
{
- // lookup the item for the appropriate index
- code.set_device_index(curindex);
- input_device_item *item = item_from_code(code);
- if (item == nullptr)
- continue;
-
// process items according to their native type
switch (targetclass)
{
@@ -651,10 +518,8 @@ s32 input_manager::code_value(input_code code)
break;
}
}
- } while (0);
+ }
- // stop the profiler before exiting
- g_profiler.stop();
return result;
}
@@ -779,50 +644,45 @@ input_code input_manager::code_from_itemid(input_item_id itemid) const
std::string input_manager::code_name(input_code code) const
{
// if nothing there, return an empty string
- input_device_item *item = item_from_code(code);
- if (item == nullptr)
+ input_device_item const *const item = item_from_code(code);
+ if (!item)
return std::string();
- // determine the devclass part
- const char *devclass = (*devclass_string_table)[code.device_class()];
-
- // determine the devindex part
- std::string devindex = string_format("%d", code.device_index() + 1);
-
- // if we're unifying all devices, don't display a number
- if (!m_class[code.device_class()]->multi())
- devindex.clear();
+ std::string str;
// keyboard 0 doesn't show a class or index if it is the only one
- input_device_class device_class = item->device().devclass();
- if (device_class == DEVICE_CLASS_KEYBOARD && m_class[device_class]->maxindex() == 0)
+ input_device_class const device_class = item->device().devclass();
+ if ((device_class != DEVICE_CLASS_KEYBOARD) || (m_class[device_class]->maxindex() > 0))
{
- devclass = "";
- devindex.clear();
- }
+ // determine the devclass part
+ str = (*devclass_string_table)[code.device_class()];
- // devcode part comes from the item name
- std::string_view devcode = item->name();
-
- // determine the modifier part
- const char *modifier = (*modifier_string_table)[code.item_modifier()];
-
- // devcode is redundant with joystick switch left/right/up/down
- if (device_class == DEVICE_CLASS_JOYSTICK && code.item_class() == ITEM_CLASS_SWITCH)
- if (code.item_modifier() >= ITEM_MODIFIER_LEFT && code.item_modifier() <= ITEM_MODIFIER_DOWN)
- devcode = std::string_view();
+ // if we're unifying all devices, don't display a number
+ if (m_class[code.device_class()]->multi())
+ str.append(util::string_format(" %d ", code.device_index() + 1));
+ else
+ str.append(" ");
+ }
- // concatenate the strings
- std::string str(devclass);
- if (!devindex.empty())
- str.append(" ").append(devindex);
- if (!devcode.empty())
- str.append(" ").append(devcode);
- if (modifier != nullptr)
- str.append(" ").append(modifier);
+ // append item name - redundant with joystick switch left/right/up/down
+ bool const joydir =
+ (device_class == DEVICE_CLASS_JOYSTICK) &&
+ (code.item_class() == ITEM_CLASS_SWITCH) &&
+ (code.item_modifier() >= ITEM_MODIFIER_LEFT) &&
+ (code.item_modifier() <= ITEM_MODIFIER_DOWN);
+ if (joydir)
+ {
+ str.append((*modifier_string_table)[code.item_modifier()]);
+ }
+ else
+ {
+ str.append(item->name());
+ char const *const modifier = (*modifier_string_table)[code.item_modifier()];
+ if (modifier && *modifier)
+ str.append(" ").append(modifier);
+ }
- // delete any leading spaces
- return std::string(strtrimspace(str));
+ return str;
}
@@ -860,7 +720,7 @@ std::string input_manager::code_to_token(input_code code) const
std::string str(devclass);
if (!devindex.empty())
str.append("_").append(devindex);
- if (devcode[0] != 0)
+ if (!devcode.empty())
str.append("_").append(devcode);
if (modifier != nullptr)
str.append("_").append(modifier);
@@ -1046,91 +906,83 @@ bool input_manager::seq_pressed(const input_seq &seq)
s32 input_manager::seq_axis_value(const input_seq &seq, input_item_class &itemclass)
{
- // start with no valid classes
- input_item_class itemclasszero = ITEM_CLASS_INVALID;
+ // start with zero result and no valid classes
+ s32 result = 0;
itemclass = ITEM_CLASS_INVALID;
+ input_item_class itemclasszero = ITEM_CLASS_INVALID;
// iterate over all of the codes
- s32 result = 0;
+ s32 groupval = 0;
+ input_item_class groupclass = ITEM_CLASS_INVALID;
+ input_item_class groupclasszero = ITEM_CLASS_INVALID;
bool invert = false;
bool enable = true;
for (int codenum = 0; ; codenum++)
{
- input_code code = seq[codenum];
+ input_code const code = seq[codenum];
if (code == input_seq::not_code)
{
- // handle NOT
+ // handle NOT - invert the next code
invert = true;
}
else if (code == input_seq::end_code)
{
- // handle END
+ // handle END - commit group and break out of loop
+ accumulate_axis_value(
+ result, itemclass, itemclasszero,
+ groupval, groupclass, groupclasszero);
break;
}
else if (code == input_seq::or_code)
{
- // handle OR
-
- // reset invert and enable for the next group
+ // handle OR - commit group and reset for the next group
+ accumulate_axis_value(
+ result, itemclass, itemclasszero,
+ groupval, groupclass, groupclasszero);
+ groupval = 0;
+ groupclasszero = ITEM_CLASS_INVALID;
+ groupclass = ITEM_CLASS_INVALID;
invert = false;
enable = true;
}
else if (enable)
{
// handle everything else only if we're still enabled
+ input_item_class const codeclass = code.item_class();
// switch codes serve as enables
- if (code.item_class() == ITEM_CLASS_SWITCH)
+ if (ITEM_CLASS_SWITCH == codeclass)
{
// AND against previous digital codes
if (enable)
+ {
enable = code_pressed(code) ^ invert;
- // FIXME: need to clear current group value if enable became false
- // you can't create a sequence where this matters using the internal UI,
- // but you can by editing a CFG file (or controller config file)
+ if (!enable)
+ {
+ // clear current group if enable became false - only way out is an OR code
+ groupval = 0;
+ groupclasszero = ITEM_CLASS_INVALID;
+ groupclass = ITEM_CLASS_INVALID;
+ }
+ }
}
else
{
// non-switch codes are analog values
- s32 value = code_value(code);
-
- // if we got a 0 value, don't do anything except remember the first type
- if (value == 0)
- {
- if (itemclasszero == ITEM_CLASS_INVALID)
- itemclasszero = code.item_class();
- }
- else if (code.item_class() == ITEM_CLASS_ABSOLUTE)
- {
- // non-zero absolute values override relative values
- if (itemclass == ITEM_CLASS_ABSOLUTE)
- result += value;
- else
- result = value;
- itemclass = ITEM_CLASS_ABSOLUTE;
- }
- else if (code.item_class() == ITEM_CLASS_RELATIVE)
- {
- // non-zero relative values accumulate in the absence of absolute values
- if (itemclass != ITEM_CLASS_ABSOLUTE)
- {
- result += value;
- itemclass = ITEM_CLASS_RELATIVE;
- }
- }
+ accumulate_axis_value(
+ groupval, groupclass, groupclasszero,
+ code_value(code), codeclass, codeclass);
}
- // clear the invert flag
+ // clear the invert flag - it only applies to one item
invert = false;
}
}
- // saturate mixed absolute values
- if (itemclass == ITEM_CLASS_ABSOLUTE)
- result = std::clamp(result, INPUT_ABSOLUTE_MIN, INPUT_ABSOLUTE_MAX);
-
- // if the caller wants to know the type, provide it
- if (result == 0)
+ // saturate mixed absolute values, report neutral type
+ if (ITEM_CLASS_ABSOLUTE == itemclass)
+ result = std::clamp(result, osd::input_device::ABSOLUTE_MIN, osd::input_device::ABSOLUTE_MAX);
+ else if (ITEM_CLASS_INVALID == itemclass)
itemclass = itemclasszero;
return result;
}
@@ -1150,7 +1002,7 @@ input_seq input_manager::seq_clean(const input_seq &seq) const
{
// if this is a code item which is not valid, don't copy it and remove any preceding ORs/NOTs
input_code code = seq[codenum];
- if (!code.internal() && code_name(code).empty())
+ if (!code.internal() && (((code.device_index() > 0) && !m_class[code.device_class()]->multi()) || !item_from_code(code)))
{
while (clean_index > 0 && clean_codes[clean_index - 1].internal())
{
@@ -1379,7 +1231,7 @@ bool input_manager::map_device_to_controller(const devicemap_table &table)
{
// remap devindex
input_devclass->remap_device_index(device->devindex(), devindex);
- osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex, device->name(), device->id());
+ osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex + 1, device->name(), device->id());
break;
}
diff --git a/src/emu/input.h b/src/emu/input.h
index 7bc03c13831..7c00a590a8d 100644
--- a/src/emu/input.h
+++ b/src/emu/input.h
@@ -17,6 +17,10 @@
#ifndef MAME_EMU_INPUT_H
#define MAME_EMU_INPUT_H
+#include "interface/inputcode.h"
+#include "interface/inputman.h"
+#include "interface/inputseq.h"
+
#include <algorithm>
#include <array>
#include <cassert>
@@ -28,467 +32,16 @@
//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// maximum number of axis/buttons/hats with ITEM_IDs for use by osd layer
-constexpr int INPUT_MAX_AXIS = 8;
-constexpr int INPUT_MAX_BUTTONS = 32;
-constexpr int INPUT_MAX_HATS = 4;
-constexpr int INPUT_MAX_ADD_SWITCH = 16;
-constexpr int INPUT_MAX_ADD_ABSOLUTE = 16;
-constexpr int INPUT_MAX_ADD_RELATIVE = 16;
-
-
-// device classes
-enum input_device_class
-{
- DEVICE_CLASS_INVALID,
- DEVICE_CLASS_FIRST_VALID,
- DEVICE_CLASS_KEYBOARD = DEVICE_CLASS_FIRST_VALID,
- DEVICE_CLASS_MOUSE,
- DEVICE_CLASS_LIGHTGUN,
- DEVICE_CLASS_JOYSTICK,
- DEVICE_CLASS_LAST_VALID = DEVICE_CLASS_JOYSTICK,
- DEVICE_CLASS_INTERNAL,
- DEVICE_CLASS_MAXIMUM
-};
-DECLARE_ENUM_INCDEC_OPERATORS(input_device_class)
-
-
-// device index
-constexpr int DEVICE_INDEX_MAXIMUM = 0xff;
-
-
-// input item classes
-enum input_item_class
-{
- ITEM_CLASS_INVALID,
- ITEM_CLASS_SWITCH,
- ITEM_CLASS_ABSOLUTE,
- ITEM_CLASS_RELATIVE,
- ITEM_CLASS_MAXIMUM
-};
-
-
-// input item modifiers
-enum input_item_modifier
-{
- ITEM_MODIFIER_NONE,
- ITEM_MODIFIER_REVERSE,
- ITEM_MODIFIER_POS,
- ITEM_MODIFIER_NEG,
- ITEM_MODIFIER_LEFT,
- ITEM_MODIFIER_RIGHT,
- ITEM_MODIFIER_UP,
- ITEM_MODIFIER_DOWN,
- ITEM_MODIFIER_MAXIMUM
-};
-
-
-// standard item IDs
-enum input_item_id
-{
- ITEM_ID_INVALID,
- ITEM_ID_FIRST_VALID,
-
- // standard keyboard IDs
- ITEM_ID_A = ITEM_ID_FIRST_VALID,
- ITEM_ID_B,
- ITEM_ID_C,
- ITEM_ID_D,
- ITEM_ID_E,
- ITEM_ID_F,
- ITEM_ID_G,
- ITEM_ID_H,
- ITEM_ID_I,
- ITEM_ID_J,
- ITEM_ID_K,
- ITEM_ID_L,
- ITEM_ID_M,
- ITEM_ID_N,
- ITEM_ID_O,
- ITEM_ID_P,
- ITEM_ID_Q,
- ITEM_ID_R,
- ITEM_ID_S,
- ITEM_ID_T,
- ITEM_ID_U,
- ITEM_ID_V,
- ITEM_ID_W,
- ITEM_ID_X,
- ITEM_ID_Y,
- ITEM_ID_Z,
- ITEM_ID_0,
- ITEM_ID_1,
- ITEM_ID_2,
- ITEM_ID_3,
- ITEM_ID_4,
- ITEM_ID_5,
- ITEM_ID_6,
- ITEM_ID_7,
- ITEM_ID_8,
- ITEM_ID_9,
- ITEM_ID_F1,
- ITEM_ID_F2,
- ITEM_ID_F3,
- ITEM_ID_F4,
- ITEM_ID_F5,
- ITEM_ID_F6,
- ITEM_ID_F7,
- ITEM_ID_F8,
- ITEM_ID_F9,
- ITEM_ID_F10,
- ITEM_ID_F11,
- ITEM_ID_F12,
- ITEM_ID_F13,
- ITEM_ID_F14,
- ITEM_ID_F15,
- ITEM_ID_F16,
- ITEM_ID_F17,
- ITEM_ID_F18,
- ITEM_ID_F19,
- ITEM_ID_F20,
- ITEM_ID_ESC,
- ITEM_ID_TILDE,
- ITEM_ID_MINUS,
- ITEM_ID_EQUALS,
- ITEM_ID_BACKSPACE,
- ITEM_ID_TAB,
- ITEM_ID_OPENBRACE,
- ITEM_ID_CLOSEBRACE,
- ITEM_ID_ENTER,
- ITEM_ID_COLON,
- ITEM_ID_QUOTE,
- ITEM_ID_BACKSLASH,
- ITEM_ID_BACKSLASH2,
- ITEM_ID_COMMA,
- ITEM_ID_STOP,
- ITEM_ID_SLASH,
- ITEM_ID_SPACE,
- ITEM_ID_INSERT,
- ITEM_ID_DEL,
- ITEM_ID_HOME,
- ITEM_ID_END,
- ITEM_ID_PGUP,
- ITEM_ID_PGDN,
- ITEM_ID_LEFT,
- ITEM_ID_RIGHT,
- ITEM_ID_UP,
- ITEM_ID_DOWN,
- ITEM_ID_0_PAD,
- ITEM_ID_1_PAD,
- ITEM_ID_2_PAD,
- ITEM_ID_3_PAD,
- ITEM_ID_4_PAD,
- ITEM_ID_5_PAD,
- ITEM_ID_6_PAD,
- ITEM_ID_7_PAD,
- ITEM_ID_8_PAD,
- ITEM_ID_9_PAD,
- ITEM_ID_SLASH_PAD,
- ITEM_ID_ASTERISK,
- ITEM_ID_MINUS_PAD,
- ITEM_ID_PLUS_PAD,
- ITEM_ID_DEL_PAD,
- ITEM_ID_ENTER_PAD,
- ITEM_ID_BS_PAD,
- ITEM_ID_TAB_PAD,
- ITEM_ID_00_PAD,
- ITEM_ID_000_PAD,
- ITEM_ID_COMMA_PAD,
- ITEM_ID_EQUALS_PAD,
- ITEM_ID_PRTSCR,
- ITEM_ID_PAUSE,
- ITEM_ID_LSHIFT,
- ITEM_ID_RSHIFT,
- ITEM_ID_LCONTROL,
- ITEM_ID_RCONTROL,
- ITEM_ID_LALT,
- ITEM_ID_RALT,
- ITEM_ID_SCRLOCK,
- ITEM_ID_NUMLOCK,
- ITEM_ID_CAPSLOCK,
- ITEM_ID_LWIN,
- ITEM_ID_RWIN,
- ITEM_ID_MENU,
- ITEM_ID_CANCEL,
-
- // standard mouse/joystick/gun IDs
- ITEM_ID_XAXIS,
- ITEM_ID_YAXIS,
- ITEM_ID_ZAXIS,
- ITEM_ID_RXAXIS,
- ITEM_ID_RYAXIS,
- ITEM_ID_RZAXIS,
- ITEM_ID_SLIDER1,
- ITEM_ID_SLIDER2,
- ITEM_ID_BUTTON1,
- ITEM_ID_BUTTON2,
- ITEM_ID_BUTTON3,
- ITEM_ID_BUTTON4,
- ITEM_ID_BUTTON5,
- ITEM_ID_BUTTON6,
- ITEM_ID_BUTTON7,
- ITEM_ID_BUTTON8,
- ITEM_ID_BUTTON9,
- ITEM_ID_BUTTON10,
- ITEM_ID_BUTTON11,
- ITEM_ID_BUTTON12,
- ITEM_ID_BUTTON13,
- ITEM_ID_BUTTON14,
- ITEM_ID_BUTTON15,
- ITEM_ID_BUTTON16,
- ITEM_ID_BUTTON17,
- ITEM_ID_BUTTON18,
- ITEM_ID_BUTTON19,
- ITEM_ID_BUTTON20,
- ITEM_ID_BUTTON21,
- ITEM_ID_BUTTON22,
- ITEM_ID_BUTTON23,
- ITEM_ID_BUTTON24,
- ITEM_ID_BUTTON25,
- ITEM_ID_BUTTON26,
- ITEM_ID_BUTTON27,
- ITEM_ID_BUTTON28,
- ITEM_ID_BUTTON29,
- ITEM_ID_BUTTON30,
- ITEM_ID_BUTTON31,
- ITEM_ID_BUTTON32,
- ITEM_ID_START,
- ITEM_ID_SELECT,
-
- // Hats
- ITEM_ID_HAT1UP,
- ITEM_ID_HAT1DOWN,
- ITEM_ID_HAT1LEFT,
- ITEM_ID_HAT1RIGHT,
- ITEM_ID_HAT2UP,
- ITEM_ID_HAT2DOWN,
- ITEM_ID_HAT2LEFT,
- ITEM_ID_HAT2RIGHT,
- ITEM_ID_HAT3UP,
- ITEM_ID_HAT3DOWN,
- ITEM_ID_HAT3LEFT,
- ITEM_ID_HAT3RIGHT,
- ITEM_ID_HAT4UP,
- ITEM_ID_HAT4DOWN,
- ITEM_ID_HAT4LEFT,
- ITEM_ID_HAT4RIGHT,
-
- // Additional IDs
- ITEM_ID_ADD_SWITCH1,
- ITEM_ID_ADD_SWITCH2,
- ITEM_ID_ADD_SWITCH3,
- ITEM_ID_ADD_SWITCH4,
- ITEM_ID_ADD_SWITCH5,
- ITEM_ID_ADD_SWITCH6,
- ITEM_ID_ADD_SWITCH7,
- ITEM_ID_ADD_SWITCH8,
- ITEM_ID_ADD_SWITCH9,
- ITEM_ID_ADD_SWITCH10,
- ITEM_ID_ADD_SWITCH11,
- ITEM_ID_ADD_SWITCH12,
- ITEM_ID_ADD_SWITCH13,
- ITEM_ID_ADD_SWITCH14,
- ITEM_ID_ADD_SWITCH15,
- ITEM_ID_ADD_SWITCH16,
-
- ITEM_ID_ADD_ABSOLUTE1,
- ITEM_ID_ADD_ABSOLUTE2,
- ITEM_ID_ADD_ABSOLUTE3,
- ITEM_ID_ADD_ABSOLUTE4,
- ITEM_ID_ADD_ABSOLUTE5,
- ITEM_ID_ADD_ABSOLUTE6,
- ITEM_ID_ADD_ABSOLUTE7,
- ITEM_ID_ADD_ABSOLUTE8,
- ITEM_ID_ADD_ABSOLUTE9,
- ITEM_ID_ADD_ABSOLUTE10,
- ITEM_ID_ADD_ABSOLUTE11,
- ITEM_ID_ADD_ABSOLUTE12,
- ITEM_ID_ADD_ABSOLUTE13,
- ITEM_ID_ADD_ABSOLUTE14,
- ITEM_ID_ADD_ABSOLUTE15,
- ITEM_ID_ADD_ABSOLUTE16,
-
- ITEM_ID_ADD_RELATIVE1,
- ITEM_ID_ADD_RELATIVE2,
- ITEM_ID_ADD_RELATIVE3,
- ITEM_ID_ADD_RELATIVE4,
- ITEM_ID_ADD_RELATIVE5,
- ITEM_ID_ADD_RELATIVE6,
- ITEM_ID_ADD_RELATIVE7,
- ITEM_ID_ADD_RELATIVE8,
- ITEM_ID_ADD_RELATIVE9,
- ITEM_ID_ADD_RELATIVE10,
- ITEM_ID_ADD_RELATIVE11,
- ITEM_ID_ADD_RELATIVE12,
- ITEM_ID_ADD_RELATIVE13,
- ITEM_ID_ADD_RELATIVE14,
- ITEM_ID_ADD_RELATIVE15,
- ITEM_ID_ADD_RELATIVE16,
-
- // generic other IDs
- ITEM_ID_OTHER_SWITCH,
- ITEM_ID_OTHER_AXIS_ABSOLUTE,
- ITEM_ID_OTHER_AXIS_RELATIVE,
- ITEM_ID_MAXIMUM,
-
- // internal codes for sequences
- ITEM_ID_SEQ_END,
- ITEM_ID_SEQ_DEFAULT,
- ITEM_ID_SEQ_NOT,
- ITEM_ID_SEQ_OR,
-
- // absolute maximum ID
- ITEM_ID_ABSOLUTE_MAXIMUM = 0xfff
-};
-DECLARE_ENUM_INCDEC_OPERATORS(input_item_id)
-
-
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// ======================> input_code
-
-// a combined code that describes a particular input on a particular device
-class input_code
-{
-public:
- // construction/destruction
- constexpr input_code(
- input_device_class devclass = DEVICE_CLASS_INVALID,
- int devindex = 0,
- input_item_class itemclass = ITEM_CLASS_INVALID,
- input_item_modifier modifier = ITEM_MODIFIER_NONE,
- input_item_id itemid = ITEM_ID_INVALID) noexcept
- : m_internal(((devclass & 0xf) << 28) | ((devindex & 0xff) << 20) | ((itemclass & 0xf) << 16) | ((modifier & 0xf) << 12) | (itemid & 0xfff))
- {
- assert(devclass >= 0 && devclass < DEVICE_CLASS_MAXIMUM);
- assert(devindex >= 0 && devindex < DEVICE_INDEX_MAXIMUM);
- assert(itemclass >= 0 && itemclass < ITEM_CLASS_MAXIMUM);
- assert(modifier >= 0 && modifier < ITEM_MODIFIER_MAXIMUM);
- assert(itemid >= 0 && itemid < ITEM_ID_ABSOLUTE_MAXIMUM);
- }
- constexpr input_code(const input_code &src) noexcept = default;
-
- // operators
- constexpr bool operator==(const input_code &rhs) const noexcept { return m_internal == rhs.m_internal; }
- constexpr bool operator!=(const input_code &rhs) const noexcept { return m_internal != rhs.m_internal; }
- constexpr bool operator<(const input_code &rhs) const noexcept { return m_internal < rhs.m_internal; }
-
- // getters
- constexpr bool internal() const noexcept { return device_class() == DEVICE_CLASS_INTERNAL; }
- constexpr input_device_class device_class() const noexcept { return input_device_class((m_internal >> 28) & 0xf); }
- constexpr int device_index() const noexcept { return ((m_internal >> 20) & 0xff); }
- constexpr input_item_class item_class() const noexcept { return input_item_class((m_internal >> 16) & 0xf); }
- constexpr input_item_modifier item_modifier() const noexcept { return input_item_modifier((m_internal >> 12) & 0xf); }
- constexpr input_item_id item_id() const noexcept { return input_item_id(m_internal & 0xfff); }
-
- // setters
- void set_device_class(input_device_class devclass) noexcept
- {
- assert(devclass >= 0 && devclass <= 0xf);
- m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28);
- }
- void set_device_index(int devindex) noexcept
- {
- assert(devindex >= 0 && devindex <= 0xff);
- m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20);
- }
- void set_item_class(input_item_class itemclass) noexcept
- {
- assert(itemclass >= 0 && itemclass <= 0xf);
- m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16);
- }
- void set_item_modifier(input_item_modifier modifier) noexcept
- {
- assert(modifier >= 0 && modifier <= 0xf);
- m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12);
- }
- void set_item_id(input_item_id itemid) noexcept
- {
- assert(itemid >= 0 && itemid <= 0xfff);
- m_internal = (m_internal & ~0xfff) | (itemid & 0xfff);
- }
-
-private:
- u32 m_internal;
-};
-
-
-// ======================> input_seq
-
-// a sequence of input_codes, supporting AND/OR and inversion
-class input_seq
-{
-public:
- // construction/destruction
- input_seq() noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value>()) { }
- template <typename... T> input_seq(input_code code_0, T... code_n) noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value - sizeof...(T) - 1>(), code_0, code_n...) { }
- constexpr input_seq(const input_seq &rhs) noexcept = default;
-
- // operators
- bool operator==(const input_seq &rhs) const noexcept { return m_code == rhs.m_code; }
- bool operator!=(const input_seq &rhs) const noexcept { return m_code != rhs.m_code; }
- constexpr input_code operator[](int index) const noexcept { return (index >= 0 && index < m_code.size()) ? m_code[index] : end_code; }
- input_seq &operator+=(input_code code) noexcept;
- input_seq &operator|=(input_code code) noexcept;
-
- // getters
- constexpr bool empty() const noexcept { return m_code[0] == end_code; }
- constexpr int max_size() const noexcept { return std::tuple_size<decltype(m_code)>::value; }
- int length() const noexcept;
- bool is_valid() const noexcept;
- constexpr bool is_default() const noexcept { return m_code[0] == default_code; }
-
- // setters
- template <typename... T> void set(input_code code_0, T... code_n) noexcept
- {
- static_assert(sizeof...(T) < std::tuple_size<decltype(m_code)>::value, "too many codes for input_seq");
- set<0>(code_0, code_n...);
- }
- void reset() noexcept { set(end_code); }
- void set_default() noexcept { set(default_code); }
- void backspace() noexcept;
- void replace(input_code oldcode, input_code newcode) noexcept;
-
- // constant codes used in sequences
- static constexpr input_code end_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END };
- static constexpr input_code default_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT };
- static constexpr input_code not_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT };
- static constexpr input_code or_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR };
-
- // constant sequences
- static const input_seq empty_seq;
-
-private:
- static constexpr input_code get_end_code(size_t) noexcept { return end_code; }
-
- template <size_t... N, typename... T> input_seq(std::integer_sequence<size_t, N...>, T... code) noexcept : m_code({ code..., get_end_code(N)... }) { }
- template <size_t... N> input_seq(std::integer_sequence<size_t, N...>) noexcept : m_code({ get_end_code(N)... }) { }
-
- template <unsigned N> void set() noexcept
- {
- std::fill(std::next(m_code.begin(), N), m_code.end(), end_code);
- }
- template <unsigned N, typename... T> void set(input_code code_0, T... code_n) noexcept
- {
- m_code[N] = code_0;
- set<N + 1>(code_n...);
- }
-
- // internal state
- std::array<input_code, 16> m_code;
-};
+using osd::input_seq; // too much trouble to qualify this everywhere
// ======================> input_manager
// global machine-level information about devices
-class input_manager
+class input_manager : public osd::input_manager
{
public:
// controller alias table typedef
@@ -498,6 +51,10 @@ public:
input_manager(running_machine &machine);
~input_manager();
+ // OSD interface
+ virtual bool class_enabled(input_device_class devclass) const override;
+ virtual osd::input_device &add_device(input_device_class devclass, std::string_view name, std::string_view id, void *internal) override;
+
// getters
running_machine &machine() const { return m_machine; }
input_class &device_class(input_device_class devclass) { assert(devclass >= DEVICE_CLASS_FIRST_VALID && devclass <= DEVICE_CLASS_LAST_VALID); return *m_class[devclass]; }
@@ -542,466 +99,4 @@ private:
};
-
-//**************************************************************************
-// MACROS
-//**************************************************************************
-
-// invalid codes
-#define INPUT_CODE_INVALID input_code()
-
-// keyboard codes
-#define KEYCODE_A_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_A)
-#define KEYCODE_B_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_B)
-#define KEYCODE_C_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_C)
-#define KEYCODE_D_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_D)
-#define KEYCODE_E_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_E)
-#define KEYCODE_F_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F)
-#define KEYCODE_G_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_G)
-#define KEYCODE_H_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_H)
-#define KEYCODE_I_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_I)
-#define KEYCODE_J_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_J)
-#define KEYCODE_K_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_K)
-#define KEYCODE_L_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_L)
-#define KEYCODE_M_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_M)
-#define KEYCODE_N_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_N)
-#define KEYCODE_O_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_O)
-#define KEYCODE_P_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_P)
-#define KEYCODE_Q_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Q)
-#define KEYCODE_R_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_R)
-#define KEYCODE_S_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_S)
-#define KEYCODE_T_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_T)
-#define KEYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_U)
-#define KEYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_V)
-#define KEYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_W)
-#define KEYCODE_X_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_X)
-#define KEYCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Y)
-#define KEYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Z)
-#define KEYCODE_0_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0)
-#define KEYCODE_1_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1)
-#define KEYCODE_2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2)
-#define KEYCODE_3_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3)
-#define KEYCODE_4_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4)
-#define KEYCODE_5_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5)
-#define KEYCODE_6_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6)
-#define KEYCODE_7_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7)
-#define KEYCODE_8_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8)
-#define KEYCODE_9_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9)
-#define KEYCODE_F1_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F1)
-#define KEYCODE_F2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F2)
-#define KEYCODE_F3_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F3)
-#define KEYCODE_F4_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F4)
-#define KEYCODE_F5_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F5)
-#define KEYCODE_F6_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F6)
-#define KEYCODE_F7_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F7)
-#define KEYCODE_F8_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F8)
-#define KEYCODE_F9_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F9)
-#define KEYCODE_F10_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F10)
-#define KEYCODE_F11_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F11)
-#define KEYCODE_F12_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F12)
-#define KEYCODE_F13_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F13)
-#define KEYCODE_F14_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F14)
-#define KEYCODE_F15_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F15)
-#define KEYCODE_F16_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F16)
-#define KEYCODE_F17_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F17)
-#define KEYCODE_F18_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F18)
-#define KEYCODE_F19_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F19)
-#define KEYCODE_F20_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F20)
-#define KEYCODE_ESC_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ESC)
-#define KEYCODE_TILDE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TILDE)
-#define KEYCODE_MINUS_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS)
-#define KEYCODE_EQUALS_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS)
-#define KEYCODE_BACKSPACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSPACE)
-#define KEYCODE_TAB_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB)
-#define KEYCODE_OPENBRACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_OPENBRACE)
-#define KEYCODE_CLOSEBRACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CLOSEBRACE)
-#define KEYCODE_ENTER_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER)
-#define KEYCODE_COLON_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COLON)
-#define KEYCODE_QUOTE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_QUOTE)
-#define KEYCODE_BACKSLASH_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH)
-#define KEYCODE_BACKSLASH2_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH2)
-#define KEYCODE_COMMA_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA)
-#define KEYCODE_STOP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_STOP)
-#define KEYCODE_SLASH_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH)
-#define KEYCODE_SPACE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SPACE)
-#define KEYCODE_INSERT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_INSERT)
-#define KEYCODE_DEL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL)
-#define KEYCODE_HOME_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HOME)
-#define KEYCODE_END_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_END)
-#define KEYCODE_PGUP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGUP)
-#define KEYCODE_PGDN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGDN)
-#define KEYCODE_LEFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LEFT)
-#define KEYCODE_RIGHT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RIGHT)
-#define KEYCODE_UP_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_UP)
-#define KEYCODE_DOWN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DOWN)
-#define KEYCODE_0_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0_PAD)
-#define KEYCODE_1_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1_PAD)
-#define KEYCODE_2_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2_PAD)
-#define KEYCODE_3_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3_PAD)
-#define KEYCODE_4_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4_PAD)
-#define KEYCODE_5_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5_PAD)
-#define KEYCODE_6_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6_PAD)
-#define KEYCODE_7_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7_PAD)
-#define KEYCODE_8_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8_PAD)
-#define KEYCODE_9_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9_PAD)
-#define KEYCODE_SLASH_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH_PAD)
-#define KEYCODE_ASTERISK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ASTERISK)
-#define KEYCODE_MINUS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS_PAD)
-#define KEYCODE_PLUS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PLUS_PAD)
-#define KEYCODE_DEL_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL_PAD)
-#define KEYCODE_ENTER_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER_PAD)
-#define KEYCODE_BS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BS_PAD)
-#define KEYCODE_TAB_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB_PAD)
-#define KEYCODE_00_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_00_PAD)
-#define KEYCODE_000_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_000_PAD)
-#define KEYCODE_COMMA_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA_PAD)
-#define KEYCODE_EQUALS_PAD_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS_PAD)
-#define KEYCODE_PRTSCR_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PRTSCR)
-#define KEYCODE_PAUSE_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PAUSE)
-#define KEYCODE_LSHIFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LSHIFT)
-#define KEYCODE_RSHIFT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RSHIFT)
-#define KEYCODE_LCONTROL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LCONTROL)
-#define KEYCODE_RCONTROL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RCONTROL)
-#define KEYCODE_LALT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LALT)
-#define KEYCODE_RALT_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RALT)
-#define KEYCODE_SCRLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SCRLOCK)
-#define KEYCODE_NUMLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_NUMLOCK)
-#define KEYCODE_CAPSLOCK_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CAPSLOCK)
-#define KEYCODE_LWIN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LWIN)
-#define KEYCODE_RWIN_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RWIN)
-#define KEYCODE_MENU_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MENU)
-#define KEYCODE_CANCEL_INDEXED(n) input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CANCEL)
-
-#define KEYCODE_A KEYCODE_A_INDEXED(0)
-#define KEYCODE_B KEYCODE_B_INDEXED(0)
-#define KEYCODE_C KEYCODE_C_INDEXED(0)
-#define KEYCODE_D KEYCODE_D_INDEXED(0)
-#define KEYCODE_E KEYCODE_E_INDEXED(0)
-#define KEYCODE_F KEYCODE_F_INDEXED(0)
-#define KEYCODE_G KEYCODE_G_INDEXED(0)
-#define KEYCODE_H KEYCODE_H_INDEXED(0)
-#define KEYCODE_I KEYCODE_I_INDEXED(0)
-#define KEYCODE_J KEYCODE_J_INDEXED(0)
-#define KEYCODE_K KEYCODE_K_INDEXED(0)
-#define KEYCODE_L KEYCODE_L_INDEXED(0)
-#define KEYCODE_M KEYCODE_M_INDEXED(0)
-#define KEYCODE_N KEYCODE_N_INDEXED(0)
-#define KEYCODE_O KEYCODE_O_INDEXED(0)
-#define KEYCODE_P KEYCODE_P_INDEXED(0)
-#define KEYCODE_Q KEYCODE_Q_INDEXED(0)
-#define KEYCODE_R KEYCODE_R_INDEXED(0)
-#define KEYCODE_S KEYCODE_S_INDEXED(0)
-#define KEYCODE_T KEYCODE_T_INDEXED(0)
-#define KEYCODE_U KEYCODE_U_INDEXED(0)
-#define KEYCODE_V KEYCODE_V_INDEXED(0)
-#define KEYCODE_W KEYCODE_W_INDEXED(0)
-#define KEYCODE_X KEYCODE_X_INDEXED(0)
-#define KEYCODE_Y KEYCODE_Y_INDEXED(0)
-#define KEYCODE_Z KEYCODE_Z_INDEXED(0)
-#define KEYCODE_0 KEYCODE_0_INDEXED(0)
-#define KEYCODE_1 KEYCODE_1_INDEXED(0)
-#define KEYCODE_2 KEYCODE_2_INDEXED(0)
-#define KEYCODE_3 KEYCODE_3_INDEXED(0)
-#define KEYCODE_4 KEYCODE_4_INDEXED(0)
-#define KEYCODE_5 KEYCODE_5_INDEXED(0)
-#define KEYCODE_6 KEYCODE_6_INDEXED(0)
-#define KEYCODE_7 KEYCODE_7_INDEXED(0)
-#define KEYCODE_8 KEYCODE_8_INDEXED(0)
-#define KEYCODE_9 KEYCODE_9_INDEXED(0)
-#define KEYCODE_F1 KEYCODE_F1_INDEXED(0)
-#define KEYCODE_F2 KEYCODE_F2_INDEXED(0)
-#define KEYCODE_F3 KEYCODE_F3_INDEXED(0)
-#define KEYCODE_F4 KEYCODE_F4_INDEXED(0)
-#define KEYCODE_F5 KEYCODE_F5_INDEXED(0)
-#define KEYCODE_F6 KEYCODE_F6_INDEXED(0)
-#define KEYCODE_F7 KEYCODE_F7_INDEXED(0)
-#define KEYCODE_F8 KEYCODE_F8_INDEXED(0)
-#define KEYCODE_F9 KEYCODE_F9_INDEXED(0)
-#define KEYCODE_F10 KEYCODE_F10_INDEXED(0)
-#define KEYCODE_F11 KEYCODE_F11_INDEXED(0)
-#define KEYCODE_F12 KEYCODE_F12_INDEXED(0)
-#define KEYCODE_F13 KEYCODE_F13_INDEXED(0)
-#define KEYCODE_F14 KEYCODE_F14_INDEXED(0)
-#define KEYCODE_F15 KEYCODE_F15_INDEXED(0)
-#define KEYCODE_F16 KEYCODE_F16_INDEXED(0)
-#define KEYCODE_F17 KEYCODE_F17_INDEXED(0)
-#define KEYCODE_F18 KEYCODE_F18_INDEXED(0)
-#define KEYCODE_F19 KEYCODE_F19_INDEXED(0)
-#define KEYCODE_F20 KEYCODE_F20_INDEXED(0)
-#define KEYCODE_ESC KEYCODE_ESC_INDEXED(0)
-#define KEYCODE_TILDE KEYCODE_TILDE_INDEXED(0)
-#define KEYCODE_MINUS KEYCODE_MINUS_INDEXED(0)
-#define KEYCODE_EQUALS KEYCODE_EQUALS_INDEXED(0)
-#define KEYCODE_BACKSPACE KEYCODE_BACKSPACE_INDEXED(0)
-#define KEYCODE_TAB KEYCODE_TAB_INDEXED(0)
-#define KEYCODE_OPENBRACE KEYCODE_OPENBRACE_INDEXED(0)
-#define KEYCODE_CLOSEBRACE KEYCODE_CLOSEBRACE_INDEXED(0)
-#define KEYCODE_ENTER KEYCODE_ENTER_INDEXED(0)
-#define KEYCODE_COLON KEYCODE_COLON_INDEXED(0)
-#define KEYCODE_QUOTE KEYCODE_QUOTE_INDEXED(0)
-#define KEYCODE_BACKSLASH KEYCODE_BACKSLASH_INDEXED(0)
-#define KEYCODE_BACKSLASH2 KEYCODE_BACKSLASH2_INDEXED(0)
-#define KEYCODE_COMMA KEYCODE_COMMA_INDEXED(0)
-#define KEYCODE_STOP KEYCODE_STOP_INDEXED(0)
-#define KEYCODE_SLASH KEYCODE_SLASH_INDEXED(0)
-#define KEYCODE_SPACE KEYCODE_SPACE_INDEXED(0)
-#define KEYCODE_INSERT KEYCODE_INSERT_INDEXED(0)
-#define KEYCODE_DEL KEYCODE_DEL_INDEXED(0)
-#define KEYCODE_HOME KEYCODE_HOME_INDEXED(0)
-#define KEYCODE_END KEYCODE_END_INDEXED(0)
-#define KEYCODE_PGUP KEYCODE_PGUP_INDEXED(0)
-#define KEYCODE_PGDN KEYCODE_PGDN_INDEXED(0)
-#define KEYCODE_LEFT KEYCODE_LEFT_INDEXED(0)
-#define KEYCODE_RIGHT KEYCODE_RIGHT_INDEXED(0)
-#define KEYCODE_UP KEYCODE_UP_INDEXED(0)
-#define KEYCODE_DOWN KEYCODE_DOWN_INDEXED(0)
-#define KEYCODE_0_PAD KEYCODE_0_PAD_INDEXED(0)
-#define KEYCODE_1_PAD KEYCODE_1_PAD_INDEXED(0)
-#define KEYCODE_2_PAD KEYCODE_2_PAD_INDEXED(0)
-#define KEYCODE_3_PAD KEYCODE_3_PAD_INDEXED(0)
-#define KEYCODE_4_PAD KEYCODE_4_PAD_INDEXED(0)
-#define KEYCODE_5_PAD KEYCODE_5_PAD_INDEXED(0)
-#define KEYCODE_6_PAD KEYCODE_6_PAD_INDEXED(0)
-#define KEYCODE_7_PAD KEYCODE_7_PAD_INDEXED(0)
-#define KEYCODE_8_PAD KEYCODE_8_PAD_INDEXED(0)
-#define KEYCODE_9_PAD KEYCODE_9_PAD_INDEXED(0)
-#define KEYCODE_SLASH_PAD KEYCODE_SLASH_PAD_INDEXED(0)
-#define KEYCODE_ASTERISK KEYCODE_ASTERISK_INDEXED(0)
-#define KEYCODE_MINUS_PAD KEYCODE_MINUS_PAD_INDEXED(0)
-#define KEYCODE_PLUS_PAD KEYCODE_PLUS_PAD_INDEXED(0)
-#define KEYCODE_DEL_PAD KEYCODE_DEL_PAD_INDEXED(0)
-#define KEYCODE_ENTER_PAD KEYCODE_ENTER_PAD_INDEXED(0)
-#define KEYCODE_BS_PAD KEYCODE_BS_PAD_INDEXED(0)
-#define KEYCODE_TAB_PAD KEYCODE_TAB_PAD_INDEXED(0)
-#define KEYCODE_00_PAD KEYCODE_00_PAD_INDEXED(0)
-#define KEYCODE_000_PAD KEYCODE_000_PAD_INDEXED(0)
-#define KEYCODE_COMMA_PAD KEYCODE_COMMA_PAD_INDEXED(0)
-#define KEYCODE_EQUALS_PAD KEYCODE_EQUALS_PAD_INDEXED(0)
-#define KEYCODE_PRTSCR KEYCODE_PRTSCR_INDEXED(0)
-#define KEYCODE_PAUSE KEYCODE_PAUSE_INDEXED(0)
-#define KEYCODE_LSHIFT KEYCODE_LSHIFT_INDEXED(0)
-#define KEYCODE_RSHIFT KEYCODE_RSHIFT_INDEXED(0)
-#define KEYCODE_LCONTROL KEYCODE_LCONTROL_INDEXED(0)
-#define KEYCODE_RCONTROL KEYCODE_RCONTROL_INDEXED(0)
-#define KEYCODE_LALT KEYCODE_LALT_INDEXED(0)
-#define KEYCODE_RALT KEYCODE_RALT_INDEXED(0)
-#define KEYCODE_SCRLOCK KEYCODE_SCRLOCK_INDEXED(0)
-#define KEYCODE_NUMLOCK KEYCODE_NUMLOCK_INDEXED(0)
-#define KEYCODE_CAPSLOCK KEYCODE_CAPSLOCK_INDEXED(0)
-#define KEYCODE_LWIN KEYCODE_LWIN_INDEXED(0)
-#define KEYCODE_RWIN KEYCODE_RWIN_INDEXED(0)
-#define KEYCODE_MENU KEYCODE_MENU_INDEXED(0)
-#define KEYCODE_CANCEL KEYCODE_CANCEL_INDEXED(0)
-
-// mouse axes as relative devices
-#define MOUSECODE_X_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS)
-#define MOUSECODE_Y_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS)
-#define MOUSECODE_Z_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS)
-
-#define MOUSECODE_X MOUSECODE_X_INDEXED(0)
-#define MOUSECODE_Y MOUSECODE_Y_INDEXED(0)
-#define MOUSECODE_Z MOUSECODE_Z_INDEXED(0)
-
-// mouse axes as switches in +/- direction
-#define MOUSECODE_X_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_XAXIS)
-#define MOUSECODE_X_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS)
-#define MOUSECODE_Y_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_YAXIS)
-#define MOUSECODE_Y_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS)
-#define MOUSECODE_Z_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS)
-#define MOUSECODE_Z_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS)
-
-#define MOUSECODE_X_POS_SWITCH MOUSECODE_X_POS_SWITCH_INDEXED(0)
-#define MOUSECODE_X_NEG_SWITCH MOUSECODE_X_NEG_SWITCH_INDEXED(0)
-#define MOUSECODE_Y_POS_SWITCH MOUSECODE_Y_POS_SWITCH_INDEXED(0)
-#define MOUSECODE_Y_NEG_SWITCH MOUSECODE_Y_NEG_SWITCH_INDEXED(0)
-#define MOUSECODE_Z_POS_SWITCH MOUSECODE_Z_POS_SWITCH_INDEXED(0)
-#define MOUSECODE_Z_NEG_SWITCH MOUSECODE_Z_NEG_SWITCH_INDEXED(0)
-
-// mouse buttons
-#define MOUSECODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1)
-#define MOUSECODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2)
-#define MOUSECODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3)
-#define MOUSECODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4)
-#define MOUSECODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5)
-#define MOUSECODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6)
-#define MOUSECODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7)
-#define MOUSECODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8)
-
-#define MOUSECODE_BUTTON1 MOUSECODE_BUTTON1_INDEXED(0)
-#define MOUSECODE_BUTTON2 MOUSECODE_BUTTON2_INDEXED(0)
-#define MOUSECODE_BUTTON3 MOUSECODE_BUTTON3_INDEXED(0)
-#define MOUSECODE_BUTTON4 MOUSECODE_BUTTON4_INDEXED(0)
-#define MOUSECODE_BUTTON5 MOUSECODE_BUTTON5_INDEXED(0)
-#define MOUSECODE_BUTTON6 MOUSECODE_BUTTON6_INDEXED(0)
-#define MOUSECODE_BUTTON7 MOUSECODE_BUTTON7_INDEXED(0)
-#define MOUSECODE_BUTTON8 MOUSECODE_BUTTON8_INDEXED(0)
-
-// gun axes as absolute devices
-#define GUNCODE_X_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS)
-#define GUNCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS)
-
-#define GUNCODE_X GUNCODE_X_INDEXED(0)
-#define GUNCODE_Y GUNCODE_Y_INDEXED(0)
-
-// gun buttons
-#define GUNCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1)
-#define GUNCODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2)
-#define GUNCODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3)
-#define GUNCODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4)
-#define GUNCODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5)
-#define GUNCODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6)
-#define GUNCODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7)
-#define GUNCODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8)
-
-#define GUNCODE_BUTTON1 GUNCODE_BUTTON1_INDEXED(0)
-#define GUNCODE_BUTTON2 GUNCODE_BUTTON2_INDEXED(0)
-#define GUNCODE_BUTTON3 GUNCODE_BUTTON3_INDEXED(0)
-#define GUNCODE_BUTTON4 GUNCODE_BUTTON4_INDEXED(0)
-#define GUNCODE_BUTTON5 GUNCODE_BUTTON5_INDEXED(0)
-#define GUNCODE_BUTTON6 GUNCODE_BUTTON6_INDEXED(0)
-#define GUNCODE_BUTTON7 GUNCODE_BUTTON7_INDEXED(0)
-#define GUNCODE_BUTTON8 GUNCODE_BUTTON8_INDEXED(0)
-
-// joystick axes as absolute devices
-#define JOYCODE_X_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS)
-#define JOYCODE_Y_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS)
-#define JOYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS)
-#define JOYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS)
-#define JOYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS)
-#define JOYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS)
-
-#define JOYCODE_X JOYCODE_X_INDEXED(0)
-#define JOYCODE_Y JOYCODE_Y_INDEXED(0)
-#define JOYCODE_Z JOYCODE_Z_INDEXED(0)
-#define JOYCODE_U JOYCODE_U_INDEXED(0)
-#define JOYCODE_V JOYCODE_V_INDEXED(0)
-#define JOYCODE_W JOYCODE_W_INDEXED(0)
-
-// joystick axes as absolute half-axes
-#define JOYCODE_X_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS)
-#define JOYCODE_X_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS)
-#define JOYCODE_Y_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_YAXIS)
-#define JOYCODE_Y_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS)
-#define JOYCODE_Z_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS)
-#define JOYCODE_Z_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS)
-#define JOYCODE_U_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS)
-#define JOYCODE_U_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS)
-#define JOYCODE_V_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS)
-#define JOYCODE_V_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS)
-#define JOYCODE_W_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS)
-#define JOYCODE_W_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS)
-
-#define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0)
-#define JOYCODE_Y_POS_ABSOLUTE JOYCODE_Y_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_Y_NEG_ABSOLUTE JOYCODE_Y_NEG_ABSOLUTE_INDEXED(0)
-#define JOYCODE_Z_POS_ABSOLUTE JOYCODE_Z_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_Z_NEG_ABSOLUTE JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0)
-#define JOYCODE_U_POS_ABSOLUTE JOYCODE_U_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0)
-#define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0)
-#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0)
-#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)
-
-// joystick axes as switches; X/Y are specially handled for left/right/up/down mapping
-#define JOYCODE_X_LEFT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS)
-#define JOYCODE_X_RIGHT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, ITEM_ID_XAXIS)
-#define JOYCODE_Y_UP_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, ITEM_ID_YAXIS)
-#define JOYCODE_Y_DOWN_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, ITEM_ID_YAXIS)
-#define JOYCODE_Z_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS)
-#define JOYCODE_Z_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS)
-#define JOYCODE_U_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS)
-#define JOYCODE_U_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS)
-#define JOYCODE_V_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS)
-#define JOYCODE_V_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS)
-#define JOYCODE_W_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS)
-#define JOYCODE_W_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS)
-
-#define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0)
-#define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0)
-#define JOYCODE_Y_UP_SWITCH JOYCODE_Y_UP_SWITCH_INDEXED(0)
-#define JOYCODE_Y_DOWN_SWITCH JOYCODE_Y_DOWN_SWITCH_INDEXED(0)
-#define JOYCODE_Z_POS_SWITCH JOYCODE_Z_POS_SWITCH_INDEXED(0)
-#define JOYCODE_Z_NEG_SWITCH JOYCODE_Z_NEG_SWITCH_INDEXED(0)
-#define JOYCODE_U_POS_SWITCH JOYCODE_U_POS_SWITCH_INDEXED(0)
-#define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0)
-#define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0)
-#define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0)
-#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0)
-#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0)
-
-// joystick buttons
-#define JOYCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1)
-#define JOYCODE_BUTTON2_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2)
-#define JOYCODE_BUTTON3_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3)
-#define JOYCODE_BUTTON4_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4)
-#define JOYCODE_BUTTON5_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5)
-#define JOYCODE_BUTTON6_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6)
-#define JOYCODE_BUTTON7_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7)
-#define JOYCODE_BUTTON8_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8)
-#define JOYCODE_BUTTON9_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON9)
-#define JOYCODE_BUTTON10_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON10)
-#define JOYCODE_BUTTON11_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON11)
-#define JOYCODE_BUTTON12_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON12)
-#define JOYCODE_BUTTON13_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON13)
-#define JOYCODE_BUTTON14_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON14)
-#define JOYCODE_BUTTON15_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON15)
-#define JOYCODE_BUTTON16_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON16)
-#define JOYCODE_BUTTON17_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON17)
-#define JOYCODE_BUTTON18_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON18)
-#define JOYCODE_BUTTON19_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON19)
-#define JOYCODE_BUTTON20_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON20)
-#define JOYCODE_BUTTON21_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON21)
-#define JOYCODE_BUTTON22_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON22)
-#define JOYCODE_BUTTON23_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON23)
-#define JOYCODE_BUTTON24_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON24)
-#define JOYCODE_BUTTON25_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON25)
-#define JOYCODE_BUTTON26_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON26)
-#define JOYCODE_BUTTON27_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON27)
-#define JOYCODE_BUTTON28_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON28)
-#define JOYCODE_BUTTON29_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON29)
-#define JOYCODE_BUTTON30_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON30)
-#define JOYCODE_BUTTON31_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON31)
-#define JOYCODE_BUTTON32_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON32)
-#define JOYCODE_START_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_START)
-#define JOYCODE_SELECT_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SELECT)
-
-#define JOYCODE_BUTTON1 JOYCODE_BUTTON1_INDEXED(0)
-#define JOYCODE_BUTTON2 JOYCODE_BUTTON2_INDEXED(0)
-#define JOYCODE_BUTTON3 JOYCODE_BUTTON3_INDEXED(0)
-#define JOYCODE_BUTTON4 JOYCODE_BUTTON4_INDEXED(0)
-#define JOYCODE_BUTTON5 JOYCODE_BUTTON5_INDEXED(0)
-#define JOYCODE_BUTTON6 JOYCODE_BUTTON6_INDEXED(0)
-#define JOYCODE_BUTTON7 JOYCODE_BUTTON7_INDEXED(0)
-#define JOYCODE_BUTTON8 JOYCODE_BUTTON8_INDEXED(0)
-#define JOYCODE_BUTTON9 JOYCODE_BUTTON9_INDEXED(0)
-#define JOYCODE_BUTTON10 JOYCODE_BUTTON10_INDEXED(0)
-#define JOYCODE_BUTTON11 JOYCODE_BUTTON11_INDEXED(0)
-#define JOYCODE_BUTTON12 JOYCODE_BUTTON12_INDEXED(0)
-#define JOYCODE_BUTTON13 JOYCODE_BUTTON13_INDEXED(0)
-#define JOYCODE_BUTTON14 JOYCODE_BUTTON14_INDEXED(0)
-#define JOYCODE_BUTTON15 JOYCODE_BUTTON15_INDEXED(0)
-#define JOYCODE_BUTTON16 JOYCODE_BUTTON16_INDEXED(0)
-#define JOYCODE_BUTTON17 JOYCODE_BUTTON17_INDEXED(0)
-#define JOYCODE_BUTTON18 JOYCODE_BUTTON18_INDEXED(0)
-#define JOYCODE_BUTTON19 JOYCODE_BUTTON19_INDEXED(0)
-#define JOYCODE_BUTTON20 JOYCODE_BUTTON20_INDEXED(0)
-#define JOYCODE_BUTTON21 JOYCODE_BUTTON21_INDEXED(0)
-#define JOYCODE_BUTTON22 JOYCODE_BUTTON22_INDEXED(0)
-#define JOYCODE_BUTTON23 JOYCODE_BUTTON23_INDEXED(0)
-#define JOYCODE_BUTTON24 JOYCODE_BUTTON24_INDEXED(0)
-#define JOYCODE_BUTTON25 JOYCODE_BUTTON25_INDEXED(0)
-#define JOYCODE_BUTTON26 JOYCODE_BUTTON26_INDEXED(0)
-#define JOYCODE_BUTTON27 JOYCODE_BUTTON27_INDEXED(0)
-#define JOYCODE_BUTTON28 JOYCODE_BUTTON28_INDEXED(0)
-#define JOYCODE_BUTTON29 JOYCODE_BUTTON29_INDEXED(0)
-#define JOYCODE_BUTTON30 JOYCODE_BUTTON30_INDEXED(0)
-#define JOYCODE_BUTTON31 JOYCODE_BUTTON31_INDEXED(0)
-#define JOYCODE_BUTTON32 JOYCODE_BUTTON32_INDEXED(0)
-#define JOYCODE_START JOYCODE_START_INDEXED(0)
-#define JOYCODE_SELECT JOYCODE_SELECT_INDEXED(0)
-
-
-
#endif // MAME_EMU_INPUT_H
diff --git a/src/emu/inputdev.cpp b/src/emu/inputdev.cpp
index 436f83cf0df..a9caaf7788d 100644
--- a/src/emu/inputdev.cpp
+++ b/src/emu/inputdev.cpp
@@ -28,7 +28,13 @@ class input_device_switch_item : public input_device_item
{
public:
// construction/destruction
- input_device_switch_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate);
+ input_device_switch_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate);
// readers
virtual s32 read_as_switch(input_item_modifier modifier) override;
@@ -54,7 +60,13 @@ class input_device_relative_item : public input_device_item
{
public:
// construction/destruction
- input_device_relative_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate);
+ input_device_relative_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate);
// readers
virtual s32 read_as_switch(input_item_modifier modifier) override;
@@ -71,7 +83,13 @@ class input_device_absolute_item : public input_device_item
{
public:
// construction/destruction
- input_device_absolute_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate);
+ input_device_absolute_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate);
// readers
virtual s32 read_as_switch(input_item_modifier modifier) override;
@@ -233,8 +251,8 @@ std::string joystick_map::to_string() const
u8 joystick_map::update(s32 xaxisval, s32 yaxisval)
{
// now map the X and Y axes to a 9x9 grid using the raw values
- xaxisval = ((xaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1);
- yaxisval = ((yaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1);
+ xaxisval = ((xaxisval - osd::input_device::ABSOLUTE_MIN) * 9) / (osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN + 1);
+ yaxisval = ((yaxisval - osd::input_device::ABSOLUTE_MIN) * 9) / (osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN + 1);
u8 mapval = m_map[yaxisval][xaxisval];
// handle stickiness
@@ -258,14 +276,15 @@ u8 joystick_map::update(s32 xaxisval, s32 yaxisval)
//-------------------------------------------------
input_device::input_device(input_manager &manager, std::string_view name, std::string_view id, void *internal)
- : m_manager(manager),
- m_name(name),
- m_id(id),
- m_devindex(-1),
- m_maxitem(input_item_id(0)),
- m_internal(internal),
- m_steadykey_enabled(manager.machine().options().steadykey()),
- m_lightgun_reload_button(manager.machine().options().offscreen_reload())
+ : m_manager(manager)
+ , m_name(name)
+ , m_id(id)
+ , m_devindex(-1)
+ , m_maxitem(input_item_id(0))
+ , m_internal(internal)
+ , m_threshold(std::max<s32>(s32(manager.machine().options().joystick_threshold() * osd::input_device::ABSOLUTE_MAX), 1))
+ , m_steadykey_enabled(manager.machine().options().steadykey())
+ , m_lightgun_reload_button(manager.machine().options().offscreen_reload())
{
}
@@ -283,7 +302,12 @@ input_device::~input_device()
// add_item - add a new item to an input device
//-------------------------------------------------
-input_item_id input_device::add_item(std::string_view name, input_item_id itemid, item_get_state_func getstate, void *internal)
+input_item_id input_device::add_item(
+ std::string_view name,
+ std::string_view tokenhint,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ void *internal)
{
if (machine().phase() != machine_phase::INIT)
throw emu_fatalerror("Can only call input_device::add_item at init time!");
@@ -305,15 +329,15 @@ input_item_id input_device::add_item(std::string_view name, input_item_id itemid
switch (m_manager.device_class(devclass()).standard_item_class(originalid))
{
case ITEM_CLASS_SWITCH:
- m_item[itemid] = std::make_unique<input_device_switch_item>(*this, name, internal, itemid, getstate);
+ m_item[itemid] = std::make_unique<input_device_switch_item>(*this, name, tokenhint, internal, itemid, getstate);
break;
case ITEM_CLASS_RELATIVE:
- m_item[itemid] = std::make_unique<input_device_relative_item>(*this, name, internal, itemid, getstate);
+ m_item[itemid] = std::make_unique<input_device_relative_item>(*this, name, tokenhint, internal, itemid, getstate);
break;
case ITEM_CLASS_ABSOLUTE:
- m_item[itemid] = std::make_unique<input_device_absolute_item>(*this, name, internal, itemid, getstate);
+ m_item[itemid] = std::make_unique<input_device_absolute_item>(*this, name, tokenhint, internal, itemid, getstate);
break;
default:
@@ -328,6 +352,17 @@ input_item_id input_device::add_item(std::string_view name, input_item_id itemid
//-------------------------------------------------
+// set_default_assignments - set additional input
+// assignments suitable for device
+//-------------------------------------------------
+
+void input_device::set_default_assignments(assignment_vector &&assignments)
+{
+ m_default_assignments = std::move(assignments);
+}
+
+
+//-------------------------------------------------
// match_device_id - match device id via
// substring search
//-------------------------------------------------
@@ -411,9 +446,10 @@ input_device_lightgun::input_device_lightgun(input_manager &manager, std::string
//-------------------------------------------------
input_device_joystick::input_device_joystick(input_manager &manager, std::string_view _name, std::string_view _id, void *_internal)
- : input_device(manager, _name, _id, _internal),
- m_joystick_deadzone(s32(manager.machine().options().joystick_deadzone() * INPUT_ABSOLUTE_MAX)),
- m_joystick_saturation(s32(manager.machine().options().joystick_saturation() * INPUT_ABSOLUTE_MAX))
+ : input_device(manager, _name, _id, _internal)
+ , m_deadzone(s32(manager.machine().options().joystick_deadzone() * osd::input_device::ABSOLUTE_MAX))
+ , m_saturation(s32(manager.machine().options().joystick_saturation() * osd::input_device::ABSOLUTE_MAX))
+ , m_range(m_saturation - m_deadzone)
{
// get the default joystick map
const char *mapstring = machine().options().joystick_map();
@@ -440,24 +476,16 @@ input_device_joystick::input_device_joystick(input_manager &manager, std::string
s32 input_device_joystick::adjust_absolute_value(s32 result) const
{
// properties are symmetric
- bool negative = false;
- if (result < 0)
- {
- negative = true;
+ bool const negative = result < 0;
+ if (negative)
result = -result;
- }
- // if in the deadzone, return 0
- if (result < m_joystick_deadzone)
+ if (result < m_deadzone) // if in the deadzone, return 0
result = 0;
-
- // if saturated, return the max
- else if (result > m_joystick_saturation)
- result = INPUT_ABSOLUTE_MAX;
-
- // otherwise, scale
- else
- result = s64(result - m_joystick_deadzone) * s64(INPUT_ABSOLUTE_MAX) / s64(m_joystick_saturation - m_joystick_deadzone);
+ else if (result >= m_saturation) // if saturated, return the max
+ result = osd::input_device::ABSOLUTE_MAX;
+ else // otherwise, scale
+ result = s64(result - m_deadzone) * s64(osd::input_device::ABSOLUTE_MAX) / m_range;
// re-apply sign and return
return negative ? -result : result;
@@ -519,9 +547,9 @@ input_device &input_class::add_device(std::unique_ptr<input_device> &&new_device
m_maxindex = std::max(m_maxindex, devindex);
if (new_device->id()[0] == 0)
- osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex, new_device->name());
+ osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex + 1, new_device->name());
else
- osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex, new_device->name(), new_device->id());
+ osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex + 1, new_device->name(), new_device->id());
m_device[devindex] = std::move(new_device);
return *m_device[devindex];
@@ -538,17 +566,21 @@ input_device &input_class::add_device(std::unique_ptr<input_device> &&new_device
input_item_class input_class::standard_item_class(input_item_id itemid) const
{
- // most everything standard is a switch, apart from the axes
if (itemid == ITEM_ID_OTHER_SWITCH || itemid < ITEM_ID_XAXIS || (itemid > ITEM_ID_SLIDER2 && itemid < ITEM_ID_ADD_ABSOLUTE1))
+ {
+ // most everything standard is a switch, apart from the axes
return ITEM_CLASS_SWITCH;
-
- // standard mouse axes are relative
+ }
else if (m_devclass == DEVICE_CLASS_MOUSE || itemid == ITEM_ID_OTHER_AXIS_RELATIVE || (itemid >= ITEM_ID_ADD_RELATIVE1 && itemid <= ITEM_ID_ADD_RELATIVE16))
+ {
+ // standard mouse axes are relative
return ITEM_CLASS_RELATIVE;
-
- // all other standard axes are absolute
+ }
else
+ {
+ // all other standard axes are absolute
return ITEM_CLASS_ABSOLUTE;
+ }
}
@@ -667,25 +699,37 @@ bool input_class_joystick::set_global_joystick_map(const char *mapstring)
// input_device_item - constructor
//-------------------------------------------------
-input_device_item::input_device_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate, input_item_class itemclass)
- : m_device(device),
- m_name(name),
- m_internal(internal),
- m_itemid(itemid),
- m_itemclass(itemclass),
- m_getstate(getstate),
- m_current(0)
+input_device_item::input_device_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ input_item_class itemclass)
+ : m_device(device)
+ , m_name(name)
+ , m_internal(internal)
+ , m_itemid(itemid)
+ , m_itemclass(itemclass)
+ , m_getstate(getstate)
+ , m_current(0)
{
const char *standard_token = manager().standard_token(itemid);
if (standard_token)
{
- // use a standard token name for know item IDs
- m_token.assign(standard_token);
+ // use a standard token name for known item IDs
+ m_token = standard_token;
+ }
+ else if (!tokenhint.empty())
+ {
+ // fall back to token hint if supplied
+ m_token = tokenhint;
}
else
{
// otherwise, create a tokenized name
- m_token.assign(strmakeupper(name));
+ m_token = strmakeupper(name);
strdelchr(m_token, ' ');
strdelchr(m_token, '_');
}
@@ -708,8 +752,8 @@ input_device_item::~input_device_item()
bool input_device_item::check_axis(input_item_modifier modifier, s32 memory)
{
- // use INVALID_AXIS_VALUE as a short-circuit
- return (memory != INVALID_AXIS_VALUE) && item_check_axis(modifier, memory);
+ // use osd::INVALID_AXIS_VALUE as a short-circuit
+ return (memory != osd::input_device::INVALID_AXIS_VALUE) && item_check_axis(modifier, memory);
}
@@ -721,10 +765,16 @@ bool input_device_item::check_axis(input_item_modifier modifier, s32 memory)
// input_device_switch_item - constructor
//-------------------------------------------------
-input_device_switch_item::input_device_switch_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate)
- : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_SWITCH),
- m_steadykey(0),
- m_oldkey(0)
+input_device_switch_item::input_device_switch_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate)
+ : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_SWITCH)
+ , m_steadykey(0)
+ , m_oldkey(0)
{
}
@@ -826,8 +876,14 @@ bool input_device_switch_item::steadykey_changed()
// input_device_relative_item - constructor
//-------------------------------------------------
-input_device_relative_item::input_device_relative_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate)
- : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_RELATIVE)
+input_device_relative_item::input_device_relative_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate)
+ : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_RELATIVE)
{
}
@@ -894,7 +950,7 @@ bool input_device_relative_item::item_check_axis(input_item_modifier modifier, s
const s32 curval = read_as_relative(modifier);
// for relative axes, look for ~20 pixels movement
- return std::abs(curval - memory) > (20 * INPUT_RELATIVE_PER_PIXEL);
+ return std::abs(curval - memory) > (20 * osd::input_device::RELATIVE_PER_PIXEL);
}
@@ -907,8 +963,14 @@ bool input_device_relative_item::item_check_axis(input_item_modifier modifier, s
// input_device_absolute_item - constructor
//-------------------------------------------------
-input_device_absolute_item::input_device_absolute_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate)
- : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_ABSOLUTE)
+input_device_absolute_item::input_device_absolute_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate)
+ : input_device_item(device, name, tokenhint, internal, itemid, getstate, ITEM_CLASS_ABSOLUTE)
{
}
@@ -921,8 +983,7 @@ input_device_absolute_item::input_device_absolute_item(input_device &device, std
s32 input_device_absolute_item::read_as_switch(input_item_modifier modifier)
{
// start with the current value
- s32 result = m_device.adjust_absolute(update_value());
- assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX);
+ s32 const result = update_value();
// left/right/up/down: if this is a joystick, fetch the paired X/Y axis values and convert
if (m_device.devclass() == DEVICE_CLASS_JOYSTICK && modifier >= ITEM_MODIFIER_LEFT && modifier <= ITEM_MODIFIER_DOWN)
@@ -940,18 +1001,24 @@ s32 input_device_absolute_item::read_as_switch(input_item_modifier modifier)
// now map the X and Y axes to a 9x9 grid using the raw values
joystick_map &joymap = downcast<input_device_joystick &>(m_device).joymap();
- return (joymap.update(xaxis_item->current(), yaxis_item->current()) >> (modifier - ITEM_MODIFIER_LEFT)) & 1;
+ return BIT(joymap.update(xaxis_item->current(), yaxis_item->current()), modifier - ITEM_MODIFIER_LEFT);
}
}
- // positive/negative: true if past the deadzone in either direction
- if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN)
- return (result > 0);
- else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP)
- return (result < 0);
-
- // all other cases just return 0
- return 0;
+ // positive/negative: true if past the threshold in either direction, otherwise zero
+ switch (modifier)
+ {
+ case ITEM_MODIFIER_POS:
+ case ITEM_MODIFIER_RIGHT:
+ case ITEM_MODIFIER_DOWN:
+ return result >= m_device.threshold();
+ case ITEM_MODIFIER_NEG:
+ case ITEM_MODIFIER_LEFT:
+ case ITEM_MODIFIER_UP:
+ return -result >= m_device.threshold();
+ default:
+ return 0;
+ }
}
@@ -977,7 +1044,7 @@ s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier)
{
// start with the current value
s32 result = m_device.adjust_absolute(update_value());
- assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX);
+ assert(result >= osd::input_device::ABSOLUTE_MIN && result <= osd::input_device::ABSOLUTE_MAX);
// if we're doing a lightgun reload hack, override the value
if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN && m_device.lightgun_reload_button())
@@ -985,16 +1052,16 @@ s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier)
// if it is pressed, return (min,max)
input_device_item *button2_item = m_device.item(ITEM_ID_BUTTON2);
if (button2_item != nullptr && button2_item->update_value())
- result = (m_itemid == ITEM_ID_XAXIS) ? INPUT_ABSOLUTE_MIN : INPUT_ABSOLUTE_MAX;
+ result = (m_itemid == ITEM_ID_XAXIS) ? osd::input_device::ABSOLUTE_MIN : osd::input_device::ABSOLUTE_MAX;
}
// positive/negative: scale to full axis
if (modifier == ITEM_MODIFIER_REVERSE)
result = -result;
else if (modifier == ITEM_MODIFIER_POS)
- result = std::max(result, 0) * 2 + INPUT_ABSOLUTE_MIN;
+ result = std::max(result, 0) * 2 + osd::input_device::ABSOLUTE_MIN;
else if (modifier == ITEM_MODIFIER_NEG)
- result = std::max(-result, 0) * 2 + INPUT_ABSOLUTE_MIN;
+ result = std::max(-result, 0) * 2 + osd::input_device::ABSOLUTE_MIN;
return result;
}
@@ -1010,9 +1077,9 @@ bool input_device_absolute_item::item_check_axis(input_item_modifier modifier, s
// so the selection will not be affected by a gun going out of range
const s32 curval = read_as_absolute(modifier);
if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN &&
- (curval == INPUT_ABSOLUTE_MAX || curval == INPUT_ABSOLUTE_MIN))
+ (curval == osd::input_device::ABSOLUTE_MAX || curval == osd::input_device::ABSOLUTE_MIN))
return false;
// for absolute axes, look for 25% of maximum
- return std::abs(curval - memory) > ((INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN) / 4);
+ return std::abs(curval - memory) > ((osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN) / 4);
}
diff --git a/src/emu/inputdev.h b/src/emu/inputdev.h
index 1b6dabc9bab..8e914094610 100644
--- a/src/emu/inputdev.h
+++ b/src/emu/inputdev.h
@@ -13,29 +13,13 @@
#pragma once
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// relative devices return ~512 units per onscreen pixel
-constexpr s32 INPUT_RELATIVE_PER_PIXEL = 512;
-
-// absolute devices return values between -65536 and +65536
-constexpr s32 INPUT_ABSOLUTE_MIN = -65536;
-constexpr s32 INPUT_ABSOLUTE_MAX = 65536;
-
-// invalid memory value for axis polling
-constexpr s32 INVALID_AXIS_VALUE = 0x7fffffff;
+#include "interface/inputdev.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// callback for getting the value of an item on a device
-typedef s32 (*item_get_state_func)(void *device_internal, void *item_internal);
-
// ======================> joystick_map
// a 9x9 joystick map
@@ -88,6 +72,8 @@ private:
class input_device_item
{
public:
+ using item_get_state_func = osd::input_device::item_get_state_func;
+
virtual ~input_device_item();
// getters
@@ -114,7 +100,14 @@ public:
protected:
// construction/destruction
- input_device_item(input_device &device, std::string_view name, void *internal, input_item_id itemid, item_get_state_func getstate, input_item_class itemclass);
+ input_device_item(
+ input_device &device,
+ std::string_view name,
+ std::string_view tokenhint,
+ void *internal,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ input_item_class itemclass);
// internal state
input_device & m_device; // reference to our owning device
@@ -133,7 +126,7 @@ protected:
// ======================> input_device
// a logical device of a given class that can provide input
-class input_device
+class input_device : public osd::input_device
{
friend class input_class;
@@ -150,16 +143,24 @@ public:
const std::string &id() const { return m_id; }
int devindex() const { return m_devindex; }
input_device_item *item(input_item_id index) const { return m_item[index].get(); }
+ const assignment_vector &default_assignments() const { return m_default_assignments; }
input_item_id maxitem() const { return m_maxitem; }
void *internal() const { return m_internal; }
+ s32 threshold() const { return m_threshold; }
bool steadykey_enabled() const { return m_steadykey_enabled; }
bool lightgun_reload_button() const { return m_lightgun_reload_button; }
// setters
void set_devindex(int devindex) { m_devindex = devindex; }
- // item management
- input_item_id add_item(std::string_view name, input_item_id itemid, item_get_state_func getstate, void *internal = nullptr);
+ // interface for host input device
+ virtual input_item_id add_item(
+ std::string_view name,
+ std::string_view tokenhint,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ void *internal) override;
+ virtual void set_default_assignments(assignment_vector &&assignments) override;
// helpers
s32 adjust_absolute(s32 value) const { return adjust_absolute_value(value); }
@@ -177,11 +178,13 @@ private:
std::string m_id; // id of device
int m_devindex; // device index of this device
std::unique_ptr<input_device_item> m_item[ITEM_ID_ABSOLUTE_MAXIMUM+1]; // array of pointers to items
+ assignment_vector m_default_assignments; // additional assignments
input_item_id m_maxitem; // maximum item index
- void * m_internal; // internal callback pointer
+ void *const m_internal; // internal callback pointer
- bool m_steadykey_enabled; // steadykey enabled for keyboards
- bool m_lightgun_reload_button; // lightgun reload hack
+ s32 const m_threshold; // threshold for treating absolute axis as active
+ bool const m_steadykey_enabled; // steadykey enabled for keyboards
+ bool const m_lightgun_reload_button; // lightgun reload hack
};
@@ -252,9 +255,10 @@ protected:
private:
// joystick information
- joystick_map m_joymap; // joystick map for this device
- s32 m_joystick_deadzone; // deadzone for joystick
- s32 m_joystick_saturation; // saturation position for joystick
+ joystick_map m_joymap; // joystick map for this device
+ s32 const m_deadzone; // deadzone for joystick
+ s32 const m_saturation; // saturation position for joystick
+ s64 const m_range; // difference between saturation and deadzone
};
diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp
index 0ea7974caf5..aed29b6324f 100644
--- a/src/emu/ioport.cpp
+++ b/src/emu/ioport.cpp
@@ -6,105 +6,30 @@
Input/output port handling.
-****************************************************************************
-
- Theory of operation
-
- ------------
- OSD controls
- ------------
-
- There are three types of controls that the OSD can provide as potential
- input devices: digital controls, absolute analog controls, and relative
- analog controls.
-
- Digital controls have only two states: on or off. They are generally
- mapped to buttons and digital joystick directions (like a gamepad or a
- joystick hat). The OSD layer must return either 0 (off) or 1 (on) for
- these types of controls.
-
- Absolute analog controls are analog in the sense that they return a
- range of values depending on how much a given control is moved, but they
- are physically bounded. This means that there is a minimum and maximum
- limit to how far the control can be moved. They are generally mapped to
- analog joystick axes, lightguns, most PC steering wheels, and pedals.
- The OSD layer must determine the minimum and maximum range of each
- analog device and scale that to a value between -65536 and +65536
- representing the position of the control. -65536 generally refers to
- the topmost or leftmost position, while +65536 refers to the bottommost
- or rightmost position. Note that pedals are a special case here, the
- OSD layer needs to return half axis as full -65536 to + 65536 range.
-
- Relative analog controls are analog as well, but are not physically
- bounded. They can be moved continually in one direction without limit.
- They are generally mapped to trackballs and mice. Because they are
- unbounded, the OSD layer can only return delta values since the last
- read. Because of this, it is difficult to scale appropriately. For
- MAME's purposes, when mapping a mouse devices to a relative analog
- control, one pixel of movement should correspond to 512 units. Other
- analog control types should be scaled to return values of a similar
- magnitude. Like absolute analog controls, negative values refer to
- upward or leftward movement, while positive values refer to downward
- or rightward movement.
-
- -------------
- Game controls
- -------------
-
- Similarly, the types of controls used by arcade games fall into the same
- three categories: digital, absolute analog, and relative analog. The
- tricky part is how to map any arbitrary type of OSD control to an
- arbitrary type of game control.
-
- Digital controls: used for game buttons and standard 4/8-way joysticks,
- as well as many other types of game controls. Mapping an OSD digital
- control to a game's OSD control is trivial. For OSD analog controls,
- the MAME core does not directly support mapping any OSD analog devices
- to digital controls. However, the OSD layer is free to enumerate digital
- equivalents for analog devices. For example, each analog axis in the
- Windows OSD code enumerates to two digital controls, one for the
- negative direction (up/left) and one for the position direction
- (down/right). When these "digital" inputs are queried, the OSD layer
- checks the axis position against the center, adding in a dead zone,
- and returns 0 or 1 to indicate its position.
-
- Absolute analog controls: used for analog joysticks, lightguns, pedals,
- and wheel controls. Mapping an OSD absolute analog control to this type
- is easy. OSD relative analog controls can be mapped here as well by
- accumulating the deltas and bounding the results. OSD digital controls
- are mapped to these types of controls in pairs, one for a decrement and
- one for an increment, but apart from that, operate the same as the OSD
- relative analog controls by accumulating deltas and applying bounds.
- The speed of the digital delta is user-configurable per analog input.
- In addition, most absolute analog control types have an autocentering
- feature that is activated when using the digital increment/decrement
- sequences, which returns the control back to the center at a user-
- controllable speed if no digital sequences are pressed.
-
- Relative analog controls: used for trackballs and dial controls. Again,
- mapping an OSD relative analog control to this type is straightforward.
- OSD absolute analog controls can't map directly to these, but if the OSD
- layer provides a digital equivalent for each direction, it can be done.
- OSD digital controls map just like they do for absolute analog controls,
- except that the accumulated deltas are not bounded, but rather wrap.
-
***************************************************************************/
#include "emu.h"
-#include "emuopts.h"
+
#include "config.h"
-#include "xmlfile.h"
-#include "profiler.h"
-#include "ui/uimain.h"
+#include "emuopts.h"
+#include "fileio.h"
#include "inputdev.h"
+#include "main.h"
#include "natkeyboard.h"
+#include "profiler.h"
+
+#include "ui/uimain.h"
#include "util/corestr.h"
#include "util/ioprocsfilter.h"
+#include "util/language.h"
+#include "util/multibyte.h"
#include "util/unicode.h"
+#include "util/xmlfile.h"
#include "osdepend.h"
+#include <algorithm>
#include <cctype>
#include <ctime>
@@ -161,6 +86,22 @@ inline s32 apply_scale(s32 value, s64 scale)
return (s64(value) * scale) / (1 << 24);
}
+//-------------------------------------------------
+// compute_shift -- get shift required to right-
+// align an I/O port field value
+//-------------------------------------------------
+
+inline u8 compute_shift(ioport_value mask)
+{
+ u8 result = 0U;
+ while (mask && !BIT(mask, 0))
+ {
+ mask >>= 1;
+ ++result;
+ }
+ return result;
+}
+
//**************************************************************************
@@ -307,6 +248,133 @@ inline bool input_seq_good(running_machine &machine, input_seq const &seq)
return input_seq::end_code != machine.input().seq_clean(seq)[0];
}
+
+std::string substitute_player(std::string_view name, u8 player)
+{
+ using util::lang_translate;
+
+ std::string result;
+ while (!name.empty())
+ {
+ auto const found = name.find('%');
+ if ((std::string_view::npos == found) || (name.length() == found + 1))
+ {
+ result.append(name);
+ break;
+ }
+ switch (name[found + 1])
+ {
+ case '%':
+ result.append(name.substr(0, found + 1));
+ break;
+ case 'p':
+ result.append(name.substr(0, found));
+ result.append(util::string_format(_("input-name", "P%1$u"), player + 1));
+ break;
+ default:
+ result.append(name.substr(0, found + 2));
+ }
+ name.remove_prefix(found + 2);
+ }
+ return result;
+}
+
+
+
+// ======================> inp_header
+
+// header at the front of INP files
+class inp_header
+{
+public:
+ // parameters
+ static constexpr unsigned MAJVERSION = 3;
+ static constexpr unsigned MINVERSION = 0;
+
+ bool read(emu_file &f)
+ {
+ return f.read(m_data, sizeof(m_data)) == sizeof(m_data);
+ }
+ bool write(emu_file &f) const
+ {
+ return f.write(m_data, sizeof(m_data)) == sizeof(m_data);
+ }
+
+ bool check_magic() const
+ {
+ return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC);
+ }
+ u64 get_basetime() const
+ {
+ return get_u64le(m_data + OFFS_BASETIME);
+ }
+ unsigned get_majversion() const
+ {
+ return m_data[OFFS_MAJVERSION];
+ }
+ unsigned get_minversion() const
+ {
+ return m_data[OFFS_MINVERSION];
+ }
+ std::string get_sysname() const
+ {
+ return get_string<OFFS_SYSNAME, OFFS_APPDESC>();
+ }
+ std::string get_appdesc() const
+ {
+ return get_string<OFFS_APPDESC, OFFS_END>();
+ }
+
+ void set_magic()
+ {
+ std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC);
+ }
+ void set_basetime(u64 time)
+ {
+ put_u64le(m_data + OFFS_BASETIME, time);
+ }
+ void set_version()
+ {
+ m_data[OFFS_MAJVERSION] = MAJVERSION;
+ m_data[OFFS_MINVERSION] = MINVERSION;
+ }
+ void set_sysname(std::string const &name)
+ {
+ set_string<OFFS_SYSNAME, OFFS_APPDESC>(name);
+ }
+ void set_appdesc(std::string const &desc)
+ {
+ set_string<OFFS_APPDESC, OFFS_END>(desc);
+ }
+
+private:
+ template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str)
+ {
+ std::size_t const used = (std::min<std::size_t>)(str.size() + 1, END - BEGIN);
+ std::memcpy(m_data + BEGIN, str.c_str(), used);
+ if ((END - BEGIN) > used)
+ std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used);
+ }
+ template <std::size_t BEGIN, std::size_t END> std::string get_string() const
+ {
+ char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN);
+ return std::string(begin, std::find(begin, reinterpret_cast<char const *>(m_data + END), '\0'));
+ }
+
+ static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes
+ static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer)
+ static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer)
+ static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer)
+ // 0x02 bytes reserved
+ static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII)
+ static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII)
+ static constexpr std::size_t OFFS_END = 0x40;
+
+ static u8 const MAGIC[OFFS_BASETIME - OFFS_MAGIC];
+
+ u8 m_data[OFFS_END];
+};
+
} // anonymous namespace
@@ -391,6 +459,24 @@ input_type_entry::input_type_entry(ioport_type type, ioport_group group, int pla
//-------------------------------------------------
+// name - gets the display name for the input
+// type
+//-------------------------------------------------
+
+std::string input_type_entry::name() const
+{
+ using util::lang_translate;
+
+ if (!m_name)
+ return std::string();
+ else if ((group() < IPG_PLAYER1) || (group() > IPG_PLAYER10))
+ return _("input-name", m_name);
+ else
+ return substitute_player(_("input-name", m_name), player());
+}
+
+
+//-------------------------------------------------
// replace_code - replace all instances of
// oldcodewith newcode in all sequences
//-------------------------------------------------
@@ -662,6 +748,20 @@ ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value def
}
}
+
+//-------------------------------------------------
+// ~ioport_field - destructor
+//-------------------------------------------------
+
+ioport_field::~ioport_field()
+{
+}
+
+
+//-------------------------------------------------
+// set_value - programmatically set field value
+//-------------------------------------------------
+
void ioport_field::set_value(ioport_value value)
{
if (is_analog())
@@ -672,11 +772,15 @@ void ioport_field::set_value(ioport_value value)
//-------------------------------------------------
-// ~ioport_field - destructor
+// clear_value - clear programmatic override
//-------------------------------------------------
-ioport_field::~ioport_field()
+void ioport_field::clear_value()
{
+ if (is_analog())
+ live().analog->clear_value();
+ else
+ m_digital_value = false;
}
@@ -685,16 +789,25 @@ ioport_field::~ioport_field()
// field (this must never return nullptr)
//-------------------------------------------------
-const char *ioport_field::name() const
+std::string ioport_field::name() const
{
- // if we have a non-default name, use that
- if (m_live != nullptr && !m_live->name.empty())
- return m_live->name.c_str();
- if (m_name != nullptr)
+ using util::lang_translate;
+
+ // if we have an overridden name, use that
+ if (m_live && !m_live->name.empty())
+ return m_live->name;
+
+ // if no specific name, use the generic name for the type
+ if (!m_name)
+ return manager().type_name(m_type, m_player);
+
+ // return name for non-controller fields as-is
+ ioport_group const group = manager().type_group(m_type, m_player);
+ if ((group < IPG_PLAYER1) || (group > IPG_PLAYER10))
return m_name;
- // otherwise, return the name associated with the type
- return manager().type_name(m_type, m_player);
+ // substitute the player number in if necessary
+ return substitute_player(m_name, m_player);
}
@@ -750,8 +863,8 @@ void ioport_field::set_defseq(input_seq_type seqtype, const input_seq &newseq)
ioport_type_class ioport_field::type_class() const noexcept
{
// inputs associated with specific players
- ioport_group group = manager().type_group(m_type, m_player);
- if (group >= IPG_PLAYER1 && group <= IPG_PLAYER10)
+ ioport_group const group = manager().type_group(m_type, m_player);
+ if ((group >= IPG_PLAYER1) && (group <= IPG_PLAYER10))
return INPUT_CLASS_CONTROLLER;
// keys (names derived from character codes)
@@ -759,7 +872,7 @@ ioport_type_class ioport_field::type_class() const noexcept
return INPUT_CLASS_KEYBOARD;
// configuration settings (specific names required)
- if (m_type == IPT_CONFIG)
+ if (m_type == IPT_CONFIG || m_type == IPT_ADJUSTER)
return INPUT_CLASS_CONFIG;
// DIP switches (specific names required)
@@ -1373,12 +1486,16 @@ ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog)
name.append(string_format("%-*s ", std::max(SPACE_COUNT - 1, 0), field.key_name(which)));
}
- // trim extra spaces
- name = strtrimspace(name);
-
// special case
if (name.empty())
name.assign("Unnamed Key");
+ else
+ {
+ // trim extra spaces
+ auto pos = name.find_last_not_of(' ');
+ assert(pos < name.size());
+ name.erase(pos + 1);
+ }
}
}
@@ -1553,14 +1670,14 @@ void ioport_port::insert_field(ioport_field &newfield, ioport_value &disallowedb
for (ioport_field *field = m_fieldlist.first(); field != nullptr; field = nextfield)
{
nextfield = field->next();
- if ((field->mask() & newfield.mask()) != 0 &&
+ if ((field->mask() & newfield.mask()) &&
(newfield.condition().none() || field->condition().none() || field->condition() == newfield.condition()))
{
// reduce the mask of the field we found
field->reduce_mask(newfield.mask());
// if the new entry fully overrides the previous one, we nuke
- if (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS || field->mask() == 0)
+ if (!field->mask() || (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS && (field->type() != IPT_UNUSED) && (field->type() != IPT_UNKNOWN)))
m_fieldlist.remove(*field);
}
}
@@ -1657,11 +1774,10 @@ ioport_manager::ioport_manager(running_machine &machine)
, m_safe_to_read(false)
, m_last_frame_time(attotime::zero)
, m_last_delta_nsec(0)
- , m_record_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS)
- , m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ)
, m_playback_accumulated_speed(0)
, m_playback_accumulated_frames(0)
, m_deselected_card_config()
+ , m_applied_device_defaults(false)
{
for (auto &entries : m_type_to_entry)
std::fill(std::begin(entries), std::end(entries), nullptr);
@@ -1702,12 +1818,14 @@ time_t ioport_manager::initialize()
if (&port.second->device() == &device)
{
for (ioport_field &field : port.second->fields())
+ {
if (field.type_class() == INPUT_CLASS_CONTROLLER)
{
if (players < field.player() + 1)
players = field.player() + 1;
field.set_player(field.player() + player_offset);
}
+ }
}
}
player_offset += players;
@@ -1718,14 +1836,14 @@ time_t ioport_manager::initialize()
port.second->init_live_state();
// handle autoselection of devices
- init_autoselect_devices(IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z, OPTION_ADSTICK_DEVICE, "analog joystick");
- init_autoselect_devices(IPT_PADDLE, IPT_PADDLE_V, 0, OPTION_PADDLE_DEVICE, "paddle");
- init_autoselect_devices(IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3, OPTION_PEDAL_DEVICE, "pedal");
- init_autoselect_devices(IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y, 0, OPTION_LIGHTGUN_DEVICE, "lightgun");
- init_autoselect_devices(IPT_POSITIONAL, IPT_POSITIONAL_V, 0, OPTION_POSITIONAL_DEVICE, "positional");
- init_autoselect_devices(IPT_DIAL, IPT_DIAL_V, 0, OPTION_DIAL_DEVICE, "dial");
- init_autoselect_devices(IPT_TRACKBALL_X, IPT_TRACKBALL_Y, 0, OPTION_TRACKBALL_DEVICE, "trackball");
- init_autoselect_devices(IPT_MOUSE_X, IPT_MOUSE_Y, 0, OPTION_MOUSE_DEVICE, "mouse");
+ init_autoselect_devices({ IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z }, OPTION_ADSTICK_DEVICE, "analog joystick");
+ init_autoselect_devices({ IPT_PADDLE, IPT_PADDLE_V }, OPTION_PADDLE_DEVICE, "paddle");
+ init_autoselect_devices({ IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3 }, OPTION_PEDAL_DEVICE, "pedal");
+ init_autoselect_devices({ IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y }, OPTION_LIGHTGUN_DEVICE, "lightgun");
+ init_autoselect_devices({ IPT_POSITIONAL, IPT_POSITIONAL_V }, OPTION_POSITIONAL_DEVICE, "positional");
+ init_autoselect_devices({ IPT_DIAL, IPT_DIAL_V }, OPTION_DIAL_DEVICE, "dial");
+ init_autoselect_devices({ IPT_TRACKBALL_X, IPT_TRACKBALL_Y }, OPTION_TRACKBALL_DEVICE, "trackball");
+ init_autoselect_devices({ IPT_MOUSE_X, IPT_MOUSE_Y }, OPTION_MOUSE_DEVICE, "mouse");
// look for 4-way diagonal joysticks and change the default map if we find any
const char *joystick_map_default = machine().options().joystick_map();
@@ -1783,39 +1901,71 @@ void ioport_manager::init_port_types()
// in and the corresponding option
//-------------------------------------------------
-void ioport_manager::init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame)
+void ioport_manager::init_autoselect_devices(std::initializer_list<ioport_type> types, std::string_view option, std::string_view ananame)
{
+ static std::pair<char const *, char const *> const CLASS_OPTIONS[] = {
+ { "mouse", OPTION_MOUSE },
+ { "joystick", OPTION_JOYSTICK },
+ { "lightgun", OPTION_LIGHTGUN } };
+
// if nothing specified, ignore the option
- const char *stemp = machine().options().value(option);
- if (stemp[0] == 0 || strcmp(stemp, "none") == 0)
+ auto const autooption = machine().options().get_entry(option);
+ char const *const autoclass = autooption->value();
+ if (!autoclass || !*autoclass || !std::strcmp(autoclass, "none"))
return;
- // extract valid strings
+ // if the device class is enabled anyway or disabled at a higher priority level, do nothing
+ auto const classname = std::find_if(
+ std::begin(CLASS_OPTIONS),
+ std::end(CLASS_OPTIONS),
+ [&autoclass] (auto const &x) { return !std::strcmp(autoclass, x.first); });
+ if (std::end(CLASS_OPTIONS) != classname)
+ {
+ if (machine().options().bool_value(classname->second))
+ return;
+
+ auto const classoption = machine().options().get_entry(classname->second);
+ if (classoption->priority() > autooption->priority())
+ {
+ osd_printf_verbose("Input: Won't autoenable %s in presence of a %s as it's disabled at a higher priority\n", autoclass, ananame);
+ return;
+ }
+ }
+
+ // find matching device class
input_class *autoenable_class = nullptr;
for (input_device_class devclass = DEVICE_CLASS_FIRST_VALID; devclass <= DEVICE_CLASS_LAST_VALID; ++devclass)
- if (strcmp(stemp, machine().input().device_class(devclass).name()) == 0)
+ {
+ if (!std::strcmp(autoclass, machine().input().device_class(devclass).name()))
{
autoenable_class = &machine().input().device_class(devclass);
break;
}
- if (autoenable_class == nullptr)
+ }
+ if (!autoenable_class)
{
- osd_printf_error("Invalid %s value %s; reverting to keyboard\n", option, stemp);
+ osd_printf_error("Invalid %s value %s; reverting to keyboard\n", option, autoclass);
autoenable_class = &machine().input().device_class(DEVICE_CLASS_KEYBOARD);
}
- // only scan the list if we haven't already enabled this class of control
- if (!autoenable_class->enabled())
- for (auto &port : m_portlist)
- for (ioport_field const &field : port.second->fields())
+ // nothing to do if the class is already enabled
+ if (autoenable_class->enabled())
+ return;
- // if this port type is in use, apply the autoselect criteria
- if ((type1 != 0 && field.type() == type1) || (type2 != 0 && field.type() == type2) || (type3 != 0 && field.type() == type3))
- {
- osd_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autoenable_class->name(), ananame);
- autoenable_class->enable();
- break;
- }
+ // scan the port list
+ for (auto &port : m_portlist)
+ {
+ for (ioport_field const &field : port.second->fields())
+ {
+ // if this port type is in use, apply the autoselect criteria
+ if (std::find(std::begin(types), std::end(types), field.type()) != std::end(types))
+ {
+ osd_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autoenable_class->name(), ananame);
+ autoenable_class->enable();
+ return;
+ }
+ }
+ }
}
@@ -1846,15 +1996,21 @@ ioport_manager::~ioport_manager()
// type/player
//-------------------------------------------------
-const char *ioport_manager::type_name(ioport_type type, u8 player) const noexcept
+std::string ioport_manager::type_name(ioport_type type, u8 player) const
{
+ using util::lang_translate;
+
// if we have a machine, use the live state and quick lookup
- input_type_entry *entry = m_type_to_entry[type][player];
- if (entry != nullptr && entry->name() != nullptr)
- return entry->name();
+ input_type_entry const *const entry = m_type_to_entry[type][player];
+ if (entry)
+ {
+ std::string name = entry->name();
+ if (!name.empty())
+ return name;
+ }
// if we find nothing, return a default string (not a null pointer)
- return "???";
+ return _("input-name", "???");
}
@@ -2000,7 +2156,7 @@ void ioport_manager::frame_update_callback()
void ioport_manager::frame_update()
{
- g_profiler.start(PROFILER_INPUT);
+ auto profile = g_profiler.start(PROFILER_INPUT);
// record/playback information about the current frame
attotime curtime = machine().time();
@@ -2037,8 +2193,6 @@ void ioport_manager::frame_update()
if (dynfield.field().type() != IPT_OUTPUT)
dynfield.write(newvalue);
}
-
- g_profiler.stop();
}
@@ -2066,6 +2220,17 @@ s32 ioport_manager::frame_interpolate(s32 oldval, s32 newval)
void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode)
{
+ // make sure device defaults get applied at some point
+ if ((cfg_type > config_type::CONTROLLER) && !m_applied_device_defaults)
+ {
+ apply_device_defaults();
+
+ // after applying controller config, push that to the backup, as it's what we'll diff against
+ for (input_type_entry &entry : m_typelist)
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
+ entry.defseq(seqtype) = entry.seq(seqtype);
+ }
+
// in the completion phase, we finish the initialization with the final ports
if (cfg_type == config_type::FINAL)
{
@@ -2080,9 +2245,7 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u
// load device map table for controller configs only
if (cfg_type == config_type::CONTROLLER)
{
- // iterate over all the remap nodes
- load_remap_table(*parentnode);
-
+ // iterate over device remapping entries
input_manager::devicemap_table devicemap;
for (util::xml::data_node const *mapdevice_node = parentnode->get_child("mapdevice"); mapdevice_node != nullptr; mapdevice_node = mapdevice_node->get_next_sibling("mapdevice"))
{
@@ -2092,9 +2255,23 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u
devicemap.emplace(devicename, controllername);
}
- // map device to controller if we have a device map
- if (!devicemap.empty())
- machine().input().map_device_to_controller(devicemap);
+ // we can't rearrange controllers after applying device-supplied defaults
+ if (!m_applied_device_defaults)
+ {
+ // map device to controller if we have a device map
+ if (!devicemap.empty())
+ machine().input().map_device_to_controller(devicemap);
+
+ // add extra default assignments for input devices
+ apply_device_defaults();
+ }
+ else if (!devicemap.empty())
+ {
+ osd_printf_warning("Controller configuration: Only <mapdevice> elements from the first applicable <system> element are applied\n");
+ }
+
+ // iterate over any input code remapping nodes
+ load_remap_table(*parentnode);
}
// iterate over all the port nodes
@@ -2137,16 +2314,16 @@ void ioport_manager::load_config(config_type cfg_type, config_level cfg_level, u
load_default_config(type, player, newseq);
}
- // after applying the controller config, push that back into the backup, since that is
- // what we will diff against
if (cfg_type == config_type::CONTROLLER)
+ {
+ // after applying the controller config, push that back into the backup, since that is what we will diff against
for (input_type_entry &entry : m_typelist)
for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
entry.defseq(seqtype) = entry.seq(seqtype);
-
- // load keyboard enable/disable state
- if (cfg_type == config_type::SYSTEM)
+ }
+ else if (cfg_type == config_type::SYSTEM)
{
+ // load keyboard enable/disable state
std::vector<bool> kbd_enable_set;
bool keyboard_enabled = false, missing_enabled = false;
natural_keyboard &natkbd = machine().natkeyboard();
@@ -2303,6 +2480,7 @@ bool ioport_manager::load_controller_config(
// find the matching field
ioport_value const defvalue = portnode.get_attribute_int("defvalue", 0);
+ bool matched = false;
for (ioport_field &field : port->second->fields())
{
// find the matching mask and default value
@@ -2313,7 +2491,10 @@ bool ioport_manager::load_controller_config(
for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
{
if (input_seq_good(machine(), newseq[seqtype].first))
+ {
+ field.live().seq[seqtype] = newseq[seqtype].first;
field.set_defseq(seqtype, newseq[seqtype].first);
+ }
}
// fetch configurable attributes
@@ -2361,13 +2542,16 @@ bool ioport_manager::load_controller_config(
#endif
}
- // successfully applied
- return true;
+ // only break out of the loop for unconditional inputs
+ if (field.condition().condition() == ioport_condition::ALWAYS)
+ return true;
+ else
+ matched = true;
}
}
- // no matching field
- return false;
+ // return whether any field matched
+ return matched;
}
@@ -2438,7 +2622,10 @@ void ioport_manager::load_system_config(
else if (revstring && !strcmp(revstring, "no"))
field.live().analog->m_reverse = false;
}
- break;
+
+ // only break out of the loop for unconditional inputs
+ if (field.condition().condition() == ioport_condition::ALWAYS)
+ break;
}
}
}
@@ -2475,6 +2662,82 @@ void ioport_manager::load_system_config(
}
+//-------------------------------------------------
+// apply_device_defaults - add default assignments
+// supplied by input devices
+//-------------------------------------------------
+
+void ioport_manager::apply_device_defaults()
+{
+ // make sure this only happens once
+ assert(!m_applied_device_defaults);
+ m_applied_device_defaults = true;
+
+ // TODO: come up with a way to deal with non-multi device classes here?
+ for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
+ {
+ input_class &devclass = machine().input().device_class(classno);
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ {
+ // make sure device exists
+ input_device const *const device = devclass.device(devnum);
+ if (!device)
+ continue;
+
+ // iterate over default assignments
+ for (auto [porttype, seqtype, seq] : device->default_assignments())
+ {
+ assert(!seq.empty());
+ assert(seq.is_valid());
+ assert(!seq.is_default());
+
+ // only apply UI assignments for first device in a class
+ if ((IPT_UI_FIRST < porttype) && (IPT_UI_LAST > porttype) && (device->devindex() != 0))
+ continue;
+
+ // limit to maximum player count
+ if (device->devindex() >= MAX_PLAYERS)
+ continue;
+
+ // find a matching port in the list
+ auto const found = std::find_if(
+ m_typelist.begin(),
+ m_typelist.end(),
+ [type = porttype, device] (input_type_entry const &entry)
+ {
+ return (entry.type() == type) && (entry.player() == device->devindex());
+ });
+ if (m_typelist.end() == found)
+ continue;
+
+ // start with the current setting
+ input_seq remapped(found->seq(seqtype));
+ if (!remapped.empty())
+ remapped += input_seq::or_code;
+
+ // append adjusting the device index
+ for (int i = 0, len = seq.length(); i < len; ++i)
+ {
+ input_code code = seq[i];
+ if (!code.internal())
+ {
+ assert(code.device_class() == classno);
+ assert(code.device_index() == 0);
+ assert(code.item_id() >= ITEM_ID_FIRST_VALID);
+ assert(code.item_id() <= ITEM_ID_ABSOLUTE_MAXIMUM);
+ code.set_device_index(device->devindex());
+ }
+ remapped += code;
+ }
+
+ // apply to the entry
+ found->set_seq(seqtype, remapped);
+ }
+ }
+ }
+}
+
+
//**************************************************************************
// SETTINGS SAVE
@@ -2586,7 +2849,7 @@ void ioport_manager::save_game_inputs(util::xml::data_node &parentnode)
// iterate over ports
for (auto &port : m_portlist)
for (ioport_field const &field : port.second->fields())
- if (save_this_input_field_type(field.type()))
+ if (save_this_input_field_type(field.type()) && field.enabled())
{
// determine if we changed
bool changed = false;
@@ -2683,9 +2946,13 @@ Type ioport_manager::playback_read(Type &result)
return result = Type(0);
// read the value; if we fail, end playback
- size_t read;
- m_playback_stream->read(&result, sizeof(result), read);
- if (sizeof(result) != read)
+ auto const [err, actual] = read(*m_playback_stream, &result, sizeof(result));
+ if (err)
+ {
+ playback_end("Read error");
+ return result = Type(0);
+ }
+ else if (sizeof(result) != actual)
{
playback_end("End of file");
return result = Type(0);
@@ -2723,7 +2990,8 @@ time_t ioport_manager::playback_init()
return 0;
// open the playback file
- std::error_condition const filerr = m_playback_file.open(filename);
+ m_playback_file = std::make_unique<emu_file>(machine().options().input_directory(), OPEN_FLAG_READ);
+ std::error_condition const filerr = m_playback_file->open(filename);
// return an explicit error if file isn't found in given path
if (filerr == std::errc::no_such_file_or_directory)
@@ -2735,7 +3003,7 @@ time_t ioport_manager::playback_init()
// read the header and verify that it is a modern version; if not, print an error
inp_header header;
- if (!header.read(m_playback_file))
+ if (!header.read(*m_playback_file))
fatalerror("Input file is corrupt or invalid (missing header)\n");
if (!header.check_magic())
fatalerror("Input file invalid or in an older, unsupported format\n");
@@ -2755,7 +3023,7 @@ time_t ioport_manager::playback_init()
osd_printf_info("Input file is for machine '%s', not for current machine '%s'\n", sysname, machine().system().name);
// enable compression
- m_playback_stream = util::zlib_read(m_playback_file, 16386);
+ m_playback_stream = util::zlib_read(*m_playback_file, 16386);
return basetime;
}
@@ -2771,7 +3039,7 @@ void ioport_manager::playback_end(const char *message)
{
// close the file
m_playback_stream.reset();
- m_playback_file.close();
+ m_playback_file.reset();
// pop a message
if (message != nullptr)
@@ -2868,9 +3136,8 @@ void ioport_manager::record_write(Type value)
value = little_endianize_int16(value);
// write the value; if we fail, end recording
- size_t written;
- if (m_record_stream->write(&value, sizeof(value), written) || (sizeof(value) != written))
- record_end("Out of space");
+ if (write(*m_record_stream, &value, sizeof(value)).first)
+ record_end("Write error");
}
template<>
@@ -2893,7 +3160,8 @@ void ioport_manager::record_init()
return;
// open the record file
- std::error_condition const filerr = m_record_file.open(filename);
+ m_record_file = std::make_unique<emu_file>(machine().options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition const filerr = m_record_file->open(filename);
if (filerr)
throw emu_fatalerror("ioport_manager::record_init: Failed to open file for recording (%s:%d %s)", filerr.category().name(), filerr.value(), filerr.message());
@@ -2910,10 +3178,10 @@ void ioport_manager::record_init()
header.set_appdesc(util::string_format("%s %s", emulator_info::get_appname(), emulator_info::get_build_version()));
// write it
- header.write(m_record_file);
+ header.write(*m_record_file);
// enable compression
- m_record_stream = util::zlib_write(m_record_file, 6, 16384);
+ m_record_stream = util::zlib_write(*m_record_file, 6, 16384);
}
@@ -2928,7 +3196,7 @@ void ioport_manager::record_end(const char *message)
{
// close the file
m_record_stream.reset(); // TODO: check for errors flushing the last compressed block before doing this
- m_record_file.close();
+ m_record_file.reset();
// pop a message
if (message != nullptr)
@@ -3145,7 +3413,7 @@ ioport_configurer& ioport_configurer::setting_alloc(ioport_value value, const ch
{
// make sure we have a field
if (!m_curfield)
- throw emu_fatalerror("alloc_setting called with no active field (value=%X name=%s)\n", value, name);
+ throw emu_fatalerror("setting_alloc called with no active field (value=%X name=%s)\n", value, name);
// append a new setting
m_cursetting = &m_curfield->m_settinglist.emplace_back(*m_curfield, value & m_curfield->mask(), string_from_token(name));
@@ -3198,9 +3466,9 @@ ioport_configurer& ioport_configurer::onoff_alloc(const char *name, ioport_value
//-------------------------------------------------
dynamic_field::dynamic_field(ioport_field &field)
- : m_field(field),
- m_shift(0),
- m_oldval(field.defvalue())
+ : m_field(field)
+ , m_shift(0)
+ , m_oldval(field.defvalue())
{
// fill in the data
for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1)
@@ -3255,45 +3523,36 @@ void dynamic_field::write(ioport_value newval)
//-------------------------------------------------
analog_field::analog_field(ioport_field &field)
- : m_field(field),
- m_shift(0),
- m_adjdefvalue(field.defvalue() & field.mask()),
- m_adjmin(field.minval() & field.mask()),
- m_adjmax(field.maxval() & field.mask()),
- m_sensitivity(field.sensitivity()),
- m_reverse(field.analog_reverse()),
- m_delta(field.delta()),
- m_centerdelta(field.centerdelta()),
- m_accum(0),
- m_previous(0),
- m_previousanalog(0),
- m_prog_analog_value(0),
- m_minimum(INPUT_ABSOLUTE_MIN),
- m_maximum(INPUT_ABSOLUTE_MAX),
- m_center(0),
- m_reverse_val(0),
- m_scalepos(0),
- m_scaleneg(0),
- m_keyscalepos(0),
- m_keyscaleneg(0),
- m_positionalscale(0),
- m_absolute(false),
- m_wraps(false),
- m_autocenter(false),
- m_single_scale(false),
- m_interpolate(false),
- m_lastdigital(false),
- m_was_written(false)
-{
- // compute the shift amount and number of bits
- for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1)
- m_shift++;
-
- // initialize core data
- m_adjdefvalue >>= m_shift;
- m_adjmin >>= m_shift;
- m_adjmax >>= m_shift;
-
+ : m_field(field)
+ , m_shift(compute_shift(field.mask()))
+ , m_adjdefvalue((field.defvalue() & field.mask()) >> m_shift)
+ , m_adjmin((field.minval() & field.mask()) >> m_shift)
+ , m_adjmax((field.maxval() & field.mask()) >> m_shift)
+ , m_adjoverride((field.defvalue() & field.mask()) >> m_shift)
+ , m_sensitivity(field.sensitivity())
+ , m_reverse(field.analog_reverse())
+ , m_delta(field.delta())
+ , m_centerdelta(field.centerdelta())
+ , m_accum(0)
+ , m_previous(0)
+ , m_previousanalog(0)
+ , m_minimum(osd::input_device::ABSOLUTE_MIN)
+ , m_maximum(osd::input_device::ABSOLUTE_MAX)
+ , m_center(0)
+ , m_reverse_val(0)
+ , m_scalepos(0)
+ , m_scaleneg(0)
+ , m_keyscalepos(0)
+ , m_keyscaleneg(0)
+ , m_positionalscale(0)
+ , m_absolute(false)
+ , m_wraps(false)
+ , m_autocenter(false)
+ , m_single_scale(false)
+ , m_interpolate(false)
+ , m_lastdigital(false)
+ , m_use_adjoverride(false)
+{
// set basic parameters based on the configured type
switch (field.type())
{
@@ -3312,7 +3571,7 @@ analog_field::analog_field(ioport_field &field)
case IPT_PEDAL:
case IPT_PEDAL2:
case IPT_PEDAL3:
- m_center = INPUT_ABSOLUTE_MIN;
+ m_center = osd::input_device::ABSOLUTE_MIN;
m_accum = apply_inverse_sensitivity(m_center);
m_absolute = true;
m_autocenter = true;
@@ -3331,7 +3590,7 @@ analog_field::analog_field(ioport_field &field)
// set each position to be 512 units
case IPT_POSITIONAL:
case IPT_POSITIONAL_V:
- m_positionalscale = compute_scale(field.maxval(), INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+ m_positionalscale = compute_scale(field.maxval(), osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN);
m_adjmin = 0;
m_adjmax = field.maxval() - 1;
m_wraps = field.analog_wraps();
@@ -3357,21 +3616,23 @@ analog_field::analog_field(ioport_field &field)
fatalerror("Unknown analog port type -- don't know if it is absolute or not\n");
}
- // further processing for absolute controls
if (m_absolute)
{
+ // further processing for absolute controls
+
// if the default value is pegged at the min or max, use a single scale value for the whole axis
m_single_scale = (m_adjdefvalue == m_adjmin) || (m_adjdefvalue == m_adjmax);
// if not "single scale", compute separate scales for each side of the default
if (!m_single_scale)
{
- // unsigned
- m_scalepos = compute_scale(m_adjmax - m_adjdefvalue, INPUT_ABSOLUTE_MAX - 0);
- m_scaleneg = compute_scale(m_adjdefvalue - m_adjmin, 0 - INPUT_ABSOLUTE_MIN);
-
- if (m_adjmin > m_adjmax)
- m_scaleneg = -m_scaleneg;
+ // unsigned, potentially passing through zero
+ m_scalepos = compute_scale(
+ (m_adjmax - m_adjdefvalue) & (field.mask() >> m_shift),
+ osd::input_device::ABSOLUTE_MAX);
+ m_scaleneg = compute_scale(
+ (m_adjdefvalue - m_adjmin) & (field.mask() >> m_shift),
+ -osd::input_device::ABSOLUTE_MIN);
// reverse point is at center
m_reverse_val = 0;
@@ -3379,7 +3640,7 @@ analog_field::analog_field(ioport_field &field)
else
{
// single axis that increases from default
- m_scalepos = compute_scale(m_adjmax - m_adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+ m_scalepos = compute_scale(m_adjmax - m_adjmin, osd::input_device::ABSOLUTE_MAX - osd::input_device::ABSOLUTE_MIN);
// make the scaling the same for easier coding when we need to scale
m_scaleneg = m_scalepos;
@@ -3388,11 +3649,11 @@ analog_field::analog_field(ioport_field &field)
m_reverse_val = m_maximum;
}
}
-
- // relative and positional controls all map directly with a 512x scale factor
else
{
- // The relative code is set up to allow specifing PORT_MINMAX and default values.
+ // relative and positional controls all map directly with a 512x scale factor
+
+ // The relative code is set up to allow specifying PORT_MINMAX and default values.
// The validity checks are purposely set up to not allow you to use anything other
// a default of 0 and PORT_MINMAX(0,mask). This is in case the need arises to use
// this feature in the future. Keeping the code in does not hurt anything.
@@ -3403,15 +3664,17 @@ analog_field::analog_field(ioport_field &field)
if (m_wraps)
m_adjmax++;
- m_minimum = (m_adjmin - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
- m_maximum = (m_adjmax - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
+ m_minimum = (m_adjmin - m_adjdefvalue) * osd::input_device::RELATIVE_PER_PIXEL;
+ m_maximum = (m_adjmax - m_adjdefvalue) * osd::input_device::RELATIVE_PER_PIXEL;
// make the scaling the same for easier coding when we need to scale
- m_scaleneg = m_scalepos = compute_scale(1, INPUT_RELATIVE_PER_PIXEL);
+ m_scaleneg = m_scalepos = compute_scale(1, osd::input_device::RELATIVE_PER_PIXEL);
if (m_field.analog_reset())
+ {
// delta values reverse from center
m_reverse_val = 0;
+ }
else
{
// positional controls reverse from their max range
@@ -3420,11 +3683,11 @@ analog_field::analog_field(ioport_field &field)
// relative controls reverse from 1 past their max range
if (m_wraps)
{
- // FIXME: positional needs -1, using INPUT_RELATIVE_PER_PIXEL skips a position (and reads outside the table array)
- if(field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V)
- m_reverse_val --;
+ // FIXME: positional needs -1, using osd::input_device::RELATIVE_PER_PIXEL skips a position (and reads outside the table array)
+ if (field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V)
+ m_reverse_val--;
else
- m_reverse_val -= INPUT_RELATIVE_PER_PIXEL;
+ m_reverse_val -= osd::input_device::RELATIVE_PER_PIXEL;
}
}
}
@@ -3497,7 +3760,7 @@ s32 analog_field::apply_settings(s32 value) const
else if (m_single_scale)
// it's a pedal or the default value is equal to min/max
// so we need to adjust the center to the minimum
- value -= INPUT_ABSOLUTE_MIN;
+ value -= osd::input_device::ABSOLUTE_MIN;
// map differently for positive and negative values
if (value >= 0)
@@ -3523,16 +3786,28 @@ s32 analog_field::apply_settings(s32 value) const
//-------------------------------------------------
-// set_value - take a new value to be used
-// at next frame update
+// set_value - override the value that will be
+// read from the field
//-------------------------------------------------
void analog_field::set_value(s32 value)
{
- m_was_written = true;
- m_prog_analog_value = value;
+ m_use_adjoverride = true;
+ m_adjoverride = std::clamp(value, m_adjmin, m_adjmax);
+}
+
+
+//-------------------------------------------------
+// clear_value - clear programmatic override
+//-------------------------------------------------
+
+void analog_field::clear_value()
+{
+ m_use_adjoverride = false;
+ m_adjoverride = m_adjdefvalue;
}
+
//-------------------------------------------------
// frame_update - update the internals of a
// single analog field periodically
@@ -3551,13 +3826,6 @@ void analog_field::frame_update(running_machine &machine)
input_item_class itemclass;
s32 rawvalue = machine.input().seq_axis_value(m_field.seq(SEQ_TYPE_STANDARD), itemclass);
- // use programmatically set value if available
- if (m_was_written)
- {
- m_was_written = false;
- rawvalue = m_prog_analog_value;
- }
-
// if we got an absolute input, it overrides everything else
if (itemclass == ITEM_CLASS_ABSOLUTE)
{
@@ -3597,7 +3865,7 @@ void analog_field::frame_update(running_machine &machine)
// if port is positional, we will take the full analog control and divide it
// into positions, that way as the control is moved full scale,
// it moves through all the positions
- rawvalue = apply_scale(rawvalue - INPUT_ABSOLUTE_MIN, m_positionalscale) * INPUT_RELATIVE_PER_PIXEL + m_minimum;
+ rawvalue = apply_scale(rawvalue - osd::input_device::ABSOLUTE_MIN, m_positionalscale) * osd::input_device::RELATIVE_PER_PIXEL + m_minimum;
// clamp the high value so it does not roll over
rawvalue = std::min(rawvalue, m_maximum);
@@ -3703,6 +3971,13 @@ void analog_field::read(ioport_value &result)
if (!m_field.enabled())
return;
+ // if set programmatically, only use the override value
+ if (m_use_adjoverride)
+ {
+ result = m_adjoverride;
+ return;
+ }
+
// start with the raw value
s32 value = m_accum;
diff --git a/src/emu/ioport.h b/src/emu/ioport.h
index c767d44c250..bbff70db21d 100644
--- a/src/emu/ioport.h
+++ b/src/emu/ioport.h
@@ -17,12 +17,15 @@
#ifndef MAME_EMU_IOPORT_H
#define MAME_EMU_IOPORT_H
+#include "inpttype.h"
+
#include "ioprocs.h"
#include <array>
#include <cstdint>
#include <cstring>
#include <ctime>
+#include <initializer_list>
#include <list>
#include <memory>
#include <vector>
@@ -32,9 +35,6 @@
// CONSTANTS
//**************************************************************************
-// input ports support up to 32 bits each
-typedef u32 ioport_value;
-
// active high/low values for input ports
constexpr ioport_value IP_ACTIVE_HIGH = 0x00000000;
constexpr ioport_value IP_ACTIVE_LOW = 0xffffffff;
@@ -51,18 +51,6 @@ constexpr char32_t UCHAR_SHIFT_END = UCHAR_SHIFT_2;
constexpr char32_t UCHAR_MAMEKEY_BEGIN = UCHAR_PRIVATE + 2;
-// sequence types for input_port_seq() call
-enum input_seq_type
-{
- SEQ_TYPE_INVALID = -1,
- SEQ_TYPE_STANDARD = 0,
- SEQ_TYPE_INCREMENT,
- SEQ_TYPE_DECREMENT,
- SEQ_TYPE_TOTAL
-};
-DECLARE_ENUM_INCDEC_OPERATORS(input_seq_type)
-
-
// crosshair types
enum crosshair_axis_t
{
@@ -92,323 +80,6 @@ enum ioport_group
};
-// various input port types
-enum ioport_type
-{
- // pseudo-port types
- IPT_INVALID = 0,
- IPT_UNUSED,
- IPT_END,
- IPT_UNKNOWN,
- IPT_PORT,
- IPT_DIPSWITCH,
- IPT_CONFIG,
-
- // start buttons
- IPT_START1,
- IPT_START2,
- IPT_START3,
- IPT_START4,
- IPT_START5,
- IPT_START6,
- IPT_START7,
- IPT_START8,
- IPT_START9,
- IPT_START10,
-
- // coin slots
- IPT_COIN1,
- IPT_COIN2,
- IPT_COIN3,
- IPT_COIN4,
- IPT_COIN5,
- IPT_COIN6,
- IPT_COIN7,
- IPT_COIN8,
- IPT_COIN9,
- IPT_COIN10,
- IPT_COIN11,
- IPT_COIN12,
- IPT_BILL1,
-
- // service coin
- IPT_SERVICE1,
- IPT_SERVICE2,
- IPT_SERVICE3,
- IPT_SERVICE4,
-
- // tilt inputs
- IPT_TILT1,
- IPT_TILT2,
- IPT_TILT3,
- IPT_TILT4,
-
- // misc other digital inputs
- IPT_POWER_ON,
- IPT_POWER_OFF,
- IPT_SERVICE,
- IPT_TILT,
- IPT_INTERLOCK,
- IPT_MEMORY_RESET,
- IPT_VOLUME_UP,
- IPT_VOLUME_DOWN,
- IPT_START, // use the numbered start button(s) for coin-ops
- IPT_SELECT,
- IPT_KEYPAD,
- IPT_KEYBOARD,
-
- // digital joystick inputs
- IPT_DIGITAL_JOYSTICK_FIRST,
-
- // use IPT_JOYSTICK for panels where the player has one single joystick
- IPT_JOYSTICK_UP,
- IPT_JOYSTICK_DOWN,
- IPT_JOYSTICK_LEFT,
- IPT_JOYSTICK_RIGHT,
-
- // use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels
- IPT_JOYSTICKRIGHT_UP,
- IPT_JOYSTICKRIGHT_DOWN,
- IPT_JOYSTICKRIGHT_LEFT,
- IPT_JOYSTICKRIGHT_RIGHT,
- IPT_JOYSTICKLEFT_UP,
- IPT_JOYSTICKLEFT_DOWN,
- IPT_JOYSTICKLEFT_LEFT,
- IPT_JOYSTICKLEFT_RIGHT,
-
- IPT_DIGITAL_JOYSTICK_LAST,
-
- // action buttons
- IPT_BUTTON1,
- IPT_BUTTON2,
- IPT_BUTTON3,
- IPT_BUTTON4,
- IPT_BUTTON5,
- IPT_BUTTON6,
- IPT_BUTTON7,
- IPT_BUTTON8,
- IPT_BUTTON9,
- IPT_BUTTON10,
- IPT_BUTTON11,
- IPT_BUTTON12,
- IPT_BUTTON13,
- IPT_BUTTON14,
- IPT_BUTTON15,
- IPT_BUTTON16,
-
- // mahjong inputs
- IPT_MAHJONG_FIRST,
-
- IPT_MAHJONG_A,
- IPT_MAHJONG_B,
- IPT_MAHJONG_C,
- IPT_MAHJONG_D,
- IPT_MAHJONG_E,
- IPT_MAHJONG_F,
- IPT_MAHJONG_G,
- IPT_MAHJONG_H,
- IPT_MAHJONG_I,
- IPT_MAHJONG_J,
- IPT_MAHJONG_K,
- IPT_MAHJONG_L,
- IPT_MAHJONG_M,
- IPT_MAHJONG_N,
- IPT_MAHJONG_O,
- IPT_MAHJONG_P,
- IPT_MAHJONG_Q,
- IPT_MAHJONG_KAN,
- IPT_MAHJONG_PON,
- IPT_MAHJONG_CHI,
- IPT_MAHJONG_REACH,
- IPT_MAHJONG_RON,
- IPT_MAHJONG_FLIP_FLOP,
- IPT_MAHJONG_BET,
- IPT_MAHJONG_SCORE,
- IPT_MAHJONG_DOUBLE_UP,
- IPT_MAHJONG_BIG,
- IPT_MAHJONG_SMALL,
- IPT_MAHJONG_LAST_CHANCE,
-
- IPT_MAHJONG_LAST,
-
- // hanafuda inputs
- IPT_HANAFUDA_FIRST,
-
- IPT_HANAFUDA_A,
- IPT_HANAFUDA_B,
- IPT_HANAFUDA_C,
- IPT_HANAFUDA_D,
- IPT_HANAFUDA_E,
- IPT_HANAFUDA_F,
- IPT_HANAFUDA_G,
- IPT_HANAFUDA_H,
- IPT_HANAFUDA_YES,
- IPT_HANAFUDA_NO,
-
- IPT_HANAFUDA_LAST,
-
- // gambling inputs
- IPT_GAMBLING_FIRST,
-
- IPT_GAMBLE_KEYIN, // attendant
- IPT_GAMBLE_KEYOUT, // attendant
- IPT_GAMBLE_SERVICE, // attendant
- IPT_GAMBLE_BOOK, // attendant
- IPT_GAMBLE_DOOR, // attendant
- // IPT_GAMBLE_DOOR2, // many gambling games have several doors.
- // IPT_GAMBLE_DOOR3,
- // IPT_GAMBLE_DOOR4,
- // IPT_GAMBLE_DOOR5,
-
- IPT_GAMBLE_PAYOUT, // player
- IPT_GAMBLE_BET, // player
- IPT_GAMBLE_DEAL, // player
- IPT_GAMBLE_STAND, // player
- IPT_GAMBLE_TAKE, // player
- IPT_GAMBLE_D_UP, // player
- IPT_GAMBLE_HALF, // player
- IPT_GAMBLE_HIGH, // player
- IPT_GAMBLE_LOW, // player
-
- // poker-specific inputs
- IPT_POKER_HOLD1,
- IPT_POKER_HOLD2,
- IPT_POKER_HOLD3,
- IPT_POKER_HOLD4,
- IPT_POKER_HOLD5,
- IPT_POKER_CANCEL,
-
- // slot-specific inputs
- IPT_SLOT_STOP1,
- IPT_SLOT_STOP2,
- IPT_SLOT_STOP3,
- IPT_SLOT_STOP4,
- IPT_SLOT_STOP_ALL,
-
- IPT_GAMBLING_LAST,
-
- // analog inputs
- IPT_ANALOG_FIRST,
-
- IPT_ANALOG_ABSOLUTE_FIRST,
-
- IPT_AD_STICK_X, // absolute // autocenter
- IPT_AD_STICK_Y, // absolute // autocenter
- IPT_AD_STICK_Z, // absolute // autocenter
- IPT_PADDLE, // absolute // autocenter
- IPT_PADDLE_V, // absolute // autocenter
- IPT_PEDAL, // absolute // autocenter
- IPT_PEDAL2, // absolute // autocenter
- IPT_PEDAL3, // absolute // autocenter
- IPT_LIGHTGUN_X, // absolute
- IPT_LIGHTGUN_Y, // absolute
- IPT_POSITIONAL, // absolute // autocenter if not wraps
- IPT_POSITIONAL_V, // absolute // autocenter if not wraps
-
- IPT_ANALOG_ABSOLUTE_LAST,
-
- IPT_DIAL, // relative
- IPT_DIAL_V, // relative
- IPT_TRACKBALL_X, // relative
- IPT_TRACKBALL_Y, // relative
- IPT_MOUSE_X, // relative
- IPT_MOUSE_Y, // relative
-
- IPT_ANALOG_LAST,
-
- // analog adjuster support
- IPT_ADJUSTER,
-
- // the following are special codes for user interface handling - not to be used by drivers!
- IPT_UI_FIRST,
-
- IPT_UI_CONFIGURE,
- IPT_UI_ON_SCREEN_DISPLAY,
- IPT_UI_DEBUG_BREAK,
- IPT_UI_PAUSE,
- IPT_UI_PAUSE_SINGLE,
- IPT_UI_REWIND_SINGLE,
- IPT_UI_RESET_MACHINE,
- IPT_UI_SOFT_RESET,
- IPT_UI_SHOW_GFX,
- IPT_UI_FRAMESKIP_DEC,
- IPT_UI_FRAMESKIP_INC,
- IPT_UI_THROTTLE,
- IPT_UI_FAST_FORWARD,
- IPT_UI_SHOW_FPS,
- IPT_UI_SNAPSHOT,
- IPT_UI_RECORD_MNG,
- IPT_UI_RECORD_AVI,
- IPT_UI_TOGGLE_CHEAT,
- IPT_UI_UP,
- IPT_UI_DOWN,
- IPT_UI_LEFT,
- IPT_UI_RIGHT,
- IPT_UI_HOME,
- IPT_UI_END,
- IPT_UI_PAGE_UP,
- IPT_UI_PAGE_DOWN,
- IPT_UI_FOCUS_NEXT,
- IPT_UI_FOCUS_PREV,
- IPT_UI_SELECT,
- IPT_UI_CANCEL,
- IPT_UI_DISPLAY_COMMENT,
- IPT_UI_CLEAR,
- IPT_UI_ZOOM_IN,
- IPT_UI_ZOOM_OUT,
- IPT_UI_ZOOM_DEFAULT,
- IPT_UI_PREV_GROUP,
- IPT_UI_NEXT_GROUP,
- IPT_UI_ROTATE,
- IPT_UI_SHOW_PROFILER,
- IPT_UI_TOGGLE_UI,
- IPT_UI_RELEASE_POINTER,
- IPT_UI_PASTE,
- IPT_UI_SAVE_STATE,
- IPT_UI_LOAD_STATE,
- IPT_UI_TAPE_START,
- IPT_UI_TAPE_STOP,
- IPT_UI_DATS,
- IPT_UI_FAVORITES,
- IPT_UI_EXPORT,
- IPT_UI_AUDIT,
-
- // additional OSD-specified UI port types (up to 16)
- IPT_OSD_1,
- IPT_OSD_2,
- IPT_OSD_3,
- IPT_OSD_4,
- IPT_OSD_5,
- IPT_OSD_6,
- IPT_OSD_7,
- IPT_OSD_8,
- IPT_OSD_9,
- IPT_OSD_10,
- IPT_OSD_11,
- IPT_OSD_12,
- IPT_OSD_13,
- IPT_OSD_14,
- IPT_OSD_15,
- IPT_OSD_16,
-
- IPT_UI_LAST,
-
- IPT_OTHER, // not mapped to standard defaults
-
- IPT_SPECIAL, // uninterpreted characters
- IPT_CUSTOM, // handled by custom code
- IPT_OUTPUT,
-
- IPT_COUNT
-};
-DECLARE_ENUM_INCDEC_OPERATORS(ioport_type)
-// aliases for some types
-#define IPT_PADDLE_H IPT_PADDLE
-#define IPT_PEDAL1 IPT_PEDAL
-#define IPT_POSITIONAL_H IPT_POSITIONAL
-#define IPT_DIAL_H IPT_DIAL
-
-
// input type classes
enum ioport_type_class
{
@@ -662,116 +333,6 @@ typedef device_delegate<void (ioport_field &, u32, ioport_value, ioport_value)>
typedef device_delegate<float (float)> ioport_field_crossmap_delegate;
-// ======================> inp_header
-
-// header at the front of INP files
-class inp_header
-{
-public:
- // parameters
- static constexpr unsigned MAJVERSION = 3;
- static constexpr unsigned MINVERSION = 0;
-
- bool read(emu_file &f)
- {
- return f.read(m_data, sizeof(m_data)) == sizeof(m_data);
- }
- bool write(emu_file &f) const
- {
- return f.write(m_data, sizeof(m_data)) == sizeof(m_data);
- }
-
- bool check_magic() const
- {
- return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC);
- }
- u64 get_basetime() const
- {
- return
- (u64(m_data[OFFS_BASETIME + 0]) << (0 * 8)) |
- (u64(m_data[OFFS_BASETIME + 1]) << (1 * 8)) |
- (u64(m_data[OFFS_BASETIME + 2]) << (2 * 8)) |
- (u64(m_data[OFFS_BASETIME + 3]) << (3 * 8)) |
- (u64(m_data[OFFS_BASETIME + 4]) << (4 * 8)) |
- (u64(m_data[OFFS_BASETIME + 5]) << (5 * 8)) |
- (u64(m_data[OFFS_BASETIME + 6]) << (6 * 8)) |
- (u64(m_data[OFFS_BASETIME + 7]) << (7 * 8));
- }
- unsigned get_majversion() const
- {
- return m_data[OFFS_MAJVERSION];
- }
- unsigned get_minversion() const
- {
- return m_data[OFFS_MINVERSION];
- }
- std::string get_sysname() const
- {
- return get_string<OFFS_SYSNAME, OFFS_APPDESC>();
- }
- std::string get_appdesc() const
- {
- return get_string<OFFS_APPDESC, OFFS_END>();
- }
-
- void set_magic()
- {
- std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC);
- }
- void set_basetime(u64 time)
- {
- m_data[OFFS_BASETIME + 0] = u8((time >> (0 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 1] = u8((time >> (1 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 2] = u8((time >> (2 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 3] = u8((time >> (3 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 4] = u8((time >> (4 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 5] = u8((time >> (5 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 6] = u8((time >> (6 * 8)) & 0x00ff);
- m_data[OFFS_BASETIME + 7] = u8((time >> (7 * 8)) & 0x00ff);
- }
- void set_version()
- {
- m_data[OFFS_MAJVERSION] = MAJVERSION;
- m_data[OFFS_MINVERSION] = MINVERSION;
- }
- void set_sysname(std::string const &name)
- {
- set_string<OFFS_SYSNAME, OFFS_APPDESC>(name);
- }
- void set_appdesc(std::string const &desc)
- {
- set_string<OFFS_APPDESC, OFFS_END>(desc);
- }
-
-private:
- template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str)
- {
- std::size_t const used = (std::min<std::size_t>)(str.size() + 1, END - BEGIN);
- std::memcpy(m_data + BEGIN, str.c_str(), used);
- if ((END - BEGIN) > used)
- std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used);
- }
- template <std::size_t BEGIN, std::size_t END> std::string get_string() const
- {
- char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN);
- return std::string(begin, std::find(begin, reinterpret_cast<char const *>(m_data + END), '\0'));
- }
-
- static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes
- static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer)
- static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer)
- static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer)
- // 0x02 bytes reserved
- static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII)
- static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII)
- static constexpr std::size_t OFFS_END = 0x40;
-
- static u8 const MAGIC[OFFS_BASETIME - OFFS_MAGIC];
-
- u8 m_data[OFFS_END];
-};
-
-
// ======================> input_device_default
// device defined default input settings
@@ -798,7 +359,7 @@ public:
ioport_group group() const noexcept { return m_group; }
u8 player() const noexcept { return m_player; }
const char *token() const noexcept { return m_token; }
- const char *name() const noexcept { return m_name; }
+ std::string name() const;
input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) noexcept { return m_defseq[seqtype]; }
const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_defseq[seqtype]; }
const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_seq[seqtype]; }
@@ -1026,6 +587,7 @@ public:
u8 player() const { return m_player; }
bool digital_value() const { return m_digital_value; }
void set_value(ioport_value value);
+ void clear_value();
bool optional() const { return ((m_flags & FIELD_FLAG_OPTIONAL) != 0); }
bool cocktail() const { return ((m_flags & FIELD_FLAG_COCKTAIL) != 0); }
@@ -1037,7 +599,7 @@ public:
bool analog_invert() const { return ((m_flags & ANALOG_FLAG_INVERT) != 0); }
u8 impulse() const noexcept { return m_impulse; }
- const char *name() const;
+ std::string name() const;
const char *specific_name() const noexcept { return m_name; }
const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
@@ -1262,8 +824,9 @@ public:
float crosshair_read();
void frame_update(running_machine &machine);
- // setters
+ // programmatic override (for script bindings)
void set_value(s32 value);
+ void clear_value();
private:
// helpers
@@ -1276,10 +839,11 @@ private:
ioport_field & m_field; // pointer to the input field referenced
// adjusted values (right-justified and tweaked)
- u8 m_shift; // shift to align final value in the port
- s32 m_adjdefvalue; // adjusted default value from the config
+ u8 const m_shift; // shift to align final value in the port
+ s32 const m_adjdefvalue; // adjusted default value from the config
s32 m_adjmin; // adjusted minimum value from the config
s32 m_adjmax; // adjusted maximum value from the config
+ s32 m_adjoverride; // programmatically set adjusted value
// live values of configurable parameters
s32 m_sensitivity; // current live sensitivity (100=normal)
@@ -1291,7 +855,6 @@ private:
s32 m_accum; // accumulated value (including relative adjustments)
s32 m_previous; // previous adjusted value
s32 m_previousanalog; // previous analog value
- s32 m_prog_analog_value; // programmatically set analog value
// parameters for modifying live values
s32 m_minimum; // minimum adjusted value
@@ -1313,7 +876,7 @@ private:
bool m_single_scale; // scale joystick differently if default is between min/max
bool m_interpolate; // should we do linear interpolation for mid-frame reads?
bool m_lastdigital; // was the last modification caused by a digital form?
- bool m_was_written; // was the last modification caused programmatically?
+ bool m_use_adjoverride; // override what will be read from the field
};
@@ -1382,7 +945,7 @@ public:
// type helpers
const std::vector<input_type_entry> &types() const noexcept { return m_typelist; }
bool type_pressed(ioport_type type, int player = 0);
- const char *type_name(ioport_type type, u8 player) const noexcept;
+ std::string type_name(ioport_type type, u8 player) const;
ioport_group type_group(ioport_type type, int player) const noexcept;
const input_seq &type_seq(ioport_type type, int player = 0, input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
void set_type_seq(ioport_type type, int player, input_seq_type seqtype, const input_seq &newseq) noexcept;
@@ -1399,7 +962,7 @@ public:
private:
// internal helpers
void init_port_types();
- void init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame);
+ void init_autoselect_devices(std::initializer_list<ioport_type> types, std::string_view option, std::string_view ananame);
void frame_update_callback();
void frame_update();
@@ -1414,6 +977,7 @@ private:
bool load_default_config(int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]);
bool load_controller_config(util::xml::data_node const &portnode, int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]);
void load_system_config(util::xml::data_node const &portnode, int type, int player, const std::pair<input_seq, char const *> (&newseq)[SEQ_TYPE_TOTAL]);
+ void apply_device_defaults();
void save_config(config_type cfg_type, util::xml::data_node *parentnode);
bool save_this_input_field_type(ioport_type type);
@@ -1449,8 +1013,8 @@ private:
attoseconds_t m_last_delta_nsec; // nanoseconds that passed since the previous callback
// playback/record information
- emu_file m_record_file; // recording file (closed if not recording)
- emu_file m_playback_file; // playback file (closed if not recording)
+ std::unique_ptr<emu_file> m_record_file; // recording file (nullptr if not recording)
+ std::unique_ptr<emu_file> m_playback_file; // playback file (nullptr if not recording)
util::write_stream::ptr m_record_stream; // recording stream (nullptr if not recording)
util::read_stream::ptr m_playback_stream; // playback stream (nullptr if not recording)
u64 m_playback_accumulated_speed; // accumulated speed during playback
@@ -1458,6 +1022,7 @@ private:
// storage for inactive configuration
std::unique_ptr<util::xml::file> m_deselected_card_config;
+ bool m_applied_device_defaults;
};
@@ -1658,10 +1223,10 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s
configurer.field_set_crosshair(CROSSHAIR_AXIS_##axis, altaxis, scale, offset);
#define PORT_CROSSHAIR_MAPPER(_callback) \
- configurer.field_set_crossmapper(ioport_field_crossmap_delegate(_callback, #_callback, DEVICE_SELF, (device_t *)nullptr));
+ configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, DEVICE_SELF, _callback, #_callback));
#define PORT_CROSSHAIR_MAPPER_MEMBER(_device, _class, _member) \
- configurer.field_set_crossmapper(ioport_field_crossmap_delegate(&_class::_member, #_class "::" #_member, _device, (_class *)nullptr));
+ configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, _device, &_class::_member, #_class "::" #_member));
// how many optical counts for 1 full turn of the control
#define PORT_FULL_TURN_COUNT(_count) \
diff --git a/src/emu/layout/dualhovu.lay b/src/emu/layout/dualhovu.lay
index e4fdb3bf943..0cd46b2d5c7 100644
--- a/src/emu/layout/dualhovu.lay
+++ b/src/emu/layout/dualhovu.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<view name="Dual Over-Under">
diff --git a/src/emu/layout/dualhsxs.lay b/src/emu/layout/dualhsxs.lay
index 18a9eaf908a..f032d0fd48d 100644
--- a/src/emu/layout/dualhsxs.lay
+++ b/src/emu/layout/dualhsxs.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<view name="Dual Side-by-Side">
diff --git a/src/emu/layout/dualhuov.lay b/src/emu/layout/dualhuov.lay
index b03d7a93258..8a94ca43dc7 100644
--- a/src/emu/layout/dualhuov.lay
+++ b/src/emu/layout/dualhuov.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<view name="Dual Under-Over">
diff --git a/src/emu/layout/ex800.lay b/src/emu/layout/ex800.lay
index 013ea3c4e4c..208fa7bc890 100644
--- a/src/emu/layout/ex800.lay
+++ b/src/emu/layout/ex800.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
copyright-holders:Dirk Best
-->
<mamelayout version="2">
diff --git a/src/emu/layout/exorterm155.lay b/src/emu/layout/exorterm155.lay
index 9da2b5ed7ef..28bb61c0d68 100644
--- a/src/emu/layout/exorterm155.lay
+++ b/src/emu/layout/exorterm155.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
LEDs for the Motorola EXORterm 155
-->
diff --git a/src/emu/layout/generic.h b/src/emu/layout/generic.h
index 502e38e0765..4249c3ef68b 100644
--- a/src/emu/layout/generic.h
+++ b/src/emu/layout/generic.h
@@ -21,6 +21,9 @@
// no screens layouts
extern const internal_layout layout_noscreens; // for screenless systems
+// single screen layouts
+extern const internal_layout layout_monitors; // common monitor aspect ratios
+
// dual screen layouts
extern const internal_layout layout_dualhsxs; // dual 4:3 screens side-by-side
extern const internal_layout layout_dualhovu; // dual 4:3 screens above and below
diff --git a/src/emu/layout/hp9122c.lay b/src/emu/layout/hp9122c.lay
index 46c197908fc..418d8964fbf 100644
--- a/src/emu/layout/hp9122c.lay
+++ b/src/emu/layout/hp9122c.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
copyright-holders:Sven Schnelle
Hewlett-Packard HP 9122C floppy drive Layout
-->
diff --git a/src/emu/layout/ie15.lay b/src/emu/layout/ie15.lay
index 255e2022ef8..287fcbdf77a 100644
--- a/src/emu/layout/ie15.lay
+++ b/src/emu/layout/ie15.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
diff --git a/src/emu/layout/lx800.lay b/src/emu/layout/lx800.lay
index 90a7dbbc742..20303e50eab 100644
--- a/src/emu/layout/lx800.lay
+++ b/src/emu/layout/lx800.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
copyright-holders:Dirk Best
-->
<mamelayout version="2">
diff --git a/src/emu/layout/monitors.lay b/src/emu/layout/monitors.lay
new file mode 100644
index 00000000000..b7a4f82f75a
--- /dev/null
+++ b/src/emu/layout/monitors.lay
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+license:CC0-1.0
+-->
+<mamelayout version="2">
+ <view name="4:3 Standard">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="4" bottom="3" />
+ </screen>
+ </view>
+ <view name="3:4 Portrait">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="3" bottom="4" />
+ </screen>
+ </view>
+ <view name="5:4 Two-Page">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="5" bottom="4" />
+ </screen>
+ </view>
+ <view name="16:9 Widescreen">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="16" bottom="9" />
+ </screen>
+ </view>
+ <view name="21:9 UltraWide">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="21" bottom="9" />
+ </screen>
+ </view>
+ <view name="32:9 Super UltraWide">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="32" bottom="9" />
+ </screen>
+ </view>
+ <view name="1:1 Air Traffic Control">
+ <screen tag="screen">
+ <bounds left="0" top="0" right="32" bottom="9" />
+ </screen>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/nes_rob.lay b/src/emu/layout/nes_rob.lay
new file mode 100644
index 00000000000..c5b10747151
--- /dev/null
+++ b/src/emu/layout/nes_rob.lay
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!--
+license:CC0-1.0
+authors:hap
+-->
+<mamelayout version="2">
+
+<!-- define elements -->
+
+ <element name="text_m1"><text align="1" string="motor 1:"><color red="0.8" green="0.8" blue="0.8" /></text></element>
+ <element name="text_m2"><text align="1" string="motor 2:"><color red="0.8" green="0.8" blue="0.8" /></text></element>
+ <element name="text_m3"><text align="1" string="motor 3:"><color red="0.8" green="0.8" blue="0.8" /></text></element>
+
+ <element name="mstatus0">
+ <text state="1" align="1" string="DOWN"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="DOWN"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+ <element name="mstatus1">
+ <text state="1" align="1" string="UP"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="UP"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+ <element name="mstatus2">
+ <text state="1" align="1" string="CLOSE"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="CLOSE"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+ <element name="mstatus3">
+ <text state="1" align="1" string="OPEN"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="OPEN"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+ <element name="mstatus4">
+ <text state="1" align="1" string="RIGHT"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="RIGHT"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+ <element name="mstatus5">
+ <text state="1" align="1" string="LEFT"><color red="1.0" green="1.0" blue="0.2" /></text>
+ <text state="0" align="1" string="LEFT"><color red="0.2" green="0.2" blue="0.2" /></text>
+ </element>
+
+ <element name="led" defstate="0">
+ <disk state="1"><color red="1.0" green="0.1" blue="0.15" /></disk>
+ <disk state="0"><color red="0.15" green="0.015" blue="0.017" /></disk>
+ </element>
+
+
+<!-- build screen -->
+
+ <view name="Internal Layout">
+ <bounds left="4.5" right="17" top="7" bottom="14.25" />
+
+ <element ref="text_m1"><bounds x="5.5" y="10" width="5" height="1" /></element>
+ <element ref="text_m2"><bounds x="5.5" y="11.25" width="5" height="1" /></element>
+ <element ref="text_m3"><bounds x="5.5" y="12.5" width="5" height="1" /></element>
+
+ <element name="rob_motor.1" ref="mstatus1"><bounds x="10" y="10" width="5" height="1" /></element>
+ <element name="rob_motor.0" ref="mstatus0"><bounds x="13.5" y="10" width="5" height="1" /></element>
+ <element name="rob_motor.5" ref="mstatus5"><bounds x="10" y="11.25" width="5" height="1" /></element>
+ <element name="rob_motor.4" ref="mstatus4"><bounds x="13.5" y="11.25" width="5" height="1" /></element>
+ <element name="rob_motor.2" ref="mstatus2"><bounds x="10" y="12.5" width="5" height="1" /></element>
+ <element name="rob_motor.3" ref="mstatus3"><bounds x="13.5" y="12.5" width="5" height="1" /></element>
+
+ <element name="rob_led" ref="led"><bounds x="10" y="8" width="1" height="1" /></element>
+
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/noscreens.lay b/src/emu/layout/noscreens.lay
index 39913376cbb..e74d12e31a5 100644
--- a/src/emu/layout/noscreens.lay
+++ b/src/emu/layout/noscreens.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<element name="warning">
@@ -9,9 +9,9 @@ license:CC0
</text>
</element>
<view name="No screens attached">
- <bounds left="0" top="0" right="280" bottom="150" />
+ <bounds left="0" top="0" right="400" bottom="300" />
<element name="warning_txt" ref="warning">
- <bounds left="50" right="230" top="50" bottom="65" />
+ <bounds xc="200" yc="150" width="400" height="25" />
</element>
</view>
</mamelayout>
diff --git a/src/emu/layout/quadhsxs.lay b/src/emu/layout/quadhsxs.lay
index 1da154bb024..d8f776cb238 100644
--- a/src/emu/layout/quadhsxs.lay
+++ b/src/emu/layout/quadhsxs.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<view name="Quad Side-by-Side">
diff --git a/src/emu/layout/qx10ascii.lay b/src/emu/layout/qx10ascii.lay
new file mode 100644
index 00000000000..c00c7c88876
--- /dev/null
+++ b/src/emu/layout/qx10ascii.lay
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!--
+license:CC0-1.0
+-->
+<mamelayout version="2">
+ <element name="led" defstate="1">
+ <disk state="0">
+ <color red="0.75" green="0.0" blue="0.0" />
+ </disk>
+ <disk state="1">
+ <color red="0.20" green="0.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <element name="capslock">
+ <text string="CAPS">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="insert">
+ <text string="INS">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf1">
+ <text string="SF1">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf2">
+ <text string="SF2">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf3">
+ <text string="SF3">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf4">
+ <text string="SF4">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+
+ <view name="Default Layout">
+ <screen index="0">
+ <bounds x="0" y="30" width="640" height="480" />
+ </screen>
+
+ <element name="led0" ref="led">
+ <bounds x="33" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led2" ref="led">
+ <bounds x="53" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led7" ref="led">
+ <bounds x="83" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led6" ref="led">
+ <bounds x="103" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led5" ref="led">
+ <bounds x="123" y="17" width="10" height="10" />
+ </element>
+ <element name="led4" ref="led">
+ <bounds x="143" y="17" width="10" height="10" />
+ </element>
+
+ <element name="label1" ref="capslock">
+ <bounds x="31" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label2" ref="insert">
+ <bounds x="51" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label3" ref="sf1">
+ <bounds x="81" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label4" ref="sf2">
+ <bounds x="101" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label5" ref="sf3">
+ <bounds x="121" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label6" ref="sf4">
+ <bounds x="141" y="0" width="15" height="15" />
+ </element>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/qx10hasci.lay b/src/emu/layout/qx10hasci.lay
new file mode 100644
index 00000000000..f0dadc6a0fa
--- /dev/null
+++ b/src/emu/layout/qx10hasci.lay
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!--
+license:CC0-1.0
+-->
+<mamelayout version="2">
+ <element name="led" defstate="1">
+ <disk state="0">
+ <color red="0.75" green="0.0" blue="0.0" />
+ </disk>
+ <disk state="1">
+ <color red="0.20" green="0.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <element name="capslock">
+ <text string="CAPS">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="insert">
+ <text string="INS">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf1">
+ <text string="CALC">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf2">
+ <text string="SCHED">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+ <element name="sf3">
+ <text string="DRAW">
+ <color red="1.0" green="1.0" blue="1.0" />
+ </text>
+ </element>
+
+ <view name="Default Layout">
+ <screen index="0">
+ <bounds x="0" y="30" width="640" height="480" />
+ </screen>
+
+ <element name="led3" ref="led">
+ <bounds x="33" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led2" ref="led">
+ <bounds x="53" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led7" ref="led">
+ <bounds x="83" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led6" ref="led">
+ <bounds x="103" y="17" width="10" height="10" />
+ </element>
+
+ <element name="led5" ref="led">
+ <bounds x="123" y="17" width="10" height="10" />
+ </element>
+
+ <element name="label1" ref="capslock">
+ <bounds x="31" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label2" ref="insert">
+ <bounds x="51" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label3" ref="sf1">
+ <bounds x="81" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label4" ref="sf2">
+ <bounds x="101" y="0" width="15" height="15" />
+ </element>
+
+ <element name="label5" ref="sf3">
+ <bounds x="121" y="0" width="15" height="15" />
+ </element>
+ </view>
+</mamelayout>
diff --git a/src/emu/layout/smartboard.lay b/src/emu/layout/smartboard.lay
index 885f914ec67..1b028bc23fe 100644
--- a/src/emu/layout/smartboard.lay
+++ b/src/emu/layout/smartboard.lay
@@ -1,6 +1,7 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
+authors:Sandro Ronco, hap
-->
<mamelayout version="2">
@@ -12,7 +13,7 @@ license:CC0
<disk><color red="0.1" green="0.05" blue="0.07" /></disk>
</element>
<element name="ledr" defstate="0">
- <disk state="1"> <color red="1" green="0" blue="0" /> </disk>
+ <disk state="1"><color red="1" green="0" blue="0" /></disk>
</element>
<element name="piece" defstate="0">
@@ -84,22 +85,22 @@ license:CC0
<image file="chess/bp.svg" state="64"><color alpha="0.5" /></image>
</element>
- <element name="text_1"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="1"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_2"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="2"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_3"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="3"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_4"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="4"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_5"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="5"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_6"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="6"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_7"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="7"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_8"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="8"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_a"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="A"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_b"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="B"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_c"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="C"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_d"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="D"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_e"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="E"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_f"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="F"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_g"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="G"> <color red="1" green="1" blue="1" /></text> </element>
- <element name="text_h"> <rect><color red="0.56" green="0.33" blue="0.12" /></rect> <text string="H"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_1"> <text string="1"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_2"> <text string="2"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_3"> <text string="3"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_4"> <text string="4"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_5"> <text string="5"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_6"> <text string="6"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_7"> <text string="7"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_8"> <text string="8"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_a"> <text string="A"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_b"> <text string="B"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_c"> <text string="C"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_d"> <text string="D"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_e"> <text string="E"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_f"> <text string="F"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_g"> <text string="G"> <color red="1" green="1" blue="1" /></text> </element>
+ <element name="text_h"> <text string="H"> <color red="1" green="1" blue="1" /></text> </element>
<!-- sb board -->
@@ -317,43 +318,23 @@ license:CC0
<element name="text_uit1"><text string="S.BOARD"><color red="0.81" green="0.8" blue="0.79" /></text></element>
<element name="text_uit2"><text string="INTERFACE"><color red="0.81" green="0.8" blue="0.79" /></text></element>
<element name="text_uib1"><text string="BOARD:"><color red="0.81" green="0.8" blue="0.79" /></text></element>
- <element name="text_uib2">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string="RESET"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
- <element name="text_uib3">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string="CLEAR"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
+ <element name="text_uib2"><text string="RESET"><color red="0.01" green="0.01" blue="0.01" /></text></element>
+ <element name="text_uib3"><text string="CLEAR"><color red="0.01" green="0.01" blue="0.01" /></text></element>
<element name="text_uis1"><text string="SPAWN:"><color red="0.81" green="0.8" blue="0.79" /></text></element>
<element name="text_uih1"><text string="HAND:"><color red="0.81" green="0.8" blue="0.79" /></text></element>
- <element name="text_uih2">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string="REMOVE"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
+ <element name="text_uih2"><text string="REMOVE"><color red="0.01" green="0.01" blue="0.01" /></text></element>
<element name="text_uiu1"><text string="UNDO:"><color red="0.81" green="0.8" blue="0.79" /></text></element>
- <element name="text_uiu2a">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string=" &lt;&lt;"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
- <element name="text_uiu2b">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string=" &lt; "><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
- <element name="text_uiu2c">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string=" &gt;"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
- <element name="text_uiu2d">
- <rect><color red="0.84" green="0.75" blue="0.50" /></rect>
- <text string=" &gt;&gt;"><color red="0.01" green="0.01" blue="0.01" /></text>
- </element>
+ <element name="text_uiu2a"><text string=" &lt;&lt;"><color red="0.01" green="0.01" blue="0.01" /></text></element>
+ <element name="text_uiu2b"><text string=" &lt; "><color red="0.01" green="0.01" blue="0.01" /></text></element>
+ <element name="text_uiu2c"><text string=" &gt;"><color red="0.01" green="0.01" blue="0.01" /></text></element>
+ <element name="text_uiu2d"><text string=" &gt;&gt;"><color red="0.01" green="0.01" blue="0.01" /></text></element>
+ <element name="text_uiu3b"><text string="/"><color red="0.81" green="0.8" blue="0.79" /></text></element>
+
<element name="text_uiu3a" defstate="0">
<simplecounter maxstate="999" digits="1" align="2">
<color red="0.81" green="0.8" blue="0.79" />
</simplecounter>
</element>
- <element name="text_uiu3b"><text string="/"><color red="0.81" green="0.8" blue="0.79" /></text></element>
<element name="text_uiu3c" defstate="0">
<simplecounter maxstate="999" digits="1" align="1">
<color red="0.81" green="0.8" blue="0.79" />
diff --git a/src/emu/layout/triphsxs.lay b/src/emu/layout/triphsxs.lay
index 4988b808100..4d7c0733956 100644
--- a/src/emu/layout/triphsxs.lay
+++ b/src/emu/layout/triphsxs.lay
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-license:CC0
+license:CC0-1.0
-->
<mamelayout version="2">
<view name="Triple Side-by-Side">
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index b70ffb69931..573c1b9e095 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -10,26 +10,31 @@
#include "emu.h"
-#include "emuopts.h"
-#include "osdepend.h"
#include "config.h"
-#include "debugger.h"
-#include "render.h"
-#include "uiinput.h"
#include "crsshair.h"
-#include "debug/debugvw.h"
#include "debug/debugcpu.h"
+#include "debug/debugvw.h"
+#include "debugger.h"
#include "dirtc.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "http.h"
#include "image.h"
+#include "main.h"
+#include "natkeyboard.h"
#include "network.h"
+#include "render.h"
#include "romload.h"
#include "tilemap.h"
-#include "natkeyboard.h"
+#include "uiinput.h"
+
#include "ui/uimain.h"
#include "corestr.h"
#include "unzip.h"
+#include "osdepend.h"
+
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
@@ -55,29 +60,28 @@ osd_interface &running_machine::osd() const
//-------------------------------------------------
running_machine::running_machine(const machine_config &_config, machine_manager &manager)
- : m_side_effects_disabled(0),
- debug_flags(0),
- m_config(_config),
- m_system(_config.gamedrv()),
- m_manager(manager),
- m_current_phase(machine_phase::PREINIT),
- m_paused(false),
- m_hard_reset_pending(false),
- m_exit_pending(false),
- m_soft_reset_timer(nullptr),
- m_rand_seed(0x9d14abd7),
- m_ui_active(_config.options().ui_active()),
- m_basename(_config.gamedrv().name),
- m_sample_rate(_config.options().sample_rate()),
- m_saveload_schedule(saveload_schedule::NONE),
- m_saveload_schedule_time(attotime::zero),
- m_saveload_searchpath(nullptr),
-
- m_save(*this),
- m_memory(*this),
- m_ioport(*this),
- m_parameters(*this),
- m_scheduler(*this)
+ : m_side_effects_disabled(0)
+ , debug_flags(0)
+ , m_config(_config)
+ , m_system(_config.gamedrv())
+ , m_manager(manager)
+ , m_current_phase(machine_phase::PREINIT)
+ , m_paused(false)
+ , m_hard_reset_pending(false)
+ , m_exit_pending(false)
+ , m_soft_reset_timer(nullptr)
+ , m_rand_seed(0x9d14abd7)
+ , m_basename(_config.gamedrv().name)
+ , m_sample_rate(_config.options().sample_rate())
+ , m_saveload_schedule(saveload_schedule::NONE)
+ , m_saveload_schedule_time(attotime::zero)
+ , m_saveload_searchpath(nullptr)
+
+ , m_save(*this)
+ , m_memory(*this)
+ , m_ioport(*this)
+ , m_parameters(*this)
+ , m_scheduler(*this)
{
memset(&m_base_time, 0, sizeof(m_base_time));
@@ -120,7 +124,10 @@ std::string running_machine::describe_context() const
}
}
- return std::string("(no context)");
+ if (m_current_phase == machine_phase::RESET)
+ return std::string("(reset phase)");
+ else
+ return std::string("(no context)");
}
@@ -143,12 +150,13 @@ void running_machine::start()
// initialize UI input
m_ui_input = std::make_unique<ui_input_manager>(*this);
- // init the osd layer
+ // init the OSD layer
m_manager.osd().init(*this);
- // create the video manager
+ // create the video manager and UI manager
m_video = std::make_unique<video_manager>(*this);
m_ui = manager().create_ui(*this);
+ m_ui->set_startup_text("Initializing...", true);
// initialize the base time (needed for doing record/playback)
::time(&m_base_time);
@@ -318,7 +326,7 @@ int running_machine::run(bool quiet)
// run the CPUs until a reset or exit
while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != saveload_schedule::NONE)
{
- g_profiler.start(PROFILER_EXTRA);
+ auto profile = g_profiler.start(PROFILER_EXTRA);
// execute CPUs if not paused
if (!m_paused)
@@ -330,8 +338,6 @@ int running_machine::run(bool quiet)
// handle save/load
if (m_saveload_schedule != saveload_schedule::NONE)
handle_saveload();
-
- g_profiler.stop();
}
m_manager.http()->clear();
@@ -344,29 +350,29 @@ int running_machine::run(bool quiet)
nvram_save();
m_configuration->save_settings();
}
- catch (emu_fatalerror &fatal)
+ catch (emu_fatalerror const &fatal)
{
osd_printf_error("Fatal error: %s\n", fatal.what());
error = EMU_ERR_FATALERROR;
if (fatal.exitcode() != 0)
error = fatal.exitcode();
}
- catch (emu_exception &)
+ catch (emu_exception const &)
{
osd_printf_error("Caught unhandled emulator exception\n");
error = EMU_ERR_FATALERROR;
}
- catch (binding_type_exception &btex)
+ catch (binding_type_exception const &btex)
{
osd_printf_error("Error performing a late bind of function expecting type %s to instance of type %s\n", btex.target_type().name(), btex.actual_type().name());
error = EMU_ERR_FATALERROR;
}
- catch (tag_add_exception &aex)
+ catch (tag_add_exception const &aex)
{
osd_printf_error("Tag '%s' already exists in tagged map\n", aex.tag());
error = EMU_ERR_FATALERROR;
}
- catch (std::exception &ex)
+ catch (std::exception const &ex)
{
osd_printf_error("Caught unhandled %s exception: %s\n", typeid(ex).name(), ex.what());
error = EMU_ERR_FATALERROR;
@@ -589,10 +595,10 @@ void running_machine::schedule_save(std::string &&filename)
// immediate_save - save state.
//-------------------------------------------------
-void running_machine::immediate_save(const char *filename)
+void running_machine::immediate_save(std::string_view filename)
{
// specify the filename to save or load
- set_saveload_filename(filename);
+ set_saveload_filename(std::string(filename));
// set up some parameters for handle_saveload()
m_saveload_schedule = saveload_schedule::SAVE;
@@ -626,10 +632,10 @@ void running_machine::schedule_load(std::string &&filename)
// immediate_load - load state.
//-------------------------------------------------
-void running_machine::immediate_load(const char *filename)
+void running_machine::immediate_load(std::string_view filename)
{
// specify the filename to save or load
- set_saveload_filename(filename);
+ set_saveload_filename(std::string(filename));
// set up some parameters for handle_saveload()
m_saveload_schedule = saveload_schedule::LOAD;
@@ -857,6 +863,7 @@ void running_machine::handle_saveload()
if (!m_saveload_pending_file.empty())
{
const char *const opname = (m_saveload_schedule == saveload_schedule::LOAD) ? "load" : "save";
+ const char *const preposname = (m_saveload_schedule == saveload_schedule::LOAD) ? "from" : "to";
// if there are anonymous timers, we can't save just yet, and we can't load yet either
// because the timers might overwrite data we have loaded
@@ -864,7 +871,7 @@ void running_machine::handle_saveload()
{
// if more than a second has passed, we're probably screwed
if ((this->time() - m_saveload_schedule_time) > attotime::from_seconds(1))
- popmessage("Unable to %s due to pending anonymous timers. See error.log for details.", opname);
+ popmessage("Error: Unable to %s state %s %s due to pending anonymous timers. See error.log for details.", opname, preposname, m_saveload_pending_file);
else
return; // return without cancelling the operation
}
@@ -877,39 +884,36 @@ void running_machine::handle_saveload()
auto const filerr = file.open(m_saveload_pending_file);
if (!filerr)
{
- const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "loaded" : "saved";
-
// read/write the save state
save_error saverr = (m_saveload_schedule == saveload_schedule::LOAD) ? m_save.read_file(file) : m_save.write_file(file);
// handle the result
switch (saverr)
{
- case STATERR_ILLEGAL_REGISTRATIONS:
- popmessage("Error: Unable to %s state due to illegal registrations. See error.log for details.", opname);
- break;
-
case STATERR_INVALID_HEADER:
- popmessage("Error: Unable to %s state due to an invalid header. Make sure the save state is correct for this machine.", opname);
+ popmessage("Error: Unable to %s state %s %s due to an invalid header. Make sure the save state is correct for this system.", opname, preposname, m_saveload_pending_file);
break;
case STATERR_READ_ERROR:
- popmessage("Error: Unable to %s state due to a read error (file is likely corrupt).", opname);
+ popmessage("Error: Unable to %s state %s %s due to a read error (file is likely corrupt).", opname, preposname, m_saveload_pending_file);
break;
case STATERR_WRITE_ERROR:
- popmessage("Error: Unable to %s state due to a write error. Verify there is enough disk space.", opname);
+ popmessage("Error: Unable to %s state %s %s due to a write error. Verify there is enough disk space.", opname, preposname, m_saveload_pending_file);
break;
case STATERR_NONE:
+ {
+ const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "Loaded" : "Saved";
if (!(m_system.flags & MACHINE_SUPPORTS_SAVE))
- popmessage("State successfully %s.\nWarning: Save states are not officially supported for this machine.", opnamed);
+ popmessage("%s state %s %s.\nWarning: Save states are not officially supported for this system.", opnamed, preposname, m_saveload_pending_file);
else
- popmessage("State successfully %s.", opnamed);
+ popmessage("%s state %s %s.", opnamed, preposname, m_saveload_pending_file);
break;
+ }
default:
- popmessage("Error: Unknown error during state %s.", opnamed);
+ popmessage("Error: Unknown error during %s state %s %s.", opname, preposname, m_saveload_pending_file);
break;
}
@@ -920,11 +924,11 @@ void running_machine::handle_saveload()
else if ((openflags == OPEN_FLAG_READ) && (std::errc::no_such_file_or_directory == filerr))
{
// attempt to load a non-existent savestate, report empty slot
- popmessage("Error: No savestate file to load.", opname);
+ popmessage("Error: Load state file %s not found.", m_saveload_pending_file);
}
else
{
- popmessage("Error: Failed to open file for %s operation.", opname);
+ popmessage("Error: Failed to open %s for %s state operation.", m_saveload_pending_file, opname);
}
}
}
@@ -941,7 +945,7 @@ void running_machine::handle_saveload()
// of the system
//-------------------------------------------------
-void running_machine::soft_reset(void *ptr, s32 param)
+void running_machine::soft_reset(s32 param)
{
logerror("Soft reset\n");
@@ -972,6 +976,17 @@ void running_machine::logfile_callback(const char *buffer)
//-------------------------------------------------
+// steal_debuglogfile - relinquish ownership of
+// the debug.log file
+//-------------------------------------------------
+
+std::unique_ptr<emu_file> running_machine::steal_debuglogfile()
+{
+ return std::move(m_debuglogfile);
+}
+
+
+//-------------------------------------------------
// start_all_devices - start any unstarted devices
//-------------------------------------------------
@@ -1118,9 +1133,10 @@ void running_machine::nvram_load()
for (device_nvram_interface &nvram : nvram_interface_enumerator(root_device()))
{
emu_file file(options().nvram_directory(), OPEN_FLAG_READ);
- if (!file.open(nvram_filename(nvram.device())))
+ if (nvram.nvram_backup_enabled() && !file.open(nvram_filename(nvram.device())))
{
- nvram.nvram_load(file);
+ if (!nvram.nvram_load(file))
+ osd_printf_error("Error reading NVRAM file %s\n", file.filename());
file.close();
}
else
@@ -1142,7 +1158,17 @@ void running_machine::nvram_save()
emu_file file(options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (!file.open(nvram_filename(nvram.device())))
{
- nvram.nvram_save(file);
+ bool error = false;
+
+ if (!nvram.nvram_save(file))
+ {
+ error = true;
+ osd_printf_error("Error writing NVRAM file %s\n", file.filename());
+ }
+
+ // close and perhaps delete the file
+ if (error || file.size() == 0)
+ file.remove_on_close();
file.close();
}
}
@@ -1159,7 +1185,7 @@ void running_machine::popup_clear() const
ui().popup_time(0, " ");
}
-void running_machine::popup_message(util::format_argument_pack<std::ostream> const &args) const
+void running_machine::popup_message(util::format_argument_pack<char> const &args) const
{
std::string const temp(string_format(args));
ui().popup_time(temp.length() / 40 + 2, "%s", temp);
@@ -1281,7 +1307,7 @@ void running_machine::emscripten_main_loop()
{
running_machine *machine = emscripten_running_machine;
- g_profiler.start(PROFILER_EXTRA);
+ auto profile = g_profiler.start(PROFILER_EXTRA);
// execute CPUs if not paused
if (!machine->m_paused)
@@ -1314,8 +1340,6 @@ void running_machine::emscripten_main_loop()
{
emscripten_cancel_main_loop();
}
-
- g_profiler.stop();
}
void running_machine::emscripten_set_running_machine(running_machine *machine)
diff --git a/src/emu/machine.h b/src/emu/machine.h
index f3aef08d265..7b4efec70da 100644
--- a/src/emu/machine.h
+++ b/src/emu/machine.h
@@ -128,7 +128,7 @@ public:
sound_manager &sound() const { assert(m_sound != nullptr); return *m_sound; }
video_manager &video() const { assert(m_video != nullptr); return *m_video; }
network_manager &network() const { assert(m_network != nullptr); return *m_network; }
- bookkeeping_manager &bookkeeping() const { assert(m_network != nullptr); return *m_bookkeeping; }
+ bookkeeping_manager &bookkeeping() const { assert(m_bookkeeping != nullptr); return *m_bookkeeping; }
configuration_manager &configuration() const { assert(m_configuration != nullptr); return *m_configuration; }
output_manager &output() const { assert(m_output != nullptr); return *m_output; }
ui_manager &ui() const { assert(m_ui != nullptr); return *m_ui; }
@@ -145,7 +145,6 @@ public:
bool paused() const { return m_paused || (m_current_phase != machine_phase::RUNNING); }
bool exit_pending() const { return m_exit_pending; }
bool hard_reset_pending() const { return m_hard_reset_pending; }
- bool ui_active() const { return m_ui_active; }
const std::string &basename() const { return m_basename; }
int sample_rate() const { return m_sample_rate; }
bool save_or_load_pending() const { return !m_saveload_pending_file.empty(); }
@@ -172,13 +171,12 @@ public:
void add_notifier(machine_notification event, machine_notify_delegate callback, bool first = false);
void call_notifiers(machine_notification which);
void add_logerror_callback(logerror_callback callback);
- void set_ui_active(bool active) { m_ui_active = active; }
void debug_break();
void export_http_api();
// TODO: Do saves and loads still require scheduling?
- void immediate_save(const char *filename);
- void immediate_load(const char *filename);
+ void immediate_save(std::string_view filename);
+ void immediate_load(std::string_view filename);
// rewind operations
bool rewind_capture();
@@ -217,7 +215,7 @@ public:
bool debug_enabled() { return (debug_flags & DEBUG_FLAG_ENABLED) != 0; }
// used by debug_console to take ownership of the debug.log file
- std::unique_ptr<emu_file> steal_debuglogfile() { return std::move(m_debuglogfile); }
+ std::unique_ptr<emu_file> steal_debuglogfile();
private:
class side_effects_disabler {
@@ -248,12 +246,12 @@ private:
void start();
void set_saveload_filename(std::string &&filename);
void handle_saveload();
- void soft_reset(void *ptr = nullptr, s32 param = 0);
+ void soft_reset(s32 param = 0);
std::string nvram_filename(device_t &device) const;
void nvram_load();
void nvram_save();
void popup_clear() const;
- void popup_message(util::format_argument_pack<std::ostream> const &args) const;
+ void popup_message(util::format_argument_pack<char> const &args) const;
// internal callbacks
void logfile_callback(const char *buffer);
@@ -297,7 +295,6 @@ private:
// misc state
u32 m_rand_seed; // current random number seed
- bool m_ui_active; // ui active or not (useful for games / systems with keyboard inputs)
time_t m_base_time; // real time at initial emulation time
std::string m_basename; // basename used for game-related paths
int m_sample_rate; // the digital audio sample rate
@@ -400,7 +397,7 @@ inline void running_machine::logerror(Format &&fmt, Params &&... args) const
// process only if there is a target
if (allow_logging())
{
- g_profiler.start(PROFILER_LOGERROR);
+ auto profile = g_profiler.start(PROFILER_LOGERROR);
// dump to the buffer
m_string_buffer.clear();
@@ -409,9 +406,7 @@ inline void running_machine::logerror(Format &&fmt, Params &&... args) const
m_string_buffer.put('\0');
strlog(&m_string_buffer.vec()[0]);
-
- g_profiler.stop();
}
}
-#endif /* MAME_EMU_MACHINE_H */
+#endif // MAME_EMU_MACHINE_H
diff --git a/src/emu/main.cpp b/src/emu/main.cpp
index e5467238238..12cde5cf299 100644
--- a/src/emu/main.cpp
+++ b/src/emu/main.cpp
@@ -9,17 +9,32 @@
***************************************************************************/
#include "emu.h"
+#include "main.h"
+
#include "emuopts.h"
+#include "http.h"
+
-machine_manager::machine_manager(emu_options& options, osd_interface& osd)
- : m_osd(osd),
+machine_manager::machine_manager(emu_options& options, osd_interface& osd) :
+ m_osd(osd),
m_options(options),
m_machine(nullptr)
{
}
+
+machine_manager::~machine_manager()
+{
+}
+
+
void machine_manager::start_http_server()
{
m_http = std::make_unique<http_manager>(options().http(), options().http_port(), options().http_root());
}
+
+http_manager *machine_manager::http()
+{
+ return m_http.get();
+}
diff --git a/src/emu/main.h b/src/emu/main.h
index 3c75205de14..78553ca5236 100644
--- a/src/emu/main.h
+++ b/src/emu/main.h
@@ -6,18 +6,17 @@
Controls execution of the core emulator system.
***************************************************************************/
+#ifndef MAME_EMU_MAIN_H
+#define MAME_EMU_MAIN_H
#pragma once
-#ifndef __EMU_H__
-#error Dont include this file directly; include emu.h instead.
-#endif
+#include "emufwd.h"
-#ifndef MAME_EMU_MAIN_H
-#define MAME_EMU_MAIN_H
+#include <memory>
+#include <string>
+#include <vector>
-#include <thread>
-#include <ctime>
//**************************************************************************
// CONSTANTS
@@ -55,7 +54,7 @@ public:
static void display_ui_chooser(running_machine &machine);
static int start_frontend(emu_options &options, osd_interface &osd, std::vector<std::string> &args);
static int start_frontend(emu_options &options, osd_interface &osd, int argc, char *argv[]);
- static void draw_user_interface(running_machine& machine);
+ static bool draw_user_interface(running_machine& machine);
static void periodic_check();
static bool frame_hook();
static void sound_hook();
@@ -66,12 +65,13 @@ public:
class machine_manager
{
- DISABLE_COPYING(machine_manager);
protected:
// construction/destruction
- machine_manager(emu_options& options, osd_interface& osd);
+ machine_manager(emu_options &options, osd_interface &osd);
+ machine_manager(machine_manager const &) = delete;
+
public:
- virtual ~machine_manager() { }
+ virtual ~machine_manager();
osd_interface &osd() const { return m_osd; }
emu_options &options() const { return m_options; }
@@ -88,7 +88,7 @@ public:
virtual void update_machine() { }
- http_manager *http() { return m_http.get(); }
+ http_manager *http();
void start_http_server();
protected:
diff --git a/src/emu/mconfig.cpp b/src/emu/mconfig.cpp
index fb97c3138a3..2c8c1aa011b 100644
--- a/src/emu/mconfig.cpp
+++ b/src/emu/mconfig.cpp
@@ -257,24 +257,23 @@ std::pair<const char *, device_t *> machine_config::resolve_owner(const char *ta
device_t *owner(m_current_device);
// if the device path is absolute, start from the root
- if (tag[0] == ':')
- {
- tag++;
- owner = m_root_device.get();
- }
+ if (!*tag || (':' == *tag) || ('^' == *tag))
+ throw emu_fatalerror("Attempting to add device with tag containing parent references '%s'\n", orig_tag);
// go down the path until we're done with it
- while (strchr(tag, ':'))
+ char const *next;
+ while ((next = strchr(tag, ':')) != nullptr)
{
- const char *next = strchr(tag, ':');
assert(next != tag);
std::string_view part(tag, next - tag);
owner = owner->subdevices().find(part);
if (!owner)
- throw emu_fatalerror("Could not find %s when looking up path for device %s\n", part, orig_tag);
- tag = next+1;
+ throw emu_fatalerror("Could not find '%s' when looking up path for device '%s'\n", part, orig_tag);
+ tag = next + 1;
+ if ('^' == *tag)
+ throw emu_fatalerror("Attempting to add device with tag containing parent references '%s'\n", orig_tag);
}
- assert(tag[0] != '\0');
+ assert(*tag != '\0');
return std::make_pair(tag, owner);
}
@@ -296,7 +295,7 @@ std::tuple<const char *, device_t *, device_t *> machine_config::prepare_replace
if (old_device)
remove_references(*old_device);
else
- osd_printf_warning("Warning: attempting to replace non-existent device '%s'\n", tag);
+ throw emu_fatalerror("Attempting to replace non-existent device '%s'\n", tag);
return std::make_tuple(owner.first, owner.second, old_device);
}
diff --git a/src/emu/mconfig.h b/src/emu/mconfig.h
index c600ca06665..c6cacde581f 100644
--- a/src/emu/mconfig.h
+++ b/src/emu/mconfig.h
@@ -133,7 +133,7 @@ public:
/// replace an existing device.
/// \return A device replacement helper to pass to a device type
/// when replacing an existing device.
- emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace(*this); };
+ emu::detail::machine_config_replace replace() { return emu::detail::machine_config_replace(*this); }
/// \brief Set internal layout for current device
///
diff --git a/src/emu/memarray.cpp b/src/emu/memarray.cpp
index 22bfa17b80a..eb03974ff1c 100644
--- a/src/emu/memarray.cpp
+++ b/src/emu/memarray.cpp
@@ -90,11 +90,6 @@ void memory_array::set(void *base, u32 bytes, int membits, endianness_t endianne
// set - additional setter variants
//-------------------------------------------------
-void memory_array::set(const address_space &space, void *base, u32 bytes, int bpe)
-{
- set(base, bytes, space.data_width(), space.endianness(), bpe);
-}
-
void memory_array::set(const memory_share &share, int bpe)
{
set(share.ptr(), share.bytes(), share.bitwidth(), share.endianness(), bpe);
@@ -139,8 +134,8 @@ void memory_array::write8_to_32le(int index, u32 data) { reinterpret_cast<u8 *>(
u32 memory_array::read8_from_32be(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE4_XOR_BE(index)]; }
void memory_array::write8_to_32be(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE4_XOR_BE(index)] = data; }
-u32 memory_array::read8_from_64le(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)]; }
-void memory_array::write8_to_64le(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)] = data; }
+u32 memory_array::read8_from_64le(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_LE(index)]; }
+void memory_array::write8_to_64le(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_LE(index)] = data; }
u32 memory_array::read8_from_64be(int index) const { return reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)]; }
void memory_array::write8_to_64be(int index, u32 data) { reinterpret_cast<u8 *>(m_base)[BYTE8_XOR_BE(index)] = data; }
diff --git a/src/emu/memarray.h b/src/emu/memarray.h
index f9a7e406a8e..fc7e47c4b3c 100644
--- a/src/emu/memarray.h
+++ b/src/emu/memarray.h
@@ -42,14 +42,12 @@ public:
memory_array();
memory_array(void *base, u32 bytes, int membits, endianness_t endianness, int bpe) { set(base, bytes, membits, endianness, bpe); }
template <typename _Type> memory_array(std::vector<_Type> &array, endianness_t endianness, int bpe) { set(array, endianness, bpe); }
- memory_array(const address_space &space, void *base, u32 bytes, int bpe) { set(space, base, bytes, bpe); }
memory_array(const memory_share &share, int bpe) { set(share, bpe); }
memory_array(const memory_array &array) { set(array); }
// configuration
void set(void *base, u32 bytes, int membits, endianness_t endianness, int bpe);
template <typename _Type> void set(std::vector<_Type> &array, endianness_t endianness, int bpe) { set(&array[0], array.size(), 8*sizeof(_Type), endianness, bpe); }
- void set(const address_space &space, void *base, u32 bytes, int bpe);
void set(const memory_share &share, int bpe);
void set(const memory_array &array);
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index e5dcdc93dbc..681f64cd263 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -15,6 +15,9 @@
#include "emuopts.h"
#include "unicode.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
#include <algorithm>
#include <cstring>
@@ -505,10 +508,10 @@ void natural_keyboard::post_utf8(const char *text, size_t length, const attotime
}
-void natural_keyboard::post_utf8(const std::string &text, const attotime &rate)
+void natural_keyboard::post_utf8(std::string_view text, const attotime &rate)
{
if (!text.empty())
- post_utf8(text.c_str(), text.size(), rate);
+ post_utf8(text.data(), text.size(), rate);
}
@@ -590,10 +593,10 @@ void natural_keyboard::post_coded(const char *text, size_t length, const attotim
}
-void natural_keyboard::post_coded(const std::string &text, const attotime &rate)
+void natural_keyboard::post_coded(std::string_view text, const attotime &rate)
{
if (!text.empty())
- post_coded(text.c_str(), text.size(), rate);
+ post_coded(text.data(), text.size(), rate);
}
@@ -864,7 +867,7 @@ void natural_keyboard::internal_post(char32_t ch)
// when posting a string of characters
//-------------------------------------------------
-void natural_keyboard::timer(void *ptr, int param)
+void natural_keyboard::timer(s32 param)
{
if (!m_queue_chars.isnull())
{
diff --git a/src/emu/natkeyboard.h b/src/emu/natkeyboard.h
index c3454ee8dd4..c14de66fa66 100644
--- a/src/emu/natkeyboard.h
+++ b/src/emu/natkeyboard.h
@@ -16,6 +16,7 @@
#include <functional>
#include <iosfwd>
#include <string>
+#include <string_view>
#include <unordered_map>
#include <vector>
@@ -63,9 +64,9 @@ public:
void post_char(char32_t ch, bool normalize_crlf = false);
void post(const char32_t *text, size_t length = 0, const attotime &rate = attotime::zero);
void post_utf8(const char *text, size_t length = 0, const attotime &rate = attotime::zero);
- void post_utf8(const std::string &text, const attotime &rate = attotime::zero);
+ void post_utf8(std::string_view text, const attotime &rate = attotime::zero);
void post_coded(const char *text, size_t length = 0, const attotime &rate = attotime::zero);
- void post_coded(const std::string &text, const attotime &rate = attotime::zero);
+ void post_coded(std::string_view text, const attotime &rate = attotime::zero);
void paste();
// debugging
@@ -109,7 +110,7 @@ private:
bool can_post_alternate(char32_t ch);
attotime choose_delay(char32_t ch);
void internal_post(char32_t ch);
- void timer(void *ptr, int param);
+ void timer(s32 param);
std::string unicode_to_string(char32_t ch) const;
const keycode_map_entry *find_code(char32_t ch) const;
diff --git a/src/emu/network.cpp b/src/emu/network.cpp
index 68c9f93c196..f5e065ac9cb 100644
--- a/src/emu/network.cpp
+++ b/src/emu/network.cpp
@@ -8,13 +8,16 @@
***************************************************************************/
-#include <cctype>
-
#include "emu.h"
#include "network.h"
+
#include "config.h"
+#include "dinetwork.h"
+
#include "xmlfile.h"
+#include <cctype>
+
//**************************************************************************
// NETWORK MANAGER
//**************************************************************************
@@ -54,7 +57,7 @@ void network_manager::config_load(config_type cfg_type, config_level cfg_level,
network.set_interface(interface);
const char *mac_addr = node->get_attribute_string("mac", nullptr);
if (mac_addr != nullptr && strlen(mac_addr) == 17) {
- char mac[7];
+ uint8_t mac[6];
unsigned int mac_num[6];
sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_num[0], &mac_num[1], &mac_num[2], &mac_num[3], &mac_num[4], &mac_num[5]);
for (int i = 0; i<6; i++) mac[i] = mac_num[i];
@@ -84,9 +87,9 @@ void network_manager::config_save(config_type cfg_type, util::xml::data_node *pa
{
node->set_attribute("tag", network.device().tag());
node->set_attribute_int("interface", network.get_interface());
- const char *mac = network.get_mac();
+ const std::array<u8, 6> &mac = network.get_mac();
char mac_addr[6 * 3];
- sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", u8(mac[0]), u8(mac[1]), u8(mac[2]), u8(mac[3]), u8(mac[4]), u8(mac[5]));
+ sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
node->set_attribute("mac", mac_addr);
}
}
diff --git a/src/emu/profiler.cpp b/src/emu/profiler.cpp
index 765373e34e7..19f3908f097 100644
--- a/src/emu/profiler.cpp
+++ b/src/emu/profiler.cpp
@@ -89,8 +89,11 @@ real_profiler_state::real_profiler_state()
// reset - initializes state
//-------------------------------------------------
-void real_profiler_state::reset(bool enabled)
+void real_profiler_state::reset(bool enabled) noexcept
{
+ // disabling the profiler from the UI happens while PROFILER_EXTRA is active
+ //assert(!m_filoptr || (m_filoptr == m_filo));
+
m_text_time = attotime::never;
if (enabled)
@@ -117,10 +120,10 @@ void real_profiler_state::reset(bool enabled)
const char *real_profiler_state::text(running_machine &machine)
{
- start(PROFILER_PROFILER);
+ auto profile = start(PROFILER_PROFILER);
// get the current time
- attotime current_time = machine.scheduler().time();
+ attotime const current_time = machine.scheduler().time();
// we only want to update the text periodically
if ((m_text_time == attotime::never) || ((current_time - m_text_time).as_double() >= TEXT_UPDATE_TIME))
@@ -129,7 +132,6 @@ const char *real_profiler_state::text(running_machine &machine)
m_text_time = current_time;
}
- stop();
return m_text.c_str();
}
diff --git a/src/emu/profiler.h b/src/emu/profiler.h
index 8341e075eae..8ea65ac7f07 100644
--- a/src/emu/profiler.h
+++ b/src/emu/profiler.h
@@ -8,11 +8,11 @@
****************************************************************************
- Profiling is scope-based. To start profiling, put a profiler_scope
+ Profiling is scope-based. To start profiling, put a profiler scope
object on the stack. To end profiling, just end the scope:
{
- profiler_scope scope(PROFILER_VIDEO);
+ auto scope = g_profiler.start(PROFILER_VIDEO);
your_work_here();
}
@@ -26,6 +26,17 @@
#pragma once
+#include "emufwd.h"
+
+#include "attotime.h"
+
+#include "eminline.h" // for get_profile_ticks()
+#include "osdcore.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+
//**************************************************************************
// CONSTANTS
@@ -83,18 +94,57 @@ DECLARE_ENUM_INCDEC_OPERATORS(profile_type)
class real_profiler_state
{
public:
+ class scope
+ {
+ private:
+ real_profiler_state &m_host;
+ bool m_active;
+
+ public:
+ scope(scope const &) = delete;
+ scope &operator=(scope const &) = delete;
+
+ scope(scope &&that) noexcept : m_host(that.m_host), m_active(that.m_active)
+ {
+ that.m_active = false;
+ }
+
+ scope(real_profiler_state &host, profile_type type) noexcept : m_host(host), m_active(false)
+ {
+ if (m_host.enabled())
+ {
+ m_host.real_start(type);
+ m_active = true;
+ }
+ }
+
+ ~scope()
+ {
+ stop();
+ }
+
+ void stop() noexcept
+ {
+ if (m_active)
+ {
+ m_host.real_stop();
+ m_active = false;
+ }
+ }
+ };
+
// construction/destruction
real_profiler_state();
// getters
- bool enabled() const
+ bool enabled() const noexcept
{
return m_filoptr != nullptr;
}
const char *text(running_machine &machine);
// enable/disable
- void enable(bool state = true)
+ void enable(bool state = true) noexcept
{
if (state != enabled())
{
@@ -103,22 +153,31 @@ public:
}
// start/stop
- void start(profile_type type) { if (enabled()) real_start(type); }
- void stop() { if (enabled()) real_stop(); }
+ [[nodiscard]] auto start(profile_type type) noexcept { return scope(*this, type); }
private:
- void reset(bool enabled);
+ // an entry in the FILO
+ struct filo_entry
+ {
+ int type; // type of entry
+ osd_ticks_t start; // start time
+ };
+
+ void reset(bool enabled) noexcept;
void update_text(running_machine &machine);
//-------------------------------------------------
// real_start - mark the beginning of a
// profiler entry
//-------------------------------------------------
- ATTR_FORCE_INLINE void real_start(profile_type type)
+ ATTR_FORCE_INLINE void real_start(profile_type type) noexcept
{
// fail if we overflow
- if (m_filoptr >= &m_filo[std::size(m_filo) - 1])
- throw emu_fatalerror("Profiler FILO overflow (type = %d)\n", type);
+ if (UNEXPECTED(m_filoptr >= &m_filo[std::size(m_filo) - 1]))
+ {
+ std::fprintf(stderr, "Profiler FILO overflow (type = %d)\n", int(type));
+ std::abort();
+ }
// get current tick count
osd_ticks_t curticks = get_profile_ticks();
@@ -137,7 +196,7 @@ private:
//-------------------------------------------------
// real_stop - mark the end of a profiler entry
//-------------------------------------------------
- ATTR_FORCE_INLINE void real_stop()
+ ATTR_FORCE_INLINE void real_stop() noexcept
{
// degenerate scenario
if (UNEXPECTED(m_filoptr <= m_filo))
@@ -156,13 +215,6 @@ private:
m_filoptr->start = curticks;
}
- // an entry in the FILO
- struct filo_entry
- {
- int type; // type of entry
- osd_ticks_t start; // start time
- };
-
// internal state
filo_entry * m_filoptr; // current FILO index
std::string m_text; // profiler text
@@ -177,19 +229,35 @@ private:
class dummy_profiler_state
{
public:
+ class scope
+ {
+ private:
+ dummy_profiler_state &m_host;
+
+ public:
+ scope(scope const &) = delete;
+ scope &operator=(scope const &) = delete;
+ scope(scope &&that) noexcept = default;
+ scope(dummy_profiler_state &host, profile_type type) noexcept : m_host(host) { }
+ ~scope() { m_host.real_stop(); }
+ void stop() noexcept { }
+ };
+
// construction/destruction
dummy_profiler_state();
// getters
- bool enabled() const { return false; }
+ bool enabled() const noexcept { return false; }
const char *text(running_machine &machine) { return ""; }
// enable/disable
- void enable(bool state = true) { }
+ void enable(bool state = true) noexcept { }
// start/stop
- void start(profile_type type) { }
- void stop() { }
+ [[nodiscard]] auto start(profile_type type) noexcept { return scope(*this, type); }
+
+private:
+ void real_stop() noexcept { }
};
@@ -210,4 +278,4 @@ typedef dummy_profiler_state profiler_state;
extern profiler_state g_profiler;
-#endif /* MAME_EMU_PROFILER_H */
+#endif // MAME_EMU_PROFILER_H
diff --git a/src/emu/recording.cpp b/src/emu/recording.cpp
index 9e3c1f3f4ae..d9c25c57767 100644
--- a/src/emu/recording.cpp
+++ b/src/emu/recording.cpp
@@ -9,7 +9,11 @@
***************************************************************************/
#include "emu.h"
+
+#include "fileio.h"
+#include "main.h"
#include "screen.h"
+
#include "aviio.h"
#include "png.h"
@@ -175,8 +179,8 @@ bool avi_movie_recording::initialize(running_machine &machine, std::unique_ptr<e
// build up information about this new movie
avi_file::movie_info info;
info.video_format = 0;
- info.video_timescale = 1000 * (screen() ? screen()->frame_period().as_hz() : screen_device::DEFAULT_FRAME_RATE);
- info.video_sampletime = 1000;
+ info.video_timescale = 0x3fff'fffc; // multiple of 60, for screenless machines
+ info.video_sampletime = screen() ? screen()->frame_period().as_ticks(info.video_timescale) : 0x0111'1111;
info.video_numsamples = 0;
info.video_width = width;
info.video_height = height;
@@ -191,7 +195,7 @@ bool avi_movie_recording::initialize(running_machine &machine, std::unique_ptr<e
info.audio_samplerate = machine.sample_rate();
// compute the frame time
- set_frame_period(attotime::from_seconds(1000) / info.video_timescale);
+ set_frame_period(attotime::from_ticks(info.video_sampletime, info.video_timescale));
// create the file
avi_file::error avierr = avi_file::create(fullpath, info, m_avi_file);
@@ -218,14 +222,13 @@ bool avi_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const
bool avi_movie_recording::add_sound_to_recording(const s16 *sound, int numsamples)
{
- g_profiler.start(PROFILER_MOVIE_REC);
+ auto profile = g_profiler.start(PROFILER_MOVIE_REC);
// write the next frame
avi_file::error avierr = m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1);
if (avierr == avi_file::error::NONE)
avierr = m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1);
- g_profiler.stop();
return avierr == avi_file::error::NONE;
}
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 1f9918539d5..571f4e79084 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -41,6 +41,7 @@
#include "corestr.h"
#include "emuopts.h"
+#include "fileio.h"
#include "rendfont.h"
#include "rendlay.h"
#include "rendutil.h"
@@ -56,6 +57,7 @@
#include "util/xmlfile.h"
#include <algorithm>
+#include <limits>
@@ -98,6 +100,40 @@ struct render_target::object_transform
};
+struct render_target::pointer_info
+{
+ pointer_info() noexcept
+ : type(osd::ui_event_handler::pointer::UNKNOWN)
+ , oldpos(std::numeric_limits<float>::min(), std::numeric_limits<float>::min())
+ , newpos(std::numeric_limits<float>::min(), std::numeric_limits<float>::min())
+ , oldbuttons(0U)
+ , newbuttons(0U)
+ , edges(0U, 0U)
+ {
+ }
+
+ osd::ui_event_handler::pointer type;
+ std::pair<float, float> oldpos;
+ std::pair<float, float> newpos;
+ u32 oldbuttons, newbuttons;
+ std::pair<size_t, size_t> edges;
+};
+
+
+struct render_target::hit_test
+{
+ hit_test() noexcept
+ : inbounds(0U, 0U)
+ , hit(0U)
+ {
+ }
+
+ std::pair<u64, u64> inbounds;
+ u64 hit;
+};
+
+
+
//**************************************************************************
// GLOBAL VARIABLES
@@ -300,7 +336,8 @@ render_texture::render_texture()
m_curseq(0)
{
m_sbounds.set(0, -1, 0, -1);
- memset(m_scaled, 0, sizeof(m_scaled));
+ for (auto &elem : m_scaled)
+ elem.seqid = 0;
}
@@ -352,6 +389,7 @@ void render_texture::release()
m_bitmap = nullptr;
m_sbounds.set(0, -1, 0, -1);
m_format = TEXFORMAT_ARGB32;
+ m_scaler = nullptr;
m_curseq = 0;
}
@@ -430,6 +468,7 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo
texinfo.base = m_bitmap->raw_pixptr(m_sbounds.top(), m_sbounds.left());
texinfo.rowpixels = m_bitmap->rowpixels();
texinfo.width = swidth;
+ texinfo.width_margin = m_sbounds.left();
texinfo.height = sheight;
// palette will be set later
texinfo.seqid = ++m_curseq;
@@ -690,7 +729,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length,
m_bcglookup.resize(palette->max_index());
recompute_lookups();
}
- assert (palette == &m_palclient->palette());
+ assert(palette == &m_palclient->palette());
out_length = palette->max_index();
return &m_bcglookup[0];
@@ -880,19 +919,21 @@ render_container::user_settings::user_settings()
// render_target - constructor
//-------------------------------------------------
-render_target::render_target(render_manager &manager, const internal_layout *layoutfile, u32 flags)
- : render_target(manager, layoutfile, flags, CONSTRUCTOR_IMPL)
+render_target::render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags)
+ : render_target(manager, ui, layoutfile, flags, CONSTRUCTOR_IMPL)
{
}
-render_target::render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags)
- : render_target(manager, layout, flags, CONSTRUCTOR_IMPL)
+render_target::render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags)
+ : render_target(manager, ui, layout, flags, CONSTRUCTOR_IMPL)
{
}
-template <typename T> render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t)
+template <typename T>
+render_target::render_target(render_manager &manager, render_container *ui, T &&layout, u32 flags, constructor_impl_t)
: m_next(nullptr)
, m_manager(manager)
+ , m_ui_container(ui)
, m_curview(0U)
, m_flags(flags)
, m_listindex(0)
@@ -1012,9 +1053,9 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect)
m_width = width;
m_height = height;
m_bounds.x0 = m_bounds.y0 = 0;
- m_bounds.x1 = (float)width;
- m_bounds.y1 = (float)height;
- m_pixel_aspect = pixel_aspect != 0.0? pixel_aspect : 1.0;
+ m_bounds.x1 = float(width);
+ m_bounds.y1 = float(height);
+ m_pixel_aspect = pixel_aspect != 0.0F ? pixel_aspect : 1.0F;
}
@@ -1027,9 +1068,12 @@ void render_target::set_view(unsigned viewindex)
{
if (m_views.size() > viewindex)
{
+ forget_pointers();
m_curview = viewindex;
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
current_view().preload();
+ m_clickable_items.clear();
+ m_clickable_items.resize(current_view().interactive_items().size());
}
}
@@ -1047,6 +1091,229 @@ void render_target::set_max_texture_size(int maxwidth, int maxheight)
//-------------------------------------------------
+// pointer_updated - pointer activity within
+// target
+//-------------------------------------------------
+
+void render_target::pointer_updated(
+ osd::ui_event_handler::pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 buttons,
+ u32 pressed,
+ u32 released,
+ s16 clicks)
+{
+ auto const target_f(map_point_layout(x, y));
+ current_view().pointer_updated(type, ptrid, device, target_f.first, target_f.second, buttons, pressed, released, clicks);
+
+ // 64 pointers ought to be enough for anyone
+ if (64 <= ptrid)
+ return;
+
+ // just store the updated pointer state
+ if (m_pointers.size() <= ptrid)
+ m_pointers.resize(ptrid + 1);
+ m_pointers[ptrid].type = type;
+ m_pointers[ptrid].newpos = target_f;
+ m_pointers[ptrid].newbuttons = buttons;
+}
+
+
+//-------------------------------------------------
+// pointer_left - pointer left target normally
+//-------------------------------------------------
+
+void render_target::pointer_left(
+ osd::ui_event_handler::pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 released,
+ s16 clicks)
+{
+ auto const target_f(map_point_layout(x, y));
+ current_view().pointer_left(type, ptrid, device, target_f.first, target_f.second, released, clicks);
+
+ // store the updated state if relevant
+ if (m_pointers.size() > ptrid)
+ {
+ m_pointers[ptrid].newpos = std::make_pair(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
+ m_pointers[ptrid].newbuttons = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// pointer_aborted - pointer left target
+// abnormally
+//-------------------------------------------------
+
+void render_target::pointer_aborted(
+ osd::ui_event_handler::pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 released,
+ s16 clicks)
+{
+ // let layout scripts handle pointer input
+ auto const target_f(map_point_layout(x, y));
+ current_view().pointer_aborted(type, ptrid, device, target_f.first, target_f.second, released, clicks);
+
+ // store the updated state if relevant
+ if (m_pointers.size() > ptrid)
+ {
+ m_pointers[ptrid].newpos = std::make_pair(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
+ m_pointers[ptrid].newbuttons = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// forget_pointers - stop processing pointer
+// input
+//-------------------------------------------------
+
+void render_target::forget_pointers()
+{
+ current_view().forget_pointers();
+ m_pointers.clear();
+ for (size_t i = 0; m_clickable_items.size() > i; ++i)
+ {
+ if (m_clickable_items[i].hit)
+ {
+ layout_view_item const &item(current_view().interactive_items()[i]);
+ auto const [port, mask] = item.input_tag_and_mask();
+ ioport_field *const field(port ? port->field(mask) : nullptr);
+ if (field)
+ field->set_value(0);
+ }
+ m_clickable_items[i] = hit_test();
+ }
+}
+
+
+//-------------------------------------------------
+// update_pointer_fields - update inputs for new
+// pointer state
+//-------------------------------------------------
+
+void render_target::update_pointer_fields()
+{
+ auto const &x_edges(current_view().interactive_edges_x());
+ auto const &y_edges(current_view().interactive_edges_y());
+
+ // update items bounds intersection checks for pointers
+ for (size_t ptr = 0; m_pointers.size() > ptr; ++ptr)
+ {
+ auto const [x, y] = m_pointers[ptr].newpos;
+ auto edges = m_pointers[ptr].edges;
+
+ // check for moving across horizontal edges
+ if (x < m_pointers[ptr].oldpos.first)
+ {
+ while (edges.first && (x < x_edges[edges.first - 1].position()))
+ {
+ --edges.first;
+ auto const &edge(x_edges[edges.first]);
+ if (edge.trailing())
+ m_clickable_items[edge.index()].inbounds.first |= u64(1) << ptr;
+ else
+ m_clickable_items[edge.index()].inbounds.first &= ~(u64(1) << ptr);
+ }
+ }
+ else if (x > m_pointers[ptr].oldpos.first)
+ {
+ while ((x_edges.size() > edges.first) && (x >= x_edges[edges.first].position()))
+ {
+ auto const &edge(x_edges[edges.first]);
+ if (edge.trailing())
+ m_clickable_items[edge.index()].inbounds.first &= ~(u64(1) << ptr);
+ else
+ m_clickable_items[edge.index()].inbounds.first |= u64(1) << ptr;
+ ++edges.first;
+ }
+ }
+
+ // check for moving across vertical edges
+ if (y < m_pointers[ptr].oldpos.second)
+ {
+ while (edges.second && (y < y_edges[edges.second - 1].position()))
+ {
+ --edges.second;
+ auto const &edge(y_edges[edges.second]);
+ if (edge.trailing())
+ m_clickable_items[edge.index()].inbounds.second |= u64(1) << ptr;
+ else
+ m_clickable_items[edge.index()].inbounds.second &= ~(u64(1) << ptr);
+ }
+ }
+ else if (y > m_pointers[ptr].oldpos.second)
+ {
+ while ((y_edges.size() > edges.second) && (y >= y_edges[edges.second].position()))
+ {
+ auto const &edge(y_edges[edges.second]);
+ if (edge.trailing())
+ m_clickable_items[edge.index()].inbounds.second &= ~(u64(1) << ptr);
+ else
+ m_clickable_items[edge.index()].inbounds.second |= u64(1) << ptr;
+ ++edges.second;
+ }
+ }
+
+ // update the pointer's state
+ m_pointers[ptr].oldpos = m_pointers[ptr].newpos;
+ m_pointers[ptr].oldbuttons = m_pointers[ptr].newbuttons;
+ m_pointers[ptr].edges = edges;
+ }
+
+ // update item hit states
+ u64 obscured(0U);
+ for (size_t i = 0; m_clickable_items.size() > i; ++i)
+ {
+ layout_view_item const &item(current_view().interactive_items()[i]);
+ u64 const inbounds(m_clickable_items[i].inbounds.first & m_clickable_items[i].inbounds.second);
+ u64 hit(m_clickable_items[i].hit);
+ for (unsigned ptr = 0; m_pointers.size() > ptr; ++ptr)
+ {
+ pointer_info const &pointer(m_pointers[ptr]);
+ bool const prefilter(BIT(~obscured & inbounds, ptr));
+ if (!prefilter || !BIT(pointer.newbuttons, 0) || !item.bounds().includes(pointer.newpos.first, pointer.newpos.second))
+ {
+ hit &= ~(u64(1) << ptr);
+ }
+ else
+ {
+ hit |= u64(1) << ptr;
+ if (!item.clickthrough())
+ obscured |= u64(1) << ptr;
+ }
+ }
+
+ // update field state
+ if (bool(hit) != bool(m_clickable_items[i].hit))
+ {
+ auto const [port, mask] = item.input_tag_and_mask();
+ ioport_field *const field(port ? port->field(mask) : nullptr);
+ if (field)
+ {
+ if (hit)
+ field->set_value(1);
+ else
+ field->clear_value();
+ }
+ }
+ m_clickable_items[i].hit = hit;
+ }
+}
+
+
+//-------------------------------------------------
// set_visibility_toggle - show or hide selected
// parts of a view
//-------------------------------------------------
@@ -1058,7 +1325,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable)
m_views[m_curview].second |= u32(1) << index;
else
m_views[m_curview].second &= ~(u32(1) << index);
- current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ update_layer_config();
current_view().preload();
}
@@ -1070,28 +1337,29 @@ void render_target::set_visibility_toggle(unsigned index, bool enable)
unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets)
{
- layout_view *view = nullptr;
-
// if it isn't "auto" or an empty string, try to match it as a view name prefix
if (viewname && *viewname && strcmp(viewname, "auto"))
{
// scan for a matching view name
size_t const viewlen = strlen(viewname);
- for (unsigned i = 0; !view && (m_views.size() > i); ++i)
+ for (unsigned i = 0; m_views.size() > i; ++i)
+ {
if (!core_strnicmp(m_views[i].first.name().c_str(), viewname, viewlen))
- view = &m_views[i].first;
+ return i;
+ }
}
// if we don't have a match, default to the nth view
std::vector<std::reference_wrapper<screen_device> > screens;
for (screen_device &screen : screen_device_enumerator(m_manager.machine().root_device()))
screens.push_back(screen);
- if (!view && !screens.empty())
+ if (!screens.empty())
{
// if we have enough targets to be one per screen, assign in order
if (numtargets >= screens.size())
{
// find the first view with this screen and this screen only
+ layout_view *view = nullptr;
screen_device const &screen = screens[index() % screens.size()];
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
@@ -1109,22 +1377,21 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
}
}
}
+ if (view)
+ return view_index(*view);
}
// otherwise, find the first view that has all the screens
- if (!view)
+ for (unsigned i = 0; m_views.size() > i; ++i)
{
- for (unsigned i = 0; !view && (m_views.size() > i); ++i)
- {
- layout_view &curview = m_views[i].first;
- if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
- view = &curview;
- }
+ layout_view &curview = m_views[i].first;
+ if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
+ return i;
}
}
- // make sure it's a valid view
- return view ? view_index(*view) : 0;
+ // default to the first view
+ return 0;
}
@@ -1197,63 +1464,103 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl
// apply orientation if required
if (target_orientation & ORIENTATION_SWAP_XY)
- src_aspect = 1.0 / src_aspect;
+ src_aspect = 1.0f / src_aspect;
- // get target aspect
- float target_aspect = (float)target_width / (float)target_height * target_pixel_aspect;
+ // we need the ratio of target to source aspect
+ float aspect_ratio = m_keepaspect ? (float)target_width / (float)target_height * target_pixel_aspect / src_aspect : 1.0f;
+
+ // first compute (a, b) scale factors to fit the screen
+ float a = (float)target_width / src_width;
+ float b = (float)target_height / src_height;
// apply automatic axial stretching if required
int scale_mode = m_scale_mode;
- if (m_scale_mode == SCALE_FRACTIONAL_AUTO)
- {
- bool is_rotated = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY);
- scale_mode = is_rotated ? SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X;
- }
+ if (scale_mode == SCALE_FRACTIONAL_AUTO)
+ scale_mode = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY) ?
+ SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X;
- // first compute scale factors to fit the screen
- float xscale = (float)target_width / src_width;
- float yscale = (float)target_height / src_height;
+ // determine the scaling method for each axis
+ bool a_is_fract = (scale_mode == SCALE_FRACTIONAL_X || scale_mode == SCALE_FRACTIONAL);
+ bool b_is_fract = (scale_mode == SCALE_FRACTIONAL_Y || scale_mode == SCALE_FRACTIONAL);
- // apply aspect correction
- if (m_keepaspect)
- {
- if (target_aspect > src_aspect)
- xscale *= src_aspect / target_aspect;
- else
- yscale *= target_aspect / src_aspect;
- }
+ // check if we have user defined scale factors, if so use them instead, but only on integer axes
+ int a_user = a_is_fract ? 0 : m_int_scale_x;
+ int b_user = b_is_fract ? 0 : m_int_scale_y;
- bool x_fits = render_round_nearest(xscale) * src_width <= target_width;
- bool y_fits = render_round_nearest(yscale) * src_height <= target_height;
+ // we allow overscan either explicitely or if integer scale factors are forced by user
+ bool int_overscan = m_int_overscan || (m_keepaspect && (a_user != 0 || b_user != 0));
+ float a_max = std::max(a, (float)a_user);
+ float b_max = std::max(b, (float)b_user);
- // compute integer scale factors
- float integer_x = std::max(1.0f, float(m_int_overscan || x_fits ? render_round_nearest(xscale) : floor(xscale)));
- float integer_y = std::max(1.0f, float(m_int_overscan || y_fits ? render_round_nearest(yscale) : floor(yscale)));
- // check if we have user defined scale factors, if so use them instead
- integer_x = m_int_scale_x > 0 ? m_int_scale_x : integer_x;
- integer_y = m_int_scale_y > 0 ? m_int_scale_y : integer_y;
+ // get the usable bounding box considering the type of scaling for each axis
+ float usable_aspect = (a_is_fract ? a : std::max(1.0f, floorf(a))) * src_width /
+ ((b_is_fract ? b : std::max(1.0f, floorf(b))) * src_height) * target_pixel_aspect;
- // now apply desired scale mode
- if (scale_mode == SCALE_FRACTIONAL_X)
+ // depending on the relative shape between target and source, let's define 'a' and 'b' so that:
+ // * a is the leader axis (first to hit a boundary)
+ // * b is the follower axis
+ if (usable_aspect > src_aspect)
{
- if (m_keepaspect) xscale *= integer_y / yscale;
- yscale = integer_y;
+ std::swap(a, b);
+ std::swap(a_user, b_user);
+ std::swap(a_is_fract, b_is_fract);
+ std::swap(a_max, b_max);
+ aspect_ratio = 1.0f / aspect_ratio;
}
- else if (scale_mode == SCALE_FRACTIONAL_Y)
- {
- if (m_keepaspect) yscale *= integer_x / xscale;
- xscale = integer_x;
- }
- else
+
+ // now find an (a, b) pair that best fits our boundaries and scale options
+ float a_best = 1.0f, b_best = 1.0f;
+ float diff = 1000;
+
+ // fill (a0, a1) range
+ float u = a_user == 0 ? a : (float)a_user;
+ float a_range[] = {a_is_fract ? u : std::max(1.0f, floorf(u)), a_is_fract ? u : std::max(1.0f, roundf(u))};
+
+ for (float aa : a_range)
{
- xscale = integer_x;
- yscale = integer_y;
+ // apply aspect correction to 'b' axis if needed, considering resulting 'a' borders
+ float ba = b * (m_keepaspect ? aspect_ratio * (aa / a) : 1.0f);
+
+ // fill (b0, b1) range
+ float v = b_user == 0 ? ba : (float)b_user;
+ float b_range[] = {b_is_fract ? v : std::max(1.0f, floorf(v)), b_is_fract ? v : std::max(1.0f, roundf(v))};
+
+ for (float bb : b_range)
+ {
+ // we may need to propagate proportions back to 'a' axis
+ float ab = aa;
+ if (m_keepaspect && a_user == 0)
+ {
+ if (a_is_fract) ab *= (bb / ba);
+ else if (b_user != 0) ab = std::max(1.0f, roundf(ab * (bb / ba)));
+ }
+
+ // if overscan isn't allowed, discard values that exceed the usable bounding box, except a minimum of 1.0f
+ if (!int_overscan && ((ab > a_max && bb > 1.0f) || (bb > b_max && ab > 1.0f)))
+ continue;
+
+ // score the result
+ float new_diff = fabsf(aspect_ratio * (a / b) - (ab / bb));
+
+ if (new_diff <= diff)
+ {
+ diff = new_diff;
+ a_best = ab;
+ b_best = bb;
+ }
+ }
}
+ a = a_best;
+ b = b_best;
+
+ // restore orientation
+ if (usable_aspect > src_aspect)
+ std::swap(a, b);
// set the final width/height
- visible_width = render_round_nearest(src_width * xscale);
- visible_height = render_round_nearest(src_height * yscale);
+ visible_width = render_round_nearest(src_width * a);
+ visible_height = render_round_nearest(src_height * b);
break;
}
}
@@ -1338,10 +1645,6 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight)
render_primitive_list &render_target::get_primitives()
{
- // remember the base values if this is the first frame
- if (!m_base_view)
- m_base_view = &current_view();
-
// switch to the next primitive list
render_primitive_list &list = m_primlist[m_listindex];
m_listindex = (m_listindex + 1) % std::size(m_primlist);
@@ -1415,8 +1718,8 @@ render_primitive_list &render_target::get_primitives()
}
}
- // process the UI if we are the UI target
- if (is_ui_target())
+ // process UI elements if applicable
+ if (m_ui_container)
{
// compute the transform for the UI
object_transform ui_xform;
@@ -1429,7 +1732,7 @@ render_primitive_list &render_target::get_primitives()
ui_xform.no_center = false;
// add UI elements
- add_container_primitives(list, root_xform, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA);
+ add_container_primitives(list, root_xform, ui_xform, *m_ui_container, BLENDMODE_ALPHA);
}
// optimize the list before handing it off
@@ -1450,7 +1753,7 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
// explicitly check for the UI container
- if (&container == &m_manager.ui_container())
+ if (&container == m_ui_container)
{
// this hit test went against the UI container
if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f))
@@ -1497,74 +1800,6 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
//-------------------------------------------------
-// map_point_input - attempts to map a point on
-// the specified render_target to an input port
-// field, if possible
-//-------------------------------------------------
-
-bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y)
-{
- std::pair<float, float> target_f(map_point_internal(target_x, target_y));
- if (m_orientation & ORIENTATION_FLIP_X)
- target_f.first = 1.0f - target_f.first;
- if (m_orientation & ORIENTATION_FLIP_Y)
- target_f.second = 1.0f - target_f.second;
- if (m_orientation & ORIENTATION_SWAP_XY)
- std::swap(target_f.first, target_f.second);
-
- auto const &items(current_view().interactive_items());
- m_hit_test.resize(items.size() * 2);
- std::fill(m_hit_test.begin(), m_hit_test.end(), false);
-
- for (auto const &edge : current_view().interactive_edges_x())
- {
- if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing()))
- break;
- else
- m_hit_test[edge.index()] = !edge.trailing();
- }
-
- for (auto const &edge : current_view().interactive_edges_y())
- {
- if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing()))
- break;
- else
- m_hit_test[items.size() + edge.index()] = !edge.trailing();
- }
-
- for (unsigned i = 0; items.size() > i; ++i)
- {
- if (m_hit_test[i] && m_hit_test[items.size() + i])
- {
- layout_view_item &item(items[i]);
- render_bounds const bounds(item.bounds());
- if (bounds.includes(target_f.first, target_f.second))
- {
- if (item.has_input())
- {
- // point successfully mapped
- std::tie(input_port, input_mask) = item.input_tag_and_mask();
- input_x = (target_f.first - bounds.x0) / bounds.width();
- input_y = (target_f.second - bounds.y0) / bounds.height();
- return true;
- }
- else
- {
- break;
- }
- }
- }
- }
-
- // default to point not mapped
- input_port = nullptr;
- input_mask = 0;
- input_x = input_y = -1.0f;
- return false;
-}
-
-
-//-------------------------------------------------
// invalidate_all - if any of our primitive lists
// contain a reference to the given pointer,
// clear them
@@ -1593,7 +1828,7 @@ void render_target::resolve_tags()
for (layout_file &file : m_filelist)
file.resolve_tags();
- current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ update_layer_config();
current_view().preload();
}
@@ -1605,7 +1840,10 @@ void render_target::resolve_tags()
void render_target::update_layer_config()
{
+ forget_pointers();
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ m_clickable_items.clear();
+ m_clickable_items.resize(current_view().interactive_items().size());
}
@@ -1668,14 +1906,6 @@ void render_target::load_additional_layout_files(const char *basename, bool have
else
m_external_artwork = true;
- // if a default view has been specified, use that as a fallback
- bool have_default = false;
- if (system.default_layout)
- have_default |= load_layout_file(nullptr, *system.default_layout);
- m_manager.machine().config().apply_default_layouts(
- [this, &have_default] (device_t &dev, internal_layout const &layout)
- { have_default |= load_layout_file(nullptr, layout, &dev); });
-
// try to load another file based on the parent driver name
int cloneof = driver_list::clone(system);
while (0 <= cloneof)
@@ -1693,6 +1923,14 @@ void render_target::load_additional_layout_files(const char *basename, bool have
cloneof = driver_list::clone(parent);
}
+ // if a default view has been specified, use that as a fallback
+ bool have_default = false;
+ if (system.default_layout)
+ have_default |= load_layout_file(nullptr, *system.default_layout);
+ m_manager.machine().config().apply_default_layouts(
+ [this, &have_default] (device_t &dev, internal_layout const &layout)
+ { have_default |= load_layout_file(nullptr, layout, &dev); });
+
have_artwork |= m_external_artwork;
// Use fallback artwork if defined and no artwork has been found yet
@@ -2080,11 +2318,10 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
size_t decompressed = 0;
do
{
- size_t actual;
- std::error_condition const err = inflater->read(
+ auto const [err, actual] = read(
+ *inflater,
&tempout[decompressed],
- layout_data.decompressed_size - decompressed,
- actual);
+ layout_data.decompressed_size - decompressed);
decompressed += actual;
if (err)
{
@@ -2177,7 +2414,7 @@ bool render_target::load_layout_file(device_t &device, util::xml::data_node cons
{
m_filelist.emplace_back(device, rootnode, searchpath, dirname);
}
- catch (emu_fatalerror &err)
+ catch (emu_fatalerror const &err)
{
osd_printf_warning("%s\n", err.what());
return false;
@@ -2313,11 +2550,11 @@ void render_target::add_container_primitives(render_primitive_list &list, const
// clip the primitive
if (!m_transform_container && PRIMFLAG_GET_VECTOR(curitem.flags()))
{
- clipped = render_clip_line(&prim->bounds, &root_cliprect);
+ clipped = render_clip_line(prim->bounds, root_cliprect);
}
else
{
- clipped = render_clip_line(&prim->bounds, &cliprect);
+ clipped = render_clip_line(prim->bounds, cliprect);
}
break;
@@ -2350,7 +2587,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
prim->texcoords = oriented_texcoords[finalorient];
// apply clipping
- clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
// apply the final orientation from the quad flags and then build up the final flags
prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK))
@@ -2410,7 +2647,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
prim->texcoords = oriented_texcoords[finalorient];
// apply clipping
- clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
// apply the final orientation from the quad flags and then build up the final flags
prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK))
@@ -2426,7 +2663,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
| PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
// apply clipping
- clipped = render_clip_quad(&prim->bounds, &cliprect, nullptr);
+ clipped = render_clip_quad(prim->bounds, cliprect, nullptr);
}
}
break;
@@ -2551,7 +2788,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
}
// add to the list or free if we're clipped out
- bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ bool const clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords);
list.append_or_return(*prim, clipped);
}
}
@@ -2582,6 +2819,25 @@ std::pair<float, float> render_target::map_point_internal(s32 target_x, s32 targ
//-------------------------------------------------
+// map_point_layout - map point from screen
+// coordinates to layout coordinates
+//-------------------------------------------------
+
+std::pair<float, float> render_target::map_point_layout(s32 target_x, s32 target_y)
+{
+ using std::swap;
+ std::pair<float, float> result(map_point_internal(target_x, target_y));
+ if (m_orientation & ORIENTATION_FLIP_X)
+ result.first = 1.0f - result.first;
+ if (m_orientation & ORIENTATION_FLIP_Y)
+ result.second = 1.0f - result.second;
+ if (m_orientation & ORIENTATION_SWAP_XY)
+ swap(result.first, result.second);
+ return result;
+}
+
+
+//-------------------------------------------------
// view_name - return the name of the indexed
// view, or nullptr if it doesn't exist
//-------------------------------------------------
@@ -2613,30 +2869,40 @@ int render_target::view_index(layout_view &targetview) const
// config_load - process config information
//-------------------------------------------------
-void render_target::config_load(util::xml::data_node const &targetnode)
+void render_target::config_load(util::xml::data_node const *targetnode)
{
+ // remember the view selected via command line and INI options
+ if (!m_base_view)
+ m_base_view = &current_view();
+
+ // bail if no configuration
+ if (!targetnode)
+ return;
+
+ // TODO: consider option priority - command line should take precedence over CFG
+ // not practical at the moment because view selection options are in the OSD layer
+
// find the view
- const char *viewname = targetnode.get_attribute_string("view", nullptr);
- if (viewname != nullptr)
- for (int viewnum = 0; viewnum < 1000; viewnum++)
+ const char *viewname = targetnode->get_attribute_string("view", nullptr);
+ if (viewname)
+ {
+ for (unsigned viewnum = 0; m_views.size() > viewnum; viewnum++)
{
- const char *testname = view_name(viewnum);
- if (testname == nullptr)
- break;
- if (!strcmp(viewname, testname))
+ if (!strcmp(viewname, view_name(viewnum)))
{
set_view(viewnum);
break;
}
}
+ }
// modify the artwork config
- int const zoom = targetnode.get_attribute_int("zoom", -1);
+ int const zoom = targetnode->get_attribute_int("zoom", -1);
if (zoom == 0 || zoom == 1)
set_zoom_to_screen(zoom);
// apply orientation
- int rotate = targetnode.get_attribute_int("rotate", -1);
+ int rotate = targetnode->get_attribute_int("rotate", -1);
if (rotate != -1)
{
if (rotate == 90)
@@ -2650,17 +2916,16 @@ void render_target::config_load(util::xml::data_node const &targetnode)
set_orientation(orientation_add(rotate, orientation()));
// apply the opposite orientation to the UI
- if (is_ui_target())
+ if (m_ui_container)
{
- render_container &ui_container = m_manager.ui_container();
- render_container::user_settings settings = ui_container.get_user_settings();
+ render_container::user_settings settings = m_ui_container->get_user_settings();
settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation);
- ui_container.set_user_settings(settings);
+ m_ui_container->set_user_settings(settings);
}
}
// apply per-view settings
- for (util::xml::data_node const *viewnode = targetnode.get_child("view"); viewnode; viewnode = viewnode->get_next_sibling("view"))
+ for (util::xml::data_node const *viewnode = targetnode->get_child("view"); viewnode; viewnode = viewnode->get_next_sibling("view"))
{
char const *const viewname = viewnode->get_attribute_string("name", nullptr);
if (!viewname)
@@ -2695,6 +2960,8 @@ void render_target::config_load(util::xml::data_node const &targetnode)
{
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
current_view().preload();
+ m_clickable_items.clear();
+ m_clickable_items.resize(current_view().interactive_items().size());
}
}
}
@@ -3056,7 +3323,6 @@ render_manager::render_manager(running_machine &machine)
, m_ui_target(nullptr)
, m_live_textures(0)
, m_texture_id(0)
- , m_ui_container(std::make_unique<render_container>(*this))
{
// register callbacks
machine.configuration().config_register(
@@ -3077,7 +3343,7 @@ render_manager::render_manager(running_machine &machine)
render_manager::~render_manager()
{
// free all the containers since they may own textures
- m_ui_container.reset();
+ m_ui_containers.clear();
m_screen_container_list.clear();
// better not be any outstanding textures when we die
@@ -3133,12 +3399,14 @@ float render_manager::max_update_rate() const
render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags)
{
- return &m_targetlist.append(*new render_target(*this, layoutfile, flags));
+ render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this);
+ return &m_targetlist.append(*new render_target(*this, ui, layoutfile, flags));
}
render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags)
{
- return &m_targetlist.append(*new render_target(*this, layout, flags));
+ render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this);
+ return &m_targetlist.append(*new render_target(*this, ui, layout, flags));
}
@@ -3175,35 +3443,56 @@ render_target *render_manager::target_by_index(int index) const
float render_manager::ui_aspect(render_container *rc)
{
- int orient;
+ // work out if this is a UI container
+ render_target *target = nullptr;
+ if (!rc)
+ {
+ target = &ui_target();
+ rc = target->ui_container();
+ assert(rc);
+ }
+ else
+ {
+ for (render_target &t : m_targetlist)
+ {
+ if (t.ui_container() == rc)
+ {
+ target = &t;
+ break;
+ }
+ }
+ }
+
float aspect;
- if (rc == m_ui_container.get() || rc == nullptr) {
- // ui container, aggregated multi-screen target
+ if (target)
+ {
+ // UI container, aggregated multi-screen target
- orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation());
// based on the orientation of the target, compute height/width or width/height
+ int const orient = orientation_add(target->orientation(), rc->orientation());
if (!(orient & ORIENTATION_SWAP_XY))
- aspect = (float)m_ui_target->height() / (float)m_ui_target->width();
+ aspect = float(target->height()) / float(target->width());
else
- aspect = (float)m_ui_target->width() / (float)m_ui_target->height();
+ aspect = float(target->width()) / float(target->height());
// if we have a valid pixel aspect, apply that and return
- if (m_ui_target->pixel_aspect() != 0.0f)
+ if (target->pixel_aspect() != 0.0f)
{
- float pixel_aspect = m_ui_target->pixel_aspect();
+ float pixel_aspect = target->pixel_aspect();
if (orient & ORIENTATION_SWAP_XY)
pixel_aspect = 1.0f / pixel_aspect;
return aspect /= pixel_aspect;
}
-
- } else {
+ }
+ else
+ {
// single screen container
- orient = rc->orientation();
// based on the orientation of the target, compute height/width or width/height
+ int const orient = rc->orientation();
if (!(orient & ORIENTATION_SWAP_XY))
aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width();
else
@@ -3211,12 +3500,7 @@ float render_manager::ui_aspect(render_container *rc)
}
// clamp for extreme proportions
- if (aspect < 0.66f)
- aspect = 0.66f;
- if (aspect > 1.5f)
- aspect = 1.5f;
-
- return aspect;
+ return std::clamp(aspect, 0.66f, 1.5f);
}
@@ -3297,8 +3581,20 @@ void render_manager::resolve_tags()
void render_manager::config_load(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode)
{
// we only care about system-specific configuration with matching nodes
- if ((cfg_type != config_type::SYSTEM) || !parentnode)
+ if (cfg_type == config_type::DEFAULT)
+ {
+ // let the targets stabilise themselves
+ for (render_target &target : m_targetlist)
+ {
+ if (!target.hidden())
+ target.config_load(nullptr);
+ }
return;
+ }
+ else if ((cfg_type != config_type::SYSTEM) || !parentnode)
+ {
+ return;
+ }
// check the UI target
util::xml::data_node const *const uinode = parentnode->get_child("interface");
@@ -3314,7 +3610,7 @@ void render_manager::config_load(config_type cfg_type, config_level cfg_level, u
{
render_target *const target = target_by_index(targetnode->get_attribute_int("index", -1));
if (target && !target->hidden())
- target->config_load(*targetnode);
+ target->config_load(targetnode);
}
// iterate over screen nodes
diff --git a/src/emu/render.h b/src/emu/render.h
index d4f99377d70..c4c0f504edd 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -47,18 +47,13 @@
#define MAME_EMU_RENDER_H
#include "rendertypes.h"
-#include "screen.h"
-#include <array>
+#include "interface/uievents.h"
+
#include <cmath>
-#include <functional>
-#include <map>
+#include <list>
#include <memory>
#include <mutex>
-#include <string>
-#include <string_view>
-#include <tuple>
-#include <unordered_map>
#include <utility>
#include <vector>
@@ -164,6 +159,7 @@ struct render_texinfo
void * base; // base of the data
u32 rowpixels; // pixels per row
u32 width; // width of the image
+ u32 width_margin; // left margin of the scaled bounds, if applicable
u32 height; // height of the image
u32 seqid; // sequence ID
u64 unique_id; // unique identifier to pass to osd
@@ -346,7 +342,7 @@ private:
void get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, u32 flags = 0);
const rgb_t *get_adjusted_palette(render_container &container, u32 &out_length);
- static constexpr int MAX_TEXTURE_SCALES = 20;
+ static constexpr int MAX_TEXTURE_SCALES = 100;
// a scaled_texture contains a single scaled entry for a texture
struct scaled_texture
@@ -498,14 +494,15 @@ class render_target
friend class render_manager;
// construction/destruction
- render_target(render_manager &manager, const internal_layout *layoutfile = nullptr, u32 flags = 0);
- render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags = 0);
+ render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags);
+ render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags);
~render_target();
public:
// getters
render_target *next() const { return m_next; }
render_manager &manager() const { return m_manager; }
+ render_container *ui_container() const { return m_ui_container; }
u32 width() const { return m_width; }
u32 height() const { return m_height; }
float pixel_aspect() const { return m_pixel_aspect; }
@@ -531,6 +528,13 @@ public:
void set_keepaspect(bool keepaspect) { m_keepaspect = keepaspect; }
void set_scale_mode(int scale_mode) { m_scale_mode = scale_mode; }
+ // pointer input handling
+ void pointer_updated(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 buttons, u32 pressed, u32 released, s16 clicks);
+ void pointer_left(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks);
+ void pointer_aborted(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks);
+ void forget_pointers();
+ void update_pointer_fields();
+
// layer config getters
bool screen_overlay_enabled() const { return m_layerconfig.screen_overlay_enabled(); }
bool zoom_to_screen() const { return m_layerconfig.zoom_to_screen(); }
@@ -556,7 +560,6 @@ public:
// hit testing
bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y);
- bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y);
// reference tracking
void invalidate_all(void *refptr);
@@ -565,15 +568,24 @@ public:
void resolve_tags();
private:
+ // constants
+ static inline constexpr int NUM_PRIMLISTS = 3;
+ static inline constexpr int MAX_CLEAR_EXTENTS = 1000;
+
using view_mask_pair = std::pair<layout_view &, u32>;
using view_mask_vector = std::vector<view_mask_pair>;
// private classes declared in render.cpp
struct object_transform;
+ struct pointer_info;
+ struct hit_test;
+
+ using pointer_info_vector = std::vector<pointer_info>;
+ using hit_test_vector = std::vector<hit_test>;
// internal helpers
enum constructor_impl_t { CONSTRUCTOR_IMPL };
- template <typename T> render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t);
+ template <typename T> render_target(render_manager &manager, render_container *ui, T&& layout, u32 flags, constructor_impl_t);
void update_layer_config();
void load_layout_files(const internal_layout *layoutfile, bool singlefile);
void load_layout_files(util::xml::data_node const &rootnode, bool singlefile);
@@ -584,9 +596,10 @@ private:
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item);
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
+ std::pair<float, float> map_point_layout(s32 target_x, s32 target_y);
// config callbacks
- void config_load(util::xml::data_node const &targetnode);
+ void config_load(util::xml::data_node const *targetnode);
bool config_save(util::xml::data_node &targetnode);
// view lookups
@@ -599,13 +612,10 @@ private:
void add_clear_extents(render_primitive_list &list);
void add_clear_and_optimize_primitive_list(render_primitive_list &list);
- // constants
- static constexpr int NUM_PRIMLISTS = 3;
- static constexpr int MAX_CLEAR_EXTENTS = 1000;
-
// internal state
render_target * m_next; // link to next target
render_manager & m_manager; // reference to our owning manager
+ render_container *const m_ui_container; // container for drawing UI elements
std::list<layout_file> m_filelist; // list of layout files
view_mask_vector m_views; // views we consider
unsigned m_curview; // current view index
@@ -624,7 +634,8 @@ private:
float m_max_refresh; // maximum refresh rate, 0 or if none
int m_orientation; // orientation
render_layer_config m_layerconfig; // layer configuration
- std::vector<bool> m_hit_test; // used when mapping points to inputs
+ pointer_info_vector m_pointers; // state of pointers over this target
+ hit_test_vector m_clickable_items; // for tracking clicked elements
layout_view * m_base_view; // the view at the time of first frame
int m_base_orientation; // the orientation at the time of first frame
render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame
@@ -671,7 +682,7 @@ public:
float ui_aspect(render_container *rc = nullptr);
// UI containers
- render_container &ui_container() const { assert(m_ui_container != nullptr); return *m_ui_container; }
+ render_container &ui_container() const { assert(ui_target().ui_container()); return *ui_target().ui_container(); }
// textures
render_texture *texture_alloc(texture_scaler_func scaler = nullptr, void *param = nullptr);
@@ -692,20 +703,20 @@ private:
void config_save(config_type cfg_type, util::xml::data_node *parentnode);
// internal state
- running_machine & m_machine; // reference back to the machine
+ running_machine & m_machine; // reference back to the machine
// array of live targets
- simple_list<render_target> m_targetlist; // list of targets
- render_target * m_ui_target; // current UI target
+ simple_list<render_target> m_targetlist; // list of targets
+ render_target * m_ui_target; // current UI target
// texture lists
- u32 m_live_textures; // number of live textures
- u64 m_texture_id; // rolling texture ID counter
- fixed_allocator<render_texture> m_texture_allocator;// texture allocator
+ u32 m_live_textures; // number of live textures
+ u64 m_texture_id; // rolling texture ID counter
+ fixed_allocator<render_texture> m_texture_allocator; // texture allocator
- // containers for the UI and for screens
- std::unique_ptr<render_container> m_ui_container; // UI container
- std::list<render_container> m_screen_container_list; // list of containers for the screen
+ // containers for UI elements and for screens
+ std::list<render_container> m_ui_containers; // containers for drawing UI elements
+ std::list<render_container> m_screen_container_list; // list of containers for the screen
};
#endif // MAME_EMU_RENDER_H
diff --git a/src/emu/rendersw.hxx b/src/emu/rendersw.hxx
index aa7b2253795..5561928e7df 100644
--- a/src/emu/rendersw.hxx
+++ b/src/emu/rendersw.hxx
@@ -153,7 +153,10 @@ private:
}
else
{
- u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1);
+ s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1);
+
+ u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + v * texture.rowpixels + u;
return palbase[texbase[0]];
}
}
@@ -185,7 +188,10 @@ private:
}
else
{
- u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 16);
+ s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1);
+ s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1);
+
+ u16 const *const texbase = reinterpret_cast<u16 const *>(texture.base) + v * texture.rowpixels + u;
return palbase[texbase[0]];
}
}
@@ -247,8 +253,11 @@ private:
}
else
{
- const u16 *texbase = reinterpret_cast<const u16 *>(texture.base) + (curv >> 16) * texture.rowpixels + (curu >> 17) * 2;
- return (texbase[(curu >> 16) & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
+ s32 u = std::clamp<s32>(curu >> 16, 0, texture.width - 1);
+ s32 v = std::clamp<s32>(curv >> 16, 0, texture.height - 1);
+
+ const u16 *texbase = reinterpret_cast<const u16 *>(texture.base) + v * texture.rowpixels + (u >> 1) * 2;
+ return (texbase[u & 1] >> 8) | ((texbase[0] & 0xff) << 8) | ((texbase[1] & 0xff) << 16);
}
}
diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h
index 43f2ebb85e7..b3eed6ad9bd 100644
--- a/src/emu/rendertypes.h
+++ b/src/emu/rendertypes.h
@@ -20,6 +20,16 @@
//**************************************************************************
+// texture formats
+enum texture_format
+{
+ TEXFORMAT_UNDEFINED = 0, // require a format to be specified
+ TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha
+ TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB
+ TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB
+ TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence
+};
+
// blending modes
enum
{
diff --git a/src/emu/rendfont.cpp b/src/emu/rendfont.cpp
index ae295e39e2d..259d7731fe5 100644
--- a/src/emu/rendfont.cpp
+++ b/src/emu/rendfont.cpp
@@ -10,9 +10,14 @@
#include "emu.h"
#include "rendfont.h"
+
#include "emuopts.h"
+#include "fileio.h"
+#include "render.h"
+
#include "corestr.h"
-#include "coreutil.h"
+#include "multibyte.h"
+#include "path.h"
#include "osdepend.h"
#include "uismall.fh"
@@ -121,13 +126,14 @@ public:
static constexpr unsigned MAJVERSION = 1;
static constexpr unsigned MINVERSION = 0;
- bool read(emu_file &f)
+ bool read(util::read_stream &f)
{
- return f.read(m_data, sizeof(m_data)) == sizeof(m_data);
+ auto const [err, actual] = util::read(f, m_data, sizeof(m_data));
+ return !err && (actual == sizeof(m_data));
}
- bool write(emu_file &f)
+ bool write(util::write_stream &f)
{
- return f.write(m_data, sizeof(m_data)) == sizeof(m_data);
+ return !util::write(f, m_data, sizeof(m_data)).first;
}
bool check_magic() const
@@ -144,51 +150,27 @@ public:
}
u64 get_original_length() const
{
- return
- (u64(m_data[OFFS_ORIGLENGTH + 0]) << (7 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 1]) << (6 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 2]) << (5 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 3]) << (4 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 4]) << (3 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 5]) << (2 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 6]) << (1 * 8)) |
- (u64(m_data[OFFS_ORIGLENGTH + 7]) << (0 * 8));
+ return get_u64be(m_data + OFFS_ORIGLENGTH);
}
u32 get_original_hash() const
{
- return
- (u32(m_data[OFFS_ORIGHASH + 0]) << (3 * 8)) |
- (u32(m_data[OFFS_ORIGHASH + 1]) << (2 * 8)) |
- (u32(m_data[OFFS_ORIGHASH + 2]) << (1 * 8)) |
- (u32(m_data[OFFS_ORIGHASH + 3]) << (0 * 8));
+ return get_u32be(m_data + OFFS_ORIGHASH);
}
u32 get_glyph_count() const
{
- return
- (u32(m_data[OFFS_GLYPHCOUNT + 0]) << (3 * 8)) |
- (u32(m_data[OFFS_GLYPHCOUNT + 1]) << (2 * 8)) |
- (u32(m_data[OFFS_GLYPHCOUNT + 2]) << (1 * 8)) |
- (u32(m_data[OFFS_GLYPHCOUNT + 3]) << (0 * 8));
+ return get_u32be(m_data + OFFS_GLYPHCOUNT);
}
u16 get_height() const
{
- return
- (u16(m_data[OFFS_HEIGHT + 0]) << (1 * 8)) |
- (u16(m_data[OFFS_HEIGHT + 1]) << (0 * 8));
+ return get_u16be(m_data + OFFS_HEIGHT);
}
s16 get_y_offset() const
{
- return
- (u16(m_data[OFFS_YOFFSET + 0]) << (1 * 8)) |
- (u16(m_data[OFFS_YOFFSET + 1]) << (0 * 8));
+ return get_u16be(m_data + OFFS_YOFFSET);
}
s32 get_default_character() const
{
- return
- (u32(m_data[OFFS_DEFCHAR + 0]) << (3 * 8)) |
- (u32(m_data[OFFS_DEFCHAR + 1]) << (2 * 8)) |
- (u32(m_data[OFFS_DEFCHAR + 2]) << (1 * 8)) |
- (u32(m_data[OFFS_DEFCHAR + 3]) << (0 * 8));
+ return get_u32be(m_data + OFFS_DEFCHAR);
}
void set_magic()
@@ -202,45 +184,27 @@ public:
}
void set_original_length(u64 value)
{
- m_data[OFFS_ORIGLENGTH + 0] = u8((value >> (7 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 1] = u8((value >> (6 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 2] = u8((value >> (5 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 3] = u8((value >> (4 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 4] = u8((value >> (3 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 5] = u8((value >> (2 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 6] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_ORIGLENGTH + 7] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u64be(m_data + OFFS_ORIGLENGTH, value);
}
void set_original_hash(u32 value)
{
- m_data[OFFS_ORIGHASH + 0] = u8((value >> (3 * 8)) & 0x00ff);
- m_data[OFFS_ORIGHASH + 1] = u8((value >> (2 * 8)) & 0x00ff);
- m_data[OFFS_ORIGHASH + 2] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_ORIGHASH + 3] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u32be(m_data + OFFS_ORIGHASH, value);
}
void set_glyph_count(u32 value)
{
- m_data[OFFS_GLYPHCOUNT + 0] = u8((value >> (3 * 8)) & 0x00ff);
- m_data[OFFS_GLYPHCOUNT + 1] = u8((value >> (2 * 8)) & 0x00ff);
- m_data[OFFS_GLYPHCOUNT + 2] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_GLYPHCOUNT + 3] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u32be(m_data + OFFS_GLYPHCOUNT, value);
}
void set_height(u16 value)
{
- m_data[OFFS_HEIGHT + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_HEIGHT + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_data + OFFS_HEIGHT, value);
}
void set_y_offset(s16 value)
{
- m_data[OFFS_YOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_YOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_data + OFFS_YOFFSET, value);
}
void set_default_character(s32 value)
{
- m_data[OFFS_DEFCHAR + 0] = u8((value >> (3 * 8)) & 0x00ff);
- m_data[OFFS_DEFCHAR + 1] = u8((value >> (2 * 8)) & 0x00ff);
- m_data[OFFS_DEFCHAR + 2] = u8((value >> (1 * 8)) & 0x00ff);
- m_data[OFFS_DEFCHAR + 3] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u32be(m_data + OFFS_DEFCHAR, value);
}
private:
@@ -280,74 +244,52 @@ public:
u32 get_encoding() const
{
- return
- (u32(m_ptr[OFFS_ENCODING + 0]) << (3 * 8)) |
- (u32(m_ptr[OFFS_ENCODING + 1]) << (2 * 8)) |
- (u32(m_ptr[OFFS_ENCODING + 2]) << (1 * 8)) |
- (u32(m_ptr[OFFS_ENCODING + 3]) << (0 * 8));
+ return get_u32be(m_ptr + OFFS_ENCODING);
}
u16 get_x_advance() const
{
- return
- (u16(m_ptr[OFFS_XADVANCE + 0]) << (1 * 8)) |
- (u16(m_ptr[OFFS_XADVANCE + 1]) << (0 * 8));
+ return get_u16be(m_ptr + OFFS_XADVANCE);
}
s16 get_bb_x_offset() const
{
- return
- (u16(m_ptr[OFFS_BBXOFFSET + 0]) << (1 * 8)) |
- (u16(m_ptr[OFFS_BBXOFFSET + 1]) << (0 * 8));
+ return get_u16be(m_ptr + OFFS_BBXOFFSET);
}
s16 get_bb_y_offset() const
{
- return
- (u16(m_ptr[OFFS_BBYOFFSET + 0]) << (1 * 8)) |
- (u16(m_ptr[OFFS_BBYOFFSET + 1]) << (0 * 8));
+ return get_u16be(m_ptr + OFFS_BBYOFFSET);
}
u16 get_bb_width() const
{
- return
- (u16(m_ptr[OFFS_BBWIDTH + 0]) << (1 * 8)) |
- (u16(m_ptr[OFFS_BBWIDTH + 1]) << (0 * 8));
+ return get_u16be(m_ptr + OFFS_BBWIDTH);
}
u16 get_bb_height() const
{
- return
- (u16(m_ptr[OFFS_BBHEIGHT + 0]) << (1 * 8)) |
- (u16(m_ptr[OFFS_BBHEIGHT + 1]) << (0 * 8));
+ return get_u16be(m_ptr + OFFS_BBHEIGHT);
}
void set_encoding(u32 value)
{
- m_ptr[OFFS_ENCODING + 0] = u8((value >> (3 * 8)) & 0x00ff);
- m_ptr[OFFS_ENCODING + 1] = u8((value >> (2 * 8)) & 0x00ff);
- m_ptr[OFFS_ENCODING + 2] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_ENCODING + 3] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u32be(m_ptr + OFFS_ENCODING, value);
}
void set_x_advance(u16 value)
{
- m_ptr[OFFS_XADVANCE + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_XADVANCE + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_ptr + OFFS_XADVANCE, value);
}
void set_bb_x_offset(s16 value)
{
- m_ptr[OFFS_BBXOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_BBXOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_ptr + OFFS_BBXOFFSET, value);
}
void set_bb_y_offset(s16 value)
{
- m_ptr[OFFS_BBYOFFSET + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_BBYOFFSET + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_ptr + OFFS_BBYOFFSET, value);
}
void set_bb_width(u16 value)
{
- m_ptr[OFFS_BBWIDTH + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_BBWIDTH + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_ptr + OFFS_BBWIDTH, value);
}
void set_bb_height(u16 value)
{
- m_ptr[OFFS_BBHEIGHT + 0] = u8((value >> (1 * 8)) & 0x00ff);
- m_ptr[OFFS_BBHEIGHT + 1] = u8((value >> (0 * 8)) & 0x00ff);
+ put_u16be(m_ptr + OFFS_BBHEIGHT, value);
}
bdc_table_entry &operator=(bdc_table_entry const &that) = default;
@@ -593,10 +535,9 @@ render_font::render_font(render_manager &manager, const char *filename)
}
// load the compiled in data instead
- emu_file ramfile(OPEN_FLAG_READ);
- std::error_condition const filerr(ramfile.open_ram(font_uismall, sizeof(font_uismall)));
- if (!filerr)
- load_cached(ramfile, 0, 0);
+ util::random_read::ptr ramfile = util::ram_read(font_uismall, sizeof(font_uismall));
+ if (ramfile)
+ load_cached(*ramfile, 0, 0);
render_font_command_glyph();
}
@@ -668,7 +609,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl)
if (accumbit == 7)
accum = *ptr++;
if (dest != nullptr)
- *dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol;
+ *dest++ = BIT(accum, accumbit) ? fgcol : bgcol;
accumbit = (accumbit - 1) & 7;
}
}
@@ -764,7 +705,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl)
if (accumbit == 7)
accum = *ptr++;
if (dest != nullptr)
- *dest++ = (accum & (1 << accumbit)) ? fgcol : bgcol;
+ *dest++ = BIT(accum, accumbit) ? fgcol : bgcol;
accumbit = (accumbit - 1) & 7;
}
}
@@ -817,7 +758,8 @@ void render_font::get_scaled_bitmap_and_bounds(bitmap_argb32 &dest, float height
bounds.min_y = 0;
// compute x1,y1 from there based on the bitmap size
- bounds.set_width(float(gl.bmwidth) * scale * aspect);
+ float width = float(gl.bmwidth) * scale * aspect;
+ bounds.set_width(width < 0.5f ? 0 : std::max(int(width), 1));
bounds.set_height(float(m_height) * scale);
// if the bitmap isn't big enough, bail
@@ -861,14 +803,15 @@ float render_font::string_width(float height, float aspect, std::string_view str
char32_t schar;
// loop over characters
- while (!string.empty())
+ int scharcount;
+ while ((scharcount = uchar_from_utf8(&schar, string)) != 0)
{
- int scharcount = uchar_from_utf8(&schar, string);
+ if (0 > scharcount)
+ schar = 0xfffd;
+ string.remove_prefix((0 > scharcount) ? 1 : scharcount);
totwidth += get_char(schar).width;
- string.remove_prefix(scharcount);
}
-
// scale the final result based on height
return float(totwidth) * m_scale * height * aspect;
}
@@ -906,11 +849,11 @@ float render_font::utf8string_width(float height, float aspect, std::string_view
// and create a new cached version
//-------------------------------------------------
-bool render_font::load_cached_bdf(const char *filename)
+bool render_font::load_cached_bdf(std::string_view filename)
{
std::error_condition filerr;
u32 chunk;
- u64 bytes;
+ std::size_t bytes;
// first try to open the BDF itself
emu_file file(m_manager.machine().options().font_path(), OPEN_FLAG_READ);
@@ -940,12 +883,10 @@ bool render_font::load_cached_bdf(const char *filename)
m_rawdata.clear();
return false;
}
- u32 const hash(core_crc32(0, reinterpret_cast<u8 const *>(&m_rawdata[0]), bytes));
+ u32 const hash(util::crc32_creator::simple(&m_rawdata[0], bytes));
// create the cached filename, changing the 'F' to a 'C' on the extension
- std::string cachedname(filename);
- if ((4U < cachedname.length()) && !core_stricmp(&cachedname[cachedname.length() - 4], ".bdf"))
- cachedname.erase(cachedname.length() - 4);
+ std::string cachedname(filename, 0, filename.length() - ((4U < filename.length()) && core_filename_ends_with(filename, ".bdf") ? 4 : 0));
cachedname.append(".bdc");
// attempt to open the cached version of the font
@@ -978,11 +919,25 @@ bool render_font::load_cached_bdf(const char *filename)
m_rawdata[m_rawsize] = '\0';
// load the BDF
- bool const result = load_bdf();
+ bool result = load_bdf();
// if we loaded okay, create a cached one
if (result)
- save_cached(cachedname.c_str(), m_rawsize, hash);
+ {
+ osd_printf_info("Generating cached BDF font...\n");
+
+ // attempt to open the file
+ emu_file cachefile(m_manager.machine().options().font_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ filerr = cachefile.open(cachedname);
+ if (filerr)
+ result = false;
+ else
+ {
+ result = save_cached(cachefile, m_rawsize, hash);
+ if (!result)
+ cachefile.remove_on_close();
+ }
+ }
else
m_rawdata.clear();
@@ -1324,7 +1279,7 @@ bool render_font::load_bdf()
// some progress for big fonts
if (0 == (++charcount % 256))
- osd_printf_warning("Loading BDF font... (%d characters loaded)\n", charcount);
+ osd_printf_info("Loading BDF font... (%d characters loaded)\n", charcount);
}
}
@@ -1344,12 +1299,17 @@ bool render_font::load_bdf()
// load_cached - load a font in cached format
//-------------------------------------------------
-bool render_font::load_cached(emu_file &file, u64 length, u32 hash)
+bool render_font::load_cached(util::random_read &file, u64 length, u32 hash)
{
// get the file size, read the header, and check that it looks good
- u64 const filesize(file.size());
+ u64 filesize;
bdc_header header;
- if (!header.read(file))
+ if (file.length(filesize))
+ {
+ LOG("render_font::load_cached: error determining size of BDC file\n");
+ return false;
+ }
+ else if (!header.read(file))
{
osd_printf_warning("render_font::load_cached: error reading BDC header\n");
return false;
@@ -1371,14 +1331,25 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash)
m_yoffs = header.get_y_offset();
m_defchar = header.get_default_character();
u32 const numchars(header.get_glyph_count());
- if ((file.tell() + (u64(numchars) * bdc_table_entry::size())) > filesize)
+ u64 filepos;
+ if (file.tell(filepos))
+ {
+ LOG("render_font::load_cached: failed to determine position in BDC file\n");
+ return false;
+ }
+ else if ((filepos + (u64(numchars) * bdc_table_entry::size())) > filesize)
{
LOG("render_font::load_cached: BDC file is too small to hold glyph table\n");
return false;
}
// now read the rest of the data
- u64 const remaining(filesize - file.tell());
+ u64 const remaining(filesize - filepos);
+ if (remaining > std::numeric_limits<std::size_t>::max())
+ {
+ osd_printf_error("render_font::load_cached: BDC file is too large to read into memory\n");
+ return false;
+ }
try
{
m_rawdata.resize(std::size_t(remaining));
@@ -1386,17 +1357,14 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash)
catch (...)
{
osd_printf_error("render_font::load_cached: allocation error\n");
+ return false;
}
- for (u64 bytes_read = 0; remaining > bytes_read; )
+ auto const [err, bytes] = read(file, &m_rawdata[0], remaining);
+ if (err || (bytes != remaining))
{
- u32 const chunk((std::min)(u64(std::numeric_limits<u32>::max()), remaining));
- if (file.read(&m_rawdata[bytes_read], chunk) != chunk)
- {
- osd_printf_error("render_font::load_cached: error reading BDC data\n");
- m_rawdata.clear();
- return false;
- }
- bytes_read += chunk;
+ osd_printf_error("render_font::load_cached: error reading BDC data\n");
+ m_rawdata.clear();
+ return false;
}
// extract the data from the data
@@ -1450,16 +1418,8 @@ bool render_font::load_cached(emu_file &file, u64 length, u32 hash)
// save_cached - save a font in cached format
//-------------------------------------------------
-bool render_font::save_cached(const char *filename, u64 length, u32 hash)
+bool render_font::save_cached(util::random_write &file, u64 length, u32 hash)
{
- osd_printf_warning("Generating cached BDF font...\n");
-
- // attempt to open the file
- emu_file file(m_manager.machine().options().font_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
- std::error_condition const filerr = file.open(filename);
- if (filerr)
- return false;
-
// count glyphs
unsigned numchars = 0;
for (glyph const *const page : m_glyphs)
@@ -1474,8 +1434,6 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
try
{
- u32 bytes_written;
-
{
LOG("render_font::save_cached: writing header\n");
bdc_header hdr;
@@ -1488,9 +1446,11 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
hdr.set_y_offset(m_yoffs);
hdr.set_default_character(m_defchar);
if (!hdr.write(file))
- throw emu_fatalerror("Error writing cached file");
+ throw emu_fatalerror("Error writing cached font file");
}
- u64 const table_offs(file.tell());
+ u64 table_offs;
+ if (file.tell(table_offs))
+ throw emu_fatalerror("Error writing cached font file");
// allocate an array to hold the character data
std::vector<u8> chartable(std::size_t(numchars) * bdc_table_entry::size(), 0);
@@ -1499,9 +1459,8 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
std::vector<u8> tempbuffer(65536);
// write the empty table to the beginning of the file
- bytes_written = file.write(&chartable[0], chartable.size());
- if (bytes_written != chartable.size())
- throw emu_fatalerror("Error writing cached file");
+ if (write(file, &chartable[0], chartable.size()).first)
+ throw emu_fatalerror("Error writing cached font file");
// loop over all characters
bdc_table_entry table_entry(chartable.empty() ? nullptr : &chartable[0]);
@@ -1543,9 +1502,8 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
*dest++ = accum;
// write the data
- bytes_written = file.write(&tempbuffer[0], dest - &tempbuffer[0]);
- if (bytes_written != dest - &tempbuffer[0])
- throw emu_fatalerror("Error writing cached file");
+ if (write(file, &tempbuffer[0], dest - &tempbuffer[0]).first)
+ throw emu_fatalerror("Error writing cached font file");
// free the bitmap and texture
m_manager.texture_free(gl.texture);
@@ -1568,17 +1526,10 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
if (!chartable.empty())
{
LOG("render_font::save_cached: writing character table\n");
- file.seek(table_offs, SEEK_SET);
- u8 const *bytes(&chartable[0]);
- for (u64 remaining = chartable.size(); remaining; )
- {
- u32 const chunk((std::min<u64>)(std::numeric_limits<u32>::max(), remaining));
- bytes_written = file.write(bytes, chunk);
- if (chunk != bytes_written)
- throw emu_fatalerror("Error writing cached file");
- bytes += chunk;
- remaining -= chunk;
- }
+ if (file.seek(table_offs, SEEK_SET))
+ return false;
+ if (write(file, &chartable[0], chartable.size()).first)
+ throw emu_fatalerror("Error writing cached font file");
}
// no trouble?
@@ -1586,7 +1537,6 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
}
catch (...)
{
- file.remove_on_close();
return false;
}
}
@@ -1595,13 +1545,13 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
void render_font::render_font_command_glyph()
{
// FIXME: this is copy/pasta from the BDC loading, and it shouldn't be injected into every font
- emu_file file(OPEN_FLAG_READ);
- if (!file.open_ram(font_uicmd14, sizeof(font_uicmd14)))
+ util::random_read::ptr file = util::ram_read(font_uicmd14, sizeof(font_uicmd14));
+ if (file)
{
// get the file size, read the header, and check that it looks good
- u64 const filesize(file.size());
+ u64 const filesize = sizeof(font_uicmd14);
bdc_header header;
- if (!header.read(file))
+ if (!header.read(*file))
{
osd_printf_warning("render_font::render_font_command_glyph: error reading BDC header\n");
return;
@@ -1616,14 +1566,25 @@ void render_font::render_font_command_glyph()
m_height_cmd = header.get_height();
m_yoffs_cmd = header.get_y_offset();
u32 const numchars(header.get_glyph_count());
- if ((file.tell() + (u64(numchars) * bdc_table_entry::size())) > filesize)
+ u64 filepos;
+ if (file->tell(filepos))
+ {
+ LOG("render_font::render_font_command_glyph: failed to determine position in BDC file\n");
+ return;
+ }
+ else if ((filepos + (u64(numchars) * bdc_table_entry::size())) > filesize)
{
LOG("render_font::render_font_command_glyph: BDC file is too small to hold glyph table\n");
return;
}
// now read the rest of the data
- u64 const remaining(filesize - file.tell());
+ u64 const remaining(filesize - filepos);
+ if (remaining > std::numeric_limits<std::size_t>::max())
+ {
+ osd_printf_error("render_font::render_font_command_glyph: BDC file is too large to read into memory\n");
+ return;
+ }
try
{
m_rawdata_cmd.resize(std::size_t(remaining));
@@ -1631,17 +1592,14 @@ void render_font::render_font_command_glyph()
catch (...)
{
osd_printf_error("render_font::render_font_command_glyph: allocation error\n");
+ return;
}
- for (u64 bytes_read = 0; remaining > bytes_read; )
+ auto const [err, bytes] = read(*file, &m_rawdata_cmd[0], remaining);
+ if (err || (bytes != remaining))
{
- u32 const chunk((std::min)(u64(std::numeric_limits<u32>::max()), remaining));
- if (file.read(&m_rawdata_cmd[bytes_read], chunk) != chunk)
- {
- osd_printf_error("render_font::render_font_command_glyph: error reading BDC data\n");
- m_rawdata_cmd.clear();
- return;
- }
- bytes_read += chunk;
+ osd_printf_error("render_font::render_font_command_glyph: error reading BDC data\n");
+ m_rawdata_cmd.clear();
+ return;
}
// extract the data from the data
diff --git a/src/emu/rendfont.h b/src/emu/rendfont.h
index 15f6754657b..9ada358ed5d 100644
--- a/src/emu/rendfont.h
+++ b/src/emu/rendfont.h
@@ -11,8 +11,6 @@
#ifndef MAME_EMU_RENDFONT_H
#define MAME_EMU_RENDFONT_H
-#include "render.h"
-
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -82,10 +80,10 @@ private:
// helpers
glyph &get_char(char32_t chnum);
void char_expand(char32_t chnum, glyph &ch);
- bool load_cached_bdf(const char *filename);
+ bool load_cached_bdf(std::string_view filename);
bool load_bdf();
- bool load_cached(emu_file &file, u64 length, u32 hash);
- bool save_cached(const char *filename, u64 length, u32 hash);
+ bool load_cached(util::random_read &file, u64 length, u32 hash);
+ bool save_cached(util::random_write &file, u64 length, u32 hash);
void render_font_command_glyph();
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 28011b8372c..be5413f99ae 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -13,6 +13,8 @@
#include "rendlay.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "rendfont.h"
#include "rendutil.h"
#include "video/rgbutil.h"
@@ -58,6 +60,9 @@
// screenless layouts
#include "noscreens.lh"
+// single screen layouts
+#include "monitors.lh"
+
// dual screen layouts
#include "dualhsxs.lh"
#include "dualhovu.lh"
@@ -220,12 +225,18 @@ private:
{
if (m_float_valid)
{
- m_text = std::to_string(m_float);
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+ stream << m_float;
+ m_text = std::move(stream).str();
m_text_valid = true;
}
else if (m_int_valid)
{
- m_text = std::to_string(m_int);
+ std::ostringstream stream;
+ stream.imbue(std::locale::classic());
+ stream << m_int;
+ m_text = std::move(stream).str();
m_text_valid = true;
}
}
@@ -1249,7 +1260,6 @@ layout_element::make_component_map const layout_element::s_make_component{
{ "simplecounter", &make_component<simplecounter_component> },
{ "reel", &make_component<reel_component> },
{ "led7seg", &make_component<led7seg_component> },
- { "led8seg_gts1", &make_component<led8seg_gts1_component> },
{ "led14seg", &make_component<led14seg_component> },
{ "led14segsc", &make_component<led14segsc_component> },
{ "led16seg", &make_component<led16seg_component> },
@@ -1267,6 +1277,7 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele
, m_defstate(env.get_attribute_int(elemnode, "defstate", -1))
, m_statemask(0)
, m_foldhigh(false)
+ , m_invalidated(false)
{
// parse components in order
bool first = true;
@@ -1637,6 +1648,17 @@ render_texture *layout_element::state_texture(int state)
//-------------------------------------------------
+// set_draw_callback - set handler called after
+// drawing components
+//-------------------------------------------------
+
+void layout_element::set_draw_callback(draw_delegate &&handler)
+{
+ m_draw = std::move(handler);
+}
+
+
+//-------------------------------------------------
// preload - perform expensive loading upfront
// for all components
//-------------------------------------------------
@@ -1649,6 +1671,25 @@ void layout_element::preload()
//-------------------------------------------------
+// prepare - perform additional tasks before
+// drawing a frame
+//-------------------------------------------------
+
+void layout_element::prepare()
+{
+ if (m_invalidated)
+ {
+ m_invalidated = false;
+ for (texture &tex : m_elemtex)
+ {
+ machine().render().texture_free(tex.m_texture);
+ tex.m_texture = nullptr;
+ }
+ }
+}
+
+
+//-------------------------------------------------
// element_scale - scale an element by rendering
// all the components at the appropriate
// resolution
@@ -1664,6 +1705,10 @@ void layout_element::element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, c
if ((elemtex.m_state & curcomp->statemask()) == curcomp->stateval())
curcomp->draw(elemtex.m_element->machine(), dest, elemtex.m_state);
}
+
+ // if there's a callback for additional drawing, invoke it
+ if (!elemtex.m_element->m_draw.isnull())
+ elemtex.m_element->m_draw(elemtex.m_state, dest);
}
@@ -1745,10 +1790,10 @@ private:
{
u8 const *const src(reinterpret_cast<u8 const *>(dst));
rgb_t const d(
- u8((float(src[3]) * c.a) + 0.5),
- u8((float(src[0]) * c.r) + 0.5),
- u8((float(src[1]) * c.g) + 0.5),
- u8((float(src[2]) * c.b) + 0.5));
+ u8((float(src[3]) * c.a) + 0.5F),
+ u8((float(src[0]) * c.r) + 0.5F),
+ u8((float(src[1]) * c.g) + 0.5F),
+ u8((float(src[2]) * c.b) + 0.5F));
*dst = d;
havealpha = havealpha || (d.a() < 255U);
}
@@ -2024,17 +2069,12 @@ private:
return;
}
svgbuf[len] = '\0';
- for (char *ptr = svgbuf.get(); len; )
+ size_t actual;
+ std::tie(filerr, actual) = read(file, svgbuf.get(), len);
+ if (filerr || (actual < len))
{
- size_t read;
- filerr = file.read(ptr, size_t(len), read);
- if (filerr || !read)
- {
- osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
- return;
- }
- ptr += read;
- len -= read;
+ osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
+ return;
}
parse_svg(svgbuf.get());
}
@@ -2109,7 +2149,7 @@ protected:
}
else if (c.a)
{
- // compute premultiplied colors
+ // compute premultiplied color
u32 const a(c.a * 255.0F);
u32 const r(u32(c.r * (255.0F * 255.0F)) * a);
u32 const g(u32(c.g * (255.0F * 255.0F)) * a);
@@ -2145,9 +2185,9 @@ public:
render_color const c(color(state));
u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
u32 const a(c.a * 255.0F);
- u32 const r(c.r * c.a * (255.0F * 255.0F * 255.0F));
- u32 const g(c.g * c.a * (255.0F * 255.0F * 255.0F));
- u32 const b(c.b * c.a * (255.0F * 255.0F * 255.0F));
+ u32 const r(c.r * (255.0F * 255.0F) * a);
+ u32 const g(c.g * (255.0F * 255.0F) * a);
+ u32 const b(c.b * (255.0F * 255.0F) * a);
u32 const inva(255 - a);
if (!a)
return;
@@ -2258,17 +2298,13 @@ public:
if ((x >= minfill) && (x <= maxfill))
{
if (255 <= a)
- {
dst = std::fill_n(dst, maxfill - x + 1, f);
- x = maxfill;
- }
else
- {
while (x++ <= maxfill)
alpha_blend(*dst++, a, r, g, b, inva);
- --x;
- }
+
--dst;
+ x = maxfill;
}
else
{
@@ -2370,17 +2406,13 @@ public:
if ((x >= minfill) && (x <= maxfill))
{
if (255 <= a)
- {
dst = std::fill_n(dst, maxfill - x + 1, f);
- x = maxfill;
- }
else
- {
while (x++ <= maxfill)
alpha_blend(*dst++, a, r, g, b, inva);
- --x;
- }
+
--dst;
+ x = maxfill;
}
else
{
@@ -2465,6 +2497,7 @@ public:
led7seg_component(environment &env, util::xml::data_node const &compnode)
: component(env, compnode)
{
+ m_invert = env.get_attribute_int(compnode, "invert", 0);
}
protected:
@@ -2473,8 +2506,8 @@ protected:
virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
- rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
- rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
+ rgb_t const onpen = rgb_t(m_invert ? 0x20 : 0xff, 0xff, 0xff, 0xff);
+ rgb_t const offpen = rgb_t(m_invert ? 0xff : 0x20, 0xff, 0xff, 0xff);
// sizes for computation
int const bmwidth = 250;
@@ -2516,74 +2549,8 @@ protected:
// resample to the target size
render_resample_argb_bitmap_hq(dest, tempbitmap, color(state));
}
-};
-
-
-// 8-segment fluorescent (Gottlieb System 1)
-class layout_element::led8seg_gts1_component : public component
-{
-public:
- // construction/destruction
- led8seg_gts1_component(environment &env, util::xml::data_node const &compnode)
- : component(env, compnode)
- {
- }
-
-protected:
- // overrides
- virtual int maxstate() const override { return 255; }
-
- virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
- {
- rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
- rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
- rgb_t const backpen = rgb_t(0x00, 0x00, 0x00, 0x00);
-
- // sizes for computation
- int const bmwidth = 250;
- int const bmheight = 400;
- int const segwidth = 40;
- int const skewwidth = 40;
-
- // allocate a temporary bitmap for drawing
- bitmap_argb32 tempbitmap(bmwidth + skewwidth, bmheight);
- tempbitmap.fill(backpen);
-
- // top bar
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 0)) ? onpen : offpen);
-
- // top-right bar
- draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 1)) ? onpen : offpen);
-
- // bottom-right bar
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (state & (1 << 2)) ? onpen : offpen);
-
- // bottom bar
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (state & (1 << 3)) ? onpen : offpen);
-
- // bottom-left bar
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 4)) ? onpen : offpen);
-
- // top-left bar
- draw_segment_vertical(tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (state & (1 << 5)) ? onpen : offpen);
-
- // horizontal bars
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3, 2*bmwidth/3 - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen);
- draw_segment_horizontal(tempbitmap, 0 + 2*segwidth/3 + bmwidth/2, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (state & (1 << 6)) ? onpen : offpen);
-
- // vertical bars
- draw_segment_vertical(tempbitmap, 0 + segwidth/3 - 8, bmheight/2 - segwidth/3 + 2, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen);
- draw_segment_vertical(tempbitmap, 0 + segwidth/3, bmheight/2 - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen);
-
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3 - 2, bmheight - segwidth/3 + 8, 2*bmwidth/3 - segwidth/2 - 4, segwidth + 8, backpen);
- draw_segment_vertical(tempbitmap, bmheight/2 + segwidth/3, bmheight - segwidth/3, 2*bmwidth/3 - segwidth/2 - 4, segwidth, (state & (1 << 7)) ? onpen : offpen);
-
- // apply skew
- apply_skew(tempbitmap, 40);
-
- // resample to the target size
- render_resample_argb_bitmap_hq(dest, tempbitmap, color(state));
- }
+private:
+ int m_invert = 0;
};
@@ -3177,7 +3144,7 @@ protected:
// shift the reels a bit based on this param, allows fine tuning
int use_state = (state + m_stateoffset) % max_state_used;
- // compute premultiplied colors
+ // compute premultiplied color
render_color const c(color(state));
u32 const r = c.r * 255.0f;
u32 const g = c.g * 255.0f;
@@ -3259,10 +3226,10 @@ protected:
width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit]);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
- s32 curx = bounds.left() + (bounds.width() - width) / 2;
+ float curx = bounds.left() + (bounds.width() - width) / 2.0f;
// loop over characters
std::string_view s = m_stopnames[fruit];
@@ -3289,7 +3256,7 @@ protected:
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = curx + x + chbounds.left();
+ int effx = int(curx) + x + chbounds.left();
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
@@ -3329,7 +3296,7 @@ private:
// shift the reels a bit based on this param, allows fine tuning
int use_state = (state + m_stateoffset) % max_state_used;
- // compute premultiplied colors
+ // compute premultiplied color
render_color const c(color(state));
u32 const r = c.r * 255.0f;
u32 const g = c.g * 255.0f;
@@ -3407,10 +3374,10 @@ private:
width = font->string_width(dest.height(), aspect, m_stopnames[fruit]);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
- s32 curx = bounds.left();
+ float curx = bounds.left();
// allocate a temporary bitmap
bitmap_argb32 tempbitmap(dest.width(), dest.height());
@@ -3440,7 +3407,7 @@ private:
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = basex + curx + x;
+ int effx = basex + int(curx) + x;
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
@@ -3545,7 +3512,7 @@ layout_element::texture::texture(texture &&that) : texture()
layout_element::texture::~texture()
{
- if (m_element != nullptr)
+ if (m_element)
m_element->machine().render().texture_free(m_texture);
}
@@ -3747,12 +3714,6 @@ void layout_element::component::draw_text(
int align,
const render_color &color)
{
- // compute premultiplied colors
- u32 const r(color.r * 255.0f);
- u32 const g(color.g * 255.0f);
- u32 const b(color.b * 255.0f);
- u32 const a(color.a * 255.0f);
-
// get the width of the string
float aspect = 1.0f;
s32 width;
@@ -3762,11 +3723,11 @@ void layout_element::component::draw_text(
width = font.string_width(bounds.height(), aspect, str);
if (width < bounds.width())
break;
- aspect *= 0.9f;
+ aspect *= 0.95f;
}
// get alignment
- s32 curx;
+ float curx;
switch (align)
{
// left
@@ -3781,7 +3742,7 @@ void layout_element::component::draw_text(
// default to center
default:
- curx = bounds.left() + (bounds.width() - width) / 2;
+ curx = bounds.left() + (bounds.width() - width) / 2.0f;
break;
}
@@ -3811,18 +3772,13 @@ void layout_element::component::draw_text(
u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
- int effx = curx + x + chbounds.left();
+ int effx = int(curx) + x + chbounds.left();
if (effx >= bounds.left() && effx <= bounds.right())
{
u32 spix = rgb_t(src[x]).a();
if (spix != 0)
{
- rgb_t dpix = d[effx];
- u32 ta = (a * (spix + 1)) >> 8;
- u32 tr = (r * ta + dpix.r() * (0x100 - ta)) >> 8;
- u32 tg = (g * ta + dpix.g() * (0x100 - ta)) >> 8;
- u32 tb = (b * ta + dpix.b() * (0x100 - ta)) >> 8;
- d[effx] = rgb_t(tr, tg, tb);
+ alpha_blend(d[effx], color, spix / 255.0);
}
}
}
@@ -4041,9 +3997,20 @@ layout_view::layout_view(
: m_effaspect(1.0f)
, m_name(make_name(env, viewnode))
, m_unqualified_name(env.get_attribute_string(viewnode, "name"))
+ , m_elemmap(elemmap)
, m_defvismask(0U)
, m_has_art(false)
+ , m_show_ptr(false)
+ , m_ptr_time_out(true) // FIXME: add attribute for this
+ , m_exp_show_ptr(-1)
{
+ // check for explicit pointer display setting
+ if (viewnode.get_attribute_string_ptr("showpointers"))
+ {
+ m_show_ptr = env.get_attribute_bool(viewnode, "showpointers", false);
+ m_exp_show_ptr = m_show_ptr ? 1 : 0;
+ }
+
// parse the layout
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
view_environment local(env, m_name.c_str());
@@ -4187,6 +4154,21 @@ bool layout_view::has_visible_screen(screen_device const &screen) const
//-------------------------------------------------
+// prepare_items - perform additional tasks
+// before rendering a frame
+//-------------------------------------------------
+
+void layout_view::prepare_items()
+{
+ if (!m_prepare_items.isnull())
+ m_prepare_items();
+
+ for (auto &[name, element] : m_elemmap)
+ element.prepare();
+}
+
+
+//-------------------------------------------------
// recompute - recompute the bounds and aspect
// ratio of a view and all of its contained items
//-------------------------------------------------
@@ -4206,6 +4188,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// loop over items and filter by visibility mask
bool first = true;
bool scrfirst = true;
+ bool haveinput = false;
for (item &curitem : m_items)
{
if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask())
@@ -4237,9 +4220,15 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// accumulate interactive elements
if (!curitem.clickthrough() || curitem.has_input())
m_interactive_items.emplace_back(curitem);
+ if (curitem.has_input())
+ haveinput = true;
}
}
+ // if show pointers isn't explicitly, update it based on visible items
+ if (0 > m_exp_show_ptr)
+ m_show_ptr = haveinput;
+
// if we have an explicit bounds, override it
if (m_expbounds.x1 > m_expbounds.x0)
m_bounds = m_expbounds;
@@ -4279,6 +4268,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// sort edges of interactive items
LOGMASKED(LOG_INTERACTIVE_ITEMS, "Recalculated view '%s' with %u interactive items\n",
name(), m_interactive_items.size());
+ //std::reverse(m_interactive_items.begin(), m_interactive_items.end()); TODO: flip hit test order to match visual order
m_interactive_edges_x.reserve(m_interactive_items.size() * 2);
m_interactive_edges_y.reserve(m_interactive_items.size() * 2);
for (unsigned i = 0; m_interactive_items.size() > i; ++i)
@@ -4310,6 +4300,29 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
//-------------------------------------------------
+// set_show_pointers - set whether pointers
+// should be displayed
+//-------------------------------------------------
+
+void layout_view::set_show_pointers(bool value) noexcept
+{
+ m_show_ptr = value;
+ m_exp_show_ptr = value ? 1 : 0;
+}
+
+
+//-------------------------------------------------
+// set_pointers_time_out - set whether pointers
+// should be hidden after inactivity
+//-------------------------------------------------
+
+void layout_view::set_hide_inactive_pointers(bool value) noexcept
+{
+ m_ptr_time_out = value;
+}
+
+
+//-------------------------------------------------
// set_prepare_items_callback - set handler called
// before adding items to render target
//-------------------------------------------------
@@ -4343,6 +4356,50 @@ void layout_view::set_recomputed_callback(recomputed_delegate &&handler)
//-------------------------------------------------
+// set_pointer_updated_callback - set handler
+// called for pointer input
+//-------------------------------------------------
+
+void layout_view::set_pointer_updated_callback(pointer_updated_delegate &&handler)
+{
+ m_pointer_updated = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_pointer_left_callback - set handler for
+// pointer leaving normally
+//-------------------------------------------------
+
+void layout_view::set_pointer_left_callback(pointer_left_delegate &&handler)
+{
+ m_pointer_left = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_pointer_aborted_callback - set handler for
+// pointer leaving abnormally
+//-------------------------------------------------
+
+void layout_view::set_pointer_aborted_callback(pointer_left_delegate &&handler)
+{
+ m_pointer_aborted = std::move(handler);
+}
+
+
+//-------------------------------------------------
+// set_forget_pointers_callback - set handler for
+// abandoning pointer input
+//-------------------------------------------------
+
+void layout_view::set_forget_pointers_callback(forget_pointers_delegate &&handler)
+{
+ m_forget_pointers = std::move(handler);
+}
+
+
+//-------------------------------------------------
// preload - perform expensive loading upfront
// for visible elements
//-------------------------------------------------
diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h
index da9edfcf752..23431e7fd92 100644
--- a/src/emu/rendlay.h
+++ b/src/emu/rendlay.h
@@ -16,6 +16,18 @@
#include "rendertypes.h"
#include "screen.h"
+#include "interface/uievents.h"
+
+#include <array>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -61,6 +73,7 @@ class layout_element
{
public:
using environment = emu::render::detail::layout_environment;
+ using draw_delegate = delegate<void (int, bitmap_argb32 &)>;
// construction/destruction
layout_element(environment &env, util::xml::data_node const &elemnode);
@@ -71,8 +84,13 @@ public:
int default_state() const { return m_defstate; }
render_texture *state_texture(int state);
+ // set handlers
+ void set_draw_callback(draw_delegate &&handler);
+
// operations
void preload();
+ void invalidate() { m_invalidated = true; }
+ void prepare();
private:
/// \brief A drawing component within a layout element
@@ -113,16 +131,16 @@ private:
virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state);
// drawing helpers
- void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, std::string_view str, int align, const render_color &color);
- void draw_segment_horizontal_caps(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color);
- void draw_segment_horizontal(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, rgb_t color);
- void draw_segment_vertical_caps(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color);
- void draw_segment_vertical(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, rgb_t color);
- void draw_segment_diagonal_1(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
- void draw_segment_diagonal_2(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
- void draw_segment_decimal(bitmap_argb32 &dest, int midx, int midy, int width, rgb_t color);
- void draw_segment_comma(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
- void apply_skew(bitmap_argb32 &dest, int skewwidth);
+ static void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, std::string_view str, int align, const render_color &color);
+ static void draw_segment_horizontal_caps(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color);
+ static void draw_segment_horizontal(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, rgb_t color);
+ static void draw_segment_vertical_caps(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color);
+ static void draw_segment_vertical(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, rgb_t color);
+ static void draw_segment_diagonal_1(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
+ static void draw_segment_diagonal_2(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
+ static void draw_segment_decimal(bitmap_argb32 &dest, int midx, int midy, int width, rgb_t color);
+ static void draw_segment_comma(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
+ static void apply_skew(bitmap_argb32 &dest, int skewwidth);
private:
using bounds_vector = emu::render::detail::bounds_vector;
@@ -141,7 +159,6 @@ private:
class disk_component;
class text_component;
class led7seg_component;
- class led8seg_gts1_component;
class led14seg_component;
class led16seg_component;
class led14segsc_component;
@@ -173,7 +190,6 @@ private:
// internal helpers
static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode);
- template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode);
static make_component_map const s_make_component; // maps component XML names to creator functions
@@ -184,6 +200,8 @@ private:
int m_statemask; // mask to apply to state values
bool m_foldhigh; // whether we need to fold state values above the mask range
std::vector<texture> m_elemtex; // array of element textures used for managing the scaled bitmaps
+ draw_delegate m_draw; // draw delegate (called after components are drawn)
+ bool m_invalidated; // force redrawing on next frame if set
};
@@ -281,7 +299,7 @@ public:
// interactivity
bool has_input() const { return bool(m_input_port); }
- std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); }
bool clickthrough() const { return m_clickthrough; }
// fetch state based on configured source
@@ -420,6 +438,9 @@ public:
using prepare_items_delegate = delegate<void ()>;
using preload_delegate = delegate<void ()>;
using recomputed_delegate = delegate<void ()>;
+ using pointer_updated_delegate = delegate<void (osd::ui_event_handler::pointer, u16, u16, float, float, u32, u32, u32, s16)>;
+ using pointer_left_delegate = delegate<void (osd::ui_event_handler::pointer, u16, u16, float, float, u32, s16)>;
+ using forget_pointers_delegate = delegate<void ()>;
using item = layout_view_item;
using item_list = std::list<item>;
@@ -506,20 +527,52 @@ public:
const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
u32 default_visibility_mask() const { return m_defvismask; }
bool has_art() const { return m_has_art; }
+ bool show_pointers() const { return m_show_ptr; }
+ bool hide_inactive_pointers() const { return m_ptr_time_out; }
+
+ // setters
+ void set_show_pointers(bool value) noexcept;
+ void set_hide_inactive_pointers(bool value) noexcept ATTR_COLD;
// set handlers
- void set_prepare_items_callback(prepare_items_delegate &&handler);
- void set_preload_callback(preload_delegate &&handler);
- void set_recomputed_callback(recomputed_delegate &&handler);
+ void set_prepare_items_callback(prepare_items_delegate &&handler) ATTR_COLD;
+ void set_preload_callback(preload_delegate &&handler) ATTR_COLD;
+ void set_recomputed_callback(recomputed_delegate &&handler) ATTR_COLD;
+ void set_pointer_updated_callback(pointer_updated_delegate &&handler) ATTR_COLD;
+ void set_pointer_left_callback(pointer_left_delegate &&handler) ATTR_COLD;
+ void set_pointer_aborted_callback(pointer_left_delegate &&handler) ATTR_COLD;
+ void set_forget_pointers_callback(forget_pointers_delegate &&handler) ATTR_COLD;
// operations
- void prepare_items() { if (!m_prepare_items.isnull()) m_prepare_items(); }
+ void prepare_items();
void recompute(u32 visibility_mask, bool zoom_to_screens);
void preload();
// resolve tags, if any
void resolve_tags();
+ // pointer input
+ void pointer_updated(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 buttons, u32 pressed, u32 released, s16 clicks)
+ {
+ if (!m_pointer_updated.isnull())
+ m_pointer_updated(type, ptrid, device, x, y, buttons, pressed, released, clicks);
+ }
+ void pointer_left(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 released, s16 clicks)
+ {
+ if (!m_pointer_left.isnull())
+ m_pointer_left(type, ptrid, device, x, y, released, clicks);
+ }
+ void pointer_aborted(osd::ui_event_handler::pointer type, u16 ptrid, u16 device, float x, float y, u32 released, s16 clicks)
+ {
+ if (!m_pointer_aborted.isnull())
+ m_pointer_aborted(type, ptrid, device, x, y, released, clicks);
+ }
+ void forget_pointers()
+ {
+ if (!m_forget_pointers.isnull())
+ m_forget_pointers();
+ }
+
private:
struct layer_lists;
@@ -560,15 +613,23 @@ private:
prepare_items_delegate m_prepare_items; // prepare items for adding to render container
preload_delegate m_preload; // additional actions when visible items change
recomputed_delegate m_recomputed; // additional actions on resizing/visibility change
+ pointer_updated_delegate m_pointer_updated; // pointer state updated
+ pointer_left_delegate m_pointer_left; // pointer left normally
+ pointer_left_delegate m_pointer_aborted; // pointer left abnormally
+ forget_pointers_delegate m_forget_pointers; // stop processing pointer input
// cold items
std::string m_name; // display name for the view
std::string m_unqualified_name; // the name exactly as specified in the layout file
+ element_map & m_elemmap; // reference to shared elements
item_id_map m_items_by_id; // items with non-empty ID indexed by ID
visibility_toggle_vector m_vistoggles; // collections of items that can be shown/hidden
render_bounds m_expbounds; // explicit bounds of the view
u32 m_defvismask; // default visibility mask
bool m_has_art; // true if the layout contains non-screen elements
+ bool m_show_ptr; // whether pointers should be displayed
+ bool m_ptr_time_out; // whether pointers should be hidden after inactivity
+ s8 m_exp_show_ptr; // explicitly configured pointer visibility
};
@@ -590,6 +651,7 @@ public:
// getters
device_t &device() const { return m_device; }
+ element_map &elements() { return m_elemmap; }
element_map const &elements() const { return m_elemmap; }
view_list &views() { return m_viewlist; }
view_list const &views() const { return m_viewlist; }
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index 2d0a823db28..5d09061ab70 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -19,29 +19,29 @@
#include <csetjmp>
#include <cstdlib>
+#include <tuple>
namespace {
struct jpeg_corefile_source : public jpeg_source_mgr
{
- static void source(j_decompress_ptr cinfo, util::random_read &file);
+ static void source(j_decompress_ptr cinfo, util::random_read &file) noexcept;
private:
static constexpr unsigned INPUT_BUF_SIZE = 4096;
- static void do_init(j_decompress_ptr cinfo)
+ static void do_init(j_decompress_ptr cinfo) noexcept
{
jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
src.start_of_file = true;
}
- static boolean do_fill(j_decompress_ptr cinfo)
+ static boolean do_fill(j_decompress_ptr cinfo) noexcept
{
jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
- size_t nbytes;
- src.infile->read(src.buffer, INPUT_BUF_SIZE, nbytes); // TODO: check error return
+ auto [err, nbytes] = read(*src.infile, src.buffer, INPUT_BUF_SIZE); // TODO: check error return
if (0 >= nbytes)
{
@@ -60,7 +60,7 @@ private:
return TRUE;
}
- static void do_skip(j_decompress_ptr cinfo, long num_bytes)
+ static void do_skip(j_decompress_ptr cinfo, long num_bytes) noexcept
{
jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
@@ -69,14 +69,14 @@ private:
while (long(src.bytes_in_buffer) < num_bytes)
{
num_bytes -= long(src.bytes_in_buffer);
- (void)(*src.fill_input_buffer)(cinfo);
+ std::ignore = (*src.fill_input_buffer)(cinfo);
}
src.next_input_byte += size_t(num_bytes);
src.bytes_in_buffer -= size_t(num_bytes);
}
}
- static void do_term(j_decompress_ptr cinfo)
+ static void do_term(j_decompress_ptr cinfo) noexcept
{
}
@@ -85,7 +85,7 @@ private:
bool start_of_file;
};
-void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &file)
+void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &file) noexcept
{
jpeg_corefile_source *src;
if (!cinfo->src)
@@ -120,7 +120,7 @@ void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::random_read &fil
struct jpeg_setjmp_error_mgr : public jpeg_error_mgr
{
- jpeg_setjmp_error_mgr()
+ jpeg_setjmp_error_mgr() noexcept
{
jpeg_std_error(this);
error_exit = [] (j_common_ptr cinfo) { std::longjmp(static_cast<jpeg_setjmp_error_mgr *>(cinfo->err)->m_jump_buffer, 1); };
@@ -137,9 +137,9 @@ struct jpeg_setjmp_error_mgr : public jpeg_error_mgr
***************************************************************************/
/* utilities */
-static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
-static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png);
+static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept;
+static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept;
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png) noexcept;
@@ -152,15 +152,15 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info
quality resampling of a texture
-------------------------------------------------*/
-void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force)
+void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force) noexcept
{
if (dest.width() == 0 || dest.height() == 0)
return;
- /* adjust the source base */
+ // adjust the source base
const u32 *sbase = &source.pix(0);
- /* determine the steppings */
+ // determine the steppings
u32 swidth = source.width();
u32 sheight = source.height();
u32 dwidth = dest.width();
@@ -168,7 +168,7 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
u32 dx = (swidth << 12) / dwidth;
u32 dy = (sheight << 12) / dheight;
- /* if the source is higher res than the target, use full averaging */
+ // if the source is higher res than the target, use full averaging
if (dx > 0x1000 || dy > 0x1000 || force)
resample_argb_bitmap_average(&dest.pix(0), dest.rowpixels(), dwidth, dheight, sbase, source.rowpixels(), swidth, sheight, color, dx, dy);
else
@@ -182,62 +182,58 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
all contributing pixels
-------------------------------------------------*/
-static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy)
+static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept
{
- u64 sumscale = u64(dx) * u64(dy);
- u32 r, g, b, a;
- u32 x, y;
-
- /* precompute premultiplied R/G/B/A factors */
- r = color.r * color.a * 256.0f;
- g = color.g * color.a * 256.0f;
- b = color.b * color.a * 256.0f;
- a = color.a * 256.0f;
-
- /* loop over the target vertically */
- for (y = 0; y < dheight; y++)
+ u64 const sumscale = u64(dx) * u64(dy);
+
+ // precompute premultiplied R/G/B/A factors
+ u32 const r = color.r * color.a * 256.0f;
+ u32 const g = color.g * color.a * 256.0f;
+ u32 const b = color.b * color.a * 256.0f;
+ u32 const a = color.a * 256.0f;
+
+ // loop over the target vertically
+ for (u32 y = 0; y < dheight; y++)
{
- u32 starty = y * dy;
+ u32 const starty = y * dy;
- /* loop over the target horizontally */
- for (x = 0; x < dwidth; x++)
+ // loop over the target horizontally
+ for (u32 x = 0; x < dwidth; x++)
{
u64 sumr = 0, sumg = 0, sumb = 0, suma = 0;
- u32 startx = x * dx;
- u32 xchunk, ychunk;
- u32 curx, cury;
+ u32 const startx = x * dx;
u32 yremaining = dy;
+ u32 ychunk;
- /* accumulate all source pixels that contribute to this pixel */
- for (cury = starty; yremaining; cury += ychunk)
+ // accumulate all source pixels that contribute to this pixel
+ for (u32 cury = starty; yremaining; cury += ychunk)
{
u32 xremaining = dx;
+ u32 xchunk;
- /* determine the Y contribution, clamping to the amount remaining */
+ // determine the Y contribution, clamping to the amount remaining
ychunk = 0x1000 - (cury & 0xfff);
if (ychunk > yremaining)
ychunk = yremaining;
yremaining -= ychunk;
- /* loop over all source pixels in the X direction */
- for (curx = startx; xremaining; curx += xchunk)
+ // loop over all source pixels in the X direction
+ for (u32 curx = startx; xremaining; curx += xchunk)
{
- u32 factor;
-
- /* determine the X contribution, clamping to the amount remaining */
+ // determine the X contribution, clamping to the amount remaining
xchunk = 0x1000 - (curx & 0xfff);
if (xchunk > xremaining)
xchunk = xremaining;
xremaining -= xchunk;
- /* total contribution = x * y */
- factor = xchunk * ychunk;
+ // total contribution = x * y
+ u32 const factor = xchunk * ychunk;
- /* fetch the source pixel */
- rgb_t pix = source[(cury >> 12) * srowpixels + (curx >> 12)];
+ // fetch the source pixel
+ rgb_t const pix = source[(cury >> 12) * srowpixels + (curx >> 12)];
- /* accumulate the RGBA values */
+ // accumulate the RGBA values
sumr += factor * pix.r();
sumg += factor * pix.g();
sumb += factor * pix.b();
@@ -245,23 +241,23 @@ static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth,
}
}
- /* apply scaling */
+ // apply scaling
suma = (suma / sumscale) * a / 256;
sumr = (sumr / sumscale) * r / 256;
sumg = (sumg / sumscale) * g / 256;
sumb = (sumb / sumscale) * b / 256;
- /* if we're translucent, add in the destination pixel contribution */
+ // if we're translucent, add in the destination pixel contribution
if (a < 256)
{
- rgb_t dpix = dest[y * drowpixels + x];
+ rgb_t const dpix = dest[y * drowpixels + x];
suma += dpix.a() * (256 - a);
sumr += dpix.r() * (256 - a);
sumg += dpix.g() * (256 - a);
sumb += dpix.b() * (256 - a);
}
- /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ // store the target pixel, dividing the RGBA values by the overall scale factor
dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb);
}
}
@@ -273,44 +269,37 @@ static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth,
sampling via a bilinear filter
-------------------------------------------------*/
-static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy)
+static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy) noexcept
{
- u32 maxx = swidth << 12, maxy = sheight << 12;
- u32 r, g, b, a;
- u32 x, y;
-
- /* precompute premultiplied R/G/B/A factors */
- r = color.r * color.a * 256.0f;
- g = color.g * color.a * 256.0f;
- b = color.b * color.a * 256.0f;
- a = color.a * 256.0f;
-
- /* loop over the target vertically */
- for (y = 0; y < dheight; y++)
+ u32 const maxx = swidth << 12, maxy = sheight << 12;
+
+ // precompute premultiplied R/G/B/A factors
+ u32 const r = color.r * color.a * 256.0f;
+ u32 const g = color.g * color.a * 256.0f;
+ u32 const b = color.b * color.a * 256.0f;
+ u32 const a = color.a * 256.0f;
+
+ // loop over the target vertically
+ for (u32 y = 0; y < dheight; y++)
{
- u32 starty = y * dy;
+ u32 const starty = y * dy;
- /* loop over the target horizontally */
- for (x = 0; x < dwidth; x++)
+ // loop over the target horizontally
+ for (u32 x = 0; x < dwidth; x++)
{
- u32 startx = x * dx;
- rgb_t pix0, pix1, pix2, pix3;
- u32 sumr, sumg, sumb, suma;
- u32 nextx, nexty;
- u32 curx, cury;
- u32 factor;
+ u32 const startx = x * dx;
- /* adjust start to the center; note that this math will tend to produce */
- /* negative results on the first pixel, which is why we clamp below */
- curx = startx + dx / 2 - 0x800;
- cury = starty + dy / 2 - 0x800;
+ // adjust start to the center; note that this math will tend to produce
+ // negative results on the first pixel, which is why we clamp below
+ u32 curx = startx + dx / 2 - 0x800;
+ u32 cury = starty + dy / 2 - 0x800;
- /* compute the neighboring pixel */
- nextx = curx + 0x1000;
- nexty = cury + 0x1000;
+ // compute the neighboring pixel
+ u32 const nextx = curx + 0x1000;
+ u32 const nexty = cury + 0x1000;
- /* fetch the four relevant pixels */
- pix0 = pix1 = pix2 = pix3 = 0;
+ // fetch the four relevant pixels
+ rgb_t pix0 = 0, pix1 = 0, pix2 = 0, pix3 = 0;
if (s32(cury) >= 0 && cury < maxy && s32(curx) >= 0 && curx < maxx)
pix0 = source[(cury >> 12) * srowpixels + (curx >> 12)];
if (s32(cury) >= 0 && cury < maxy && s32(nextx) >= 0 && nextx < maxx)
@@ -320,173 +309,176 @@ static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth,
if (s32(nexty) >= 0 && nexty < maxy && s32(nextx) >= 0 && nextx < maxx)
pix3 = source[(nexty >> 12) * srowpixels + (nextx >> 12)];
- /* compute the x/y scaling factors */
+ // compute the x/y scaling factors
curx &= 0xfff;
cury &= 0xfff;
- /* contributions from pixel 0 (top,left) */
+ u32 factor;
+ u32 sumr, sumg, sumb, suma;
+
+ // contributions from pixel 0 (top,left)
factor = (0x1000 - curx) * (0x1000 - cury);
sumr = factor * pix0.r();
sumg = factor * pix0.g();
sumb = factor * pix0.b();
suma = factor * pix0.a();
- /* contributions from pixel 1 (top,right) */
+ // contributions from pixel 1 (top,right)
factor = curx * (0x1000 - cury);
sumr += factor * pix1.r();
sumg += factor * pix1.g();
sumb += factor * pix1.b();
suma += factor * pix1.a();
- /* contributions from pixel 2 (bottom,left) */
+ // contributions from pixel 2 (bottom,left)
factor = (0x1000 - curx) * cury;
sumr += factor * pix2.r();
sumg += factor * pix2.g();
sumb += factor * pix2.b();
suma += factor * pix2.a();
- /* contributions from pixel 3 (bottom,right) */
+ // contributions from pixel 3 (bottom,right)
factor = curx * cury;
sumr += factor * pix3.r();
sumg += factor * pix3.g();
sumb += factor * pix3.b();
suma += factor * pix3.a();
- /* apply scaling */
+ // apply scaling
suma = (suma >> 24) * a / 256;
sumr = (sumr >> 24) * r / 256;
sumg = (sumg >> 24) * g / 256;
sumb = (sumb >> 24) * b / 256;
- /* if we're translucent, add in the destination pixel contribution */
+ // if we're translucent, add in the destination pixel contribution
if (a < 256)
{
- rgb_t dpix = dest[y * drowpixels + x];
+ rgb_t const dpix = dest[y * drowpixels + x];
suma += dpix.a() * (256 - a);
sumr += dpix.r() * (256 - a);
sumg += dpix.g() * (256 - a);
sumb += dpix.b() * (256 - a);
}
- /* store the target pixel, dividing the RGBA values by the overall scale factor */
+ // store the target pixel, dividing the RGBA values by the overall scale factor
dest[y * drowpixels + x] = rgb_t(suma, sumr, sumg, sumb);
}
}
}
-/*-------------------------------------------------
- render_clip_line - clip a line to a rectangle
--------------------------------------------------*/
+//-------------------------------------------------
+// render_clip_line - clip a line to a rectangle
+//-------------------------------------------------
-bool render_clip_line(render_bounds *bounds, const render_bounds *clip)
+bool render_clip_line(render_bounds &bounds, const render_bounds &clip)
{
- /* loop until we get a final result */
- while (1)
+ // loop until we get a final result
+ while (true)
{
u8 code0 = 0, code1 = 0;
u8 thiscode;
float x, y;
- /* compute Cohen Sutherland bits for first coordinate */
- if (bounds->y0 > clip->y1)
+ // compute Cohen Sutherland bits for first coordinate
+ if (bounds.y0 > clip.y1)
code0 |= 1;
- if (bounds->y0 < clip->y0)
+ if (bounds.y0 < clip.y0)
code0 |= 2;
- if (bounds->x0 > clip->x1)
+ if (bounds.x0 > clip.x1)
code0 |= 4;
- if (bounds->x0 < clip->x0)
+ if (bounds.x0 < clip.x0)
code0 |= 8;
- /* compute Cohen Sutherland bits for second coordinate */
- if (bounds->y1 > clip->y1)
+ // compute Cohen Sutherland bits for second coordinate
+ if (bounds.y1 > clip.y1)
code1 |= 1;
- if (bounds->y1 < clip->y0)
+ if (bounds.y1 < clip.y0)
code1 |= 2;
- if (bounds->x1 > clip->x1)
+ if (bounds.x1 > clip.x1)
code1 |= 4;
- if (bounds->x1 < clip->x0)
+ if (bounds.x1 < clip.x0)
code1 |= 8;
- /* trivial accept: just return false */
+ // trivial accept: just return false
if ((code0 | code1) == 0)
return false;
- /* trivial reject: just return true */
+ // trivial reject: just return true
if ((code0 & code1) != 0)
return true;
- /* fix one of the OOB cases */
+ // fix one of the OOB cases
thiscode = code0 ? code0 : code1;
- /* off the bottom */
+ // off the bottom
if (thiscode & 1)
{
- x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y1 - bounds->y0) / (bounds->y1 - bounds->y0);
- y = clip->y1;
+ x = bounds.x0 + (bounds.x1 - bounds.x0) * (clip.y1 - bounds.y0) / (bounds.y1 - bounds.y0);
+ y = clip.y1;
}
- /* off the top */
+ // off the top
else if (thiscode & 2)
{
- x = bounds->x0 + (bounds->x1 - bounds->x0) * (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0);
- y = clip->y0;
+ x = bounds.x0 + (bounds.x1 - bounds.x0) * (clip.y0 - bounds.y0) / (bounds.y1 - bounds.y0);
+ y = clip.y0;
}
- /* off the right */
+ // off the right
else if (thiscode & 4)
{
- y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x1 - bounds->x0) / (bounds->x1 - bounds->x0);
- x = clip->x1;
+ y = bounds.y0 + (bounds.y1 - bounds.y0) * (clip.x1 - bounds.x0) / (bounds.x1 - bounds.x0);
+ x = clip.x1;
}
- /* off the left */
+ // off the left
else
{
- y = bounds->y0 + (bounds->y1 - bounds->y0) * (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0);
- x = clip->x0;
+ y = bounds.y0 + (bounds.y1 - bounds.y0) * (clip.x0 - bounds.x0) / (bounds.x1 - bounds.x0);
+ x = clip.x0;
}
- /* fix the appropriate coordinate */
+ // fix the appropriate coordinate
if (thiscode == code0)
{
- bounds->x0 = x;
- bounds->y0 = y;
+ bounds.x0 = x;
+ bounds.y0 = y;
}
else
{
- bounds->x1 = x;
- bounds->y1 = y;
+ bounds.x1 = x;
+ bounds.y1 = y;
}
}
}
-/*-------------------------------------------------
- render_clip_quad - clip a quad to a rectangle
--------------------------------------------------*/
+//-------------------------------------------------
+// render_clip_quad - clip a quad to a rectangle
+//-------------------------------------------------
-bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords)
+bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords)
{
- /* ensure our assumptions about the bounds are correct */
- assert(bounds->x0 <= bounds->x1);
- assert(bounds->y0 <= bounds->y1);
+ // ensure our assumptions about the bounds are correct
+ assert(bounds.x0 <= bounds.x1);
+ assert(bounds.y0 <= bounds.y1);
- /* trivial reject */
- if (bounds->y1 < clip->y0)
+ // trivial reject
+ if (bounds.y1 < clip.y0)
return true;
- if (bounds->y0 > clip->y1)
+ if (bounds.y0 > clip.y1)
return true;
- if (bounds->x1 < clip->x0)
+ if (bounds.x1 < clip.x0)
return true;
- if (bounds->x0 > clip->x1)
+ if (bounds.x0 > clip.x1)
return true;
- /* clip top (x0,y0)-(x1,y1) */
- if (bounds->y0 < clip->y0)
+ // clip top (x0,y0)-(x1,y1)
+ if (bounds.y0 < clip.y0)
{
- float frac = (clip->y0 - bounds->y0) / (bounds->y1 - bounds->y0);
- bounds->y0 = clip->y0;
+ float frac = (clip.y0 - bounds.y0) / (bounds.y1 - bounds.y0);
+ bounds.y0 = clip.y0;
if (texcoords != nullptr)
{
texcoords->tl.u += (texcoords->bl.u - texcoords->tl.u) * frac;
@@ -496,11 +488,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q
}
}
- /* clip bottom (x3,y3)-(x2,y2) */
- if (bounds->y1 > clip->y1)
+ // clip bottom (x3,y3)-(x2,y2)
+ if (bounds.y1 > clip.y1)
{
- float frac = (bounds->y1 - clip->y1) / (bounds->y1 - bounds->y0);
- bounds->y1 = clip->y1;
+ float frac = (bounds.y1 - clip.y1) / (bounds.y1 - bounds.y0);
+ bounds.y1 = clip.y1;
if (texcoords != nullptr)
{
texcoords->bl.u -= (texcoords->bl.u - texcoords->tl.u) * frac;
@@ -510,11 +502,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q
}
}
- /* clip left (x0,y0)-(x3,y3) */
- if (bounds->x0 < clip->x0)
+ // clip left (x0,y0)-(x3,y3)
+ if (bounds.x0 < clip.x0)
{
- float frac = (clip->x0 - bounds->x0) / (bounds->x1 - bounds->x0);
- bounds->x0 = clip->x0;
+ float frac = (clip.x0 - bounds.x0) / (bounds.x1 - bounds.x0);
+ bounds.x0 = clip.x0;
if (texcoords != nullptr)
{
texcoords->tl.u += (texcoords->tr.u - texcoords->tl.u) * frac;
@@ -524,11 +516,11 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q
}
}
- /* clip right (x1,y1)-(x2,y2) */
- if (bounds->x1 > clip->x1)
+ // clip right (x1,y1)-(x2,y2)
+ if (bounds.x1 > clip.x1)
{
- float frac = (bounds->x1 - clip->x1) / (bounds->x1 - bounds->x0);
- bounds->x1 = clip->x1;
+ float frac = (bounds.x1 - clip.x1) / (bounds.x1 - bounds.x0);
+ bounds.x1 = clip.x1;
if (texcoords != nullptr)
{
texcoords->tr.u -= (texcoords->tr.u - texcoords->tl.u) * frac;
@@ -541,14 +533,14 @@ bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_q
}
-/*-------------------------------------------------
- render_line_to_quad - convert a line and a
- width to four points
--------------------------------------------------*/
+//-------------------------------------------------
+// render_line_to_quad - convert a line and a
+// width to four points
+//-----------------------------------------------
-void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1)
+std::pair<render_bounds, render_bounds> render_line_to_quad(const render_bounds &bounds, float width, float length_extension)
{
- render_bounds modbounds = *bounds;
+ render_bounds modbounds = bounds;
/*
High-level logic -- due to math optimizations, this info is lost below.
@@ -595,18 +587,18 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
D.y = p1.y - 0.5 * w * u.x
*/
- /* we only care about the half-width */
+ // we only care about the half-width
float half_width = width * 0.5f;
- /* compute a vector from point 0 to point 1 */
+ // compute a vector from point 0 to point 1
float unitx = modbounds.x1 - modbounds.x0;
float unity = modbounds.y1 - modbounds.y0;
- /* points just use a +1/+1 unit vector; this gives a nice diamond pattern */
+ // points just use a +1/+1 unit vector; this gives a nice diamond pattern
if (unitx == 0 && unity == 0)
{
- /* length of a unit vector (1,1) */
- float unit_length = 0.70710678f;
+ // length of a unit vector (1,1)
+ constexpr float unit_length = 0.70710678f;
unitx = unity = unit_length * half_width;
modbounds.x0 -= unitx;
@@ -615,12 +607,12 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
modbounds.y1 += unity;
}
- /* lines need to be divided by their length */
+ // lines need to be divided by their length
else
{
float length = sqrtf(unitx * unitx + unity * unity);
- /* extend line length */
+ // extend line length
if (length_extension > 0.0f)
{
float half_length_extension = length_extension *0.5f;
@@ -634,27 +626,16 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
modbounds.y1 += directiony * half_length_extension;
}
- /* prescale unitx and unity by the half-width */
+ // prescale unitx and unity by the half-width
float invlength = half_width / length;
unitx *= invlength;
unity *= invlength;
}
- /* rotate the unit vector by 90 degrees and add to point 0 */
- bounds0->x0 = modbounds.x0 - unity;
- bounds0->y0 = modbounds.y0 + unitx;
-
- /* rotate the unit vector by -90 degrees and add to point 0 */
- bounds0->x1 = modbounds.x0 + unity;
- bounds0->y1 = modbounds.y0 - unitx;
-
- /* rotate the unit vector by 90 degrees and add to point 1 */
- bounds1->x0 = modbounds.x1 - unity;
- bounds1->y0 = modbounds.y1 + unitx;
-
- /* rotate the unit vector by -90 degrees and add to point 1 */
- bounds1->x1 = modbounds.x1 + unity;
- bounds1->y1 = modbounds.y1 - unitx;
+ // rotate the unit vector by 90 and -90 degrees and add to points 0 and 1
+ return std::make_pair(
+ render_bounds{ modbounds.x0 - unity, modbounds.y0 + unitx, modbounds.x0 + unity, modbounds.y0 - unitx },
+ render_bounds{ modbounds.x1 - unity, modbounds.y1 + unitx, modbounds.x1 + unity, modbounds.y1 - unitx });
}
@@ -663,7 +644,7 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
into a bitmap
-------------------------------------------------*/
-void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file)
+void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept
{
// deallocate previous bitmap
bitmap.reset();
@@ -683,7 +664,7 @@ void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file)
bitmap
-------------------------------------------------*/
-void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file)
+void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept
{
// deallocate previous bitmap
bitmap.reset();
@@ -721,30 +702,39 @@ void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file)
// allocates a buffer to receive the information and copy them into the bitmap
row_stride = cinfo.output_width * cinfo.output_components;
buffer = reinterpret_cast<JSAMPARRAY>(std::malloc(sizeof(JSAMPROW)));
- buffer[0] = reinterpret_cast<JSAMPROW>(std::malloc(sizeof(JSAMPLE) * row_stride));
+ if (buffer)
+ buffer[0] = reinterpret_cast<JSAMPROW>(std::malloc(sizeof(JSAMPLE) * row_stride));
- while (cinfo.output_scanline < cinfo.output_height)
+ if (bitmap.valid() && buffer && buffer[0])
{
- j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
-
- if (s == 1)
+ while (cinfo.output_scanline < cinfo.output_height)
{
- for (i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i], buffer[0][i], buffer[0][i]);
+ j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
+ if (s == 1)
+ {
+ for (i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i], buffer[0][i], buffer[0][i]);
+
+ }
+ else if (s == 3)
+ {
+ for (i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+ }
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from file.\n");
+ bitmap.reset();
+ break;
+ }
}
- else if (s == 3)
- {
- for (i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xff, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- }
- else
- {
- osd_printf_error("Cannot read JPEG data from file.\n");
- bitmap.reset();
- break;
- }
+ }
+ else
+ {
+ osd_printf_error("Error allocating memory for JPEG image.\n");
+ bitmap.reset();
}
// finish decompression and free the memory
@@ -765,7 +755,7 @@ cleanup:
bitmap
-------------------------------------------------*/
-bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing)
+bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing) noexcept
{
// deallocate if we're not overlaying alpha
if (!load_as_alpha_to_existing)
@@ -820,7 +810,7 @@ bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_a
to the alpha channel of a bitmap
-------------------------------------------------*/
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png)
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png) noexcept
{
// FIXME: this function is basically copy/pasted from the PNG code in util, and should be unified with it
u8 accumalpha = 0xff;
@@ -931,7 +921,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info
render_detect_image - detect image format
-------------------------------------------------*/
-ru_imgformat render_detect_image(util::random_read &file)
+ru_imgformat render_detect_image(util::random_read &file) noexcept
{
// PNG: check for valid header
{
diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h
index 4d2b89567e3..71e5bdc95c3 100644
--- a/src/emu/rendutil.h
+++ b/src/emu/rendutil.h
@@ -15,8 +15,11 @@
#include "rendertypes.h"
+#include "utilfwd.h"
+
#include <algorithm>
#include <cmath>
+#include <utility>
/* ----- image formats ----- */
@@ -39,14 +42,14 @@ enum ru_imgformat
/* ----- render utilities ----- */
-void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false);
-bool render_clip_line(render_bounds *bounds, const render_bounds *clip);
-bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
-void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1);
-void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file);
-void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file);
-bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false);
-ru_imgformat render_detect_image(util::random_read &file);
+void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false) noexcept;
+bool render_clip_line(render_bounds &bounds, const render_bounds &clip);
+bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords);
+std::pair<render_bounds, render_bounds> render_line_to_quad(const render_bounds &bounds, float width, float length_extension);
+void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept;
+void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept;
+bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false) noexcept;
+ru_imgformat render_detect_image(util::random_read &file) noexcept;
diff --git a/src/emu/romentry.h b/src/emu/romentry.h
index ff73e432c65..2a315c2a03e 100644
--- a/src/emu/romentry.h
+++ b/src/emu/romentry.h
@@ -29,18 +29,17 @@ CONSTANTS
#define ROMENTRY_TYPEMASK 0x0000000f /* type of entry */
enum
{
- ROMENTRYTYPE_ROM = 0, /* this entry is an actual ROM definition */
- ROMENTRYTYPE_REGION, /* this entry marks the start of a region */
- ROMENTRYTYPE_END, /* this entry marks the end of a region */
- ROMENTRYTYPE_RELOAD, /* this entry reloads the previous ROM */
- ROMENTRYTYPE_CONTINUE, /* this entry continues loading the previous ROM */
- ROMENTRYTYPE_FILL, /* this entry fills an area with a constant value */
- ROMENTRYTYPE_COPY, /* this entry copies data from another region/offset */
- ROMENTRYTYPE_CARTRIDGE, /* this entry specifies a cartridge (MESS) */
- ROMENTRYTYPE_IGNORE, /* this entry continues loading the previous ROM but throws the data away */
- ROMENTRYTYPE_SYSTEM_BIOS, /* this entry specifies a bios */
- ROMENTRYTYPE_DEFAULT_BIOS, /* this entry specifies a default bios */
- ROMENTRYTYPE_PARAMETER, /* this entry specifies a per-game parameter */
+ ROMENTRYTYPE_ROM = 0, // starts loading a ROM file
+ ROMENTRYTYPE_REGION, // starts a new ROM region
+ ROMENTRYTYPE_END, // sentinel marking the end of a ROM definition
+ ROMENTRYTYPE_RELOAD, // starts loading the current ROM file from the beginning again
+ ROMENTRYTYPE_CONTINUE, // continues loading the current ROM file at a different offset
+ ROMENTRYTYPE_FILL, // fills an area with a constant value
+ ROMENTRYTYPE_COPY, // copies data from another region/offset
+ ROMENTRYTYPE_IGNORE, // ignores a portion of the current ROM file
+ ROMENTRYTYPE_SYSTEM_BIOS, // specifies a BIOS option
+ ROMENTRYTYPE_DEFAULT_BIOS, // specifies the default BIOS option
+ ROMENTRYTYPE_PARAMETER, // specifies a per-game parameter
ROMENTRYTYPE_COUNT
};
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index bdff58a4a41..a429153be3f 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -11,13 +11,19 @@
#include "emu.h"
#include "romload.h"
-#include "corestr.h"
-#include "emuopts.h"
#include "drivenum.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "softlist_dev.h"
+
#include "ui/uimain.h"
+#include "corestr.h"
+#include "path.h"
+
#include <algorithm>
+#include <cstdarg>
#include <set>
@@ -37,6 +43,25 @@
namespace {
+/*-------------------------------------------------
+ debugload - log data to a file
+-------------------------------------------------*/
+
+void ATTR_PRINTF(1,2) debugload(const char *string, ...)
+{
+ static int opened = 0;
+ FILE *const f(fopen("romload.log", opened++ ? "a" : "w"));
+ if (f)
+ {
+ va_list arg;
+ va_start(arg, string);
+ vfprintf(f, string, arg);
+ va_end(arg);
+ fclose(f);
+ }
+}
+
+
auto next_parent_system(game_driver const &system)
{
return
@@ -48,13 +73,41 @@ auto next_parent_system(game_driver const &system)
if (0 > parent)
{
sys = nullptr;
+ roms.clear();
+ roms.shrink_to_fit();
return nullptr;
}
else
{
sys = &driver_list::driver(parent);
roms = rom_build_entries(sys->rom);
- return &roms[0];
+ return &roms.front();
+ }
+ };
+}
+
+
+auto next_parent_device(device_t const &device, emu_options &options)
+{
+ return
+ [&options, type = &device.type(), roms = std::vector<rom_entry>()] () mutable -> rom_entry const *
+ {
+ if (!type)
+ return nullptr;
+ type = type->parent_rom_device_type();
+ if (!type)
+ {
+ roms.clear();
+ roms.shrink_to_fit();
+ return nullptr;
+ }
+ else
+ {
+ machine_config config(GAME_NAME(___empty), options);
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ roms = config.device_add("_tmp", *type, 0)->rom_region_vector();
+ config.device_remove("_tmp");
+ return &roms.front();
}
};
}
@@ -89,7 +142,7 @@ std::vector<std::string> make_software_searchpath(software_list_device &swlist,
if (std::find(parents.begin(), parents.end(), i) != parents.end())
break;
parents.emplace_back(i);
- result.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->shortname()));
+ result.emplace_back(util::path_concat(swlist.list_name(), i->shortname()));
i = i->parentname().empty() ? nullptr : swlist.find(i->parentname());
}
@@ -101,13 +154,19 @@ std::vector<std::string> make_software_searchpath(software_list_device &swlist,
}
-std::error_condition do_open_disk(const emu_options &options, std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, chd_file &chd, std::function<const rom_entry * ()> next_parent)
+std::error_condition do_open_disk(
+ emu_options const &options,
+ std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath,
+ rom_entry const *romp,
+ chd_file &chd,
+ std::function<rom_entry const * ()> next_parent,
+ chd_file::open_parent_func const &open_parent)
{
// hashes are fixed, but we might need to try multiple filenames
std::set<std::string> tried;
- const util::hash_collection hashes(romp->hashdata());
+ util::hash_collection const hashes(romp->hashdata());
std::string filename, fullpath;
- const rom_entry *parent(nullptr);
+ rom_entry const *parent(nullptr);
std::error_condition result(std::errc::no_such_file_or_directory);
while (romp && result)
{
@@ -116,11 +175,11 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
{
// piggyback on emu_file to find the disk image file
std::unique_ptr<emu_file> imgfile;
- for (const std::vector<std::string> &paths : searchpath)
+ for (std::vector<std::string> const &paths : searchpath)
{
imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ));
imgfile->set_restrict_to_mediapath(1);
- const std::error_condition filerr(imgfile->open(filename, OPEN_FLAG_READ));
+ std::error_condition const filerr(imgfile->open(filename, OPEN_FLAG_READ));
if (!filerr)
break;
else
@@ -132,7 +191,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
{
fullpath = imgfile->fullpath();
imgfile.reset();
- result = chd.open(fullpath);
+ result = chd.open(fullpath, false, nullptr, open_parent);
}
}
@@ -154,10 +213,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
romp = nullptr;
break;
}
- while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent))
- ++parent;
- if (ROMENTRY_ISEND(parent))
- parent = nullptr;
+ parent = rom_first_region(parent);
}
else
{
@@ -178,6 +234,46 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
return result;
}
+
+auto open_parent_disk(
+ emu_options const &options,
+ std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath,
+ std::function<rom_entry const * ()> const &next_parent)
+{
+ return
+ [&options, searchpath, next_parent] (util::sha1_t const &sha1) -> std::unique_ptr<chd_file>
+ {
+ util::hash_collection hashes;
+ hashes.add_sha1(sha1);
+ std::function<rom_entry const * ()> np(next_parent); // important - copy mutable lambda
+ for (rom_entry const *parent = np(); parent; parent = np())
+ {
+ parent = rom_first_region(parent);
+ while (parent)
+ {
+ while (parent && !ROMREGION_ISDISKDATA(parent))
+ parent = rom_next_region(parent);
+ if (parent)
+ {
+ rom_entry const *romp(rom_first_file(parent));
+ while (romp)
+ {
+ if (util::hash_collection(romp->hashdata()) == hashes)
+ {
+ std::unique_ptr<chd_file> chd(new chd_file);
+ if (!do_open_disk(options, searchpath, romp, *chd, next_parent, nullptr))
+ return chd;
+ }
+ romp = rom_next_file(romp);
+ }
+ parent = rom_next_region(parent);
+ }
+ }
+ }
+ return nullptr;
+ };
+}
+
} // anonymous namespace
@@ -257,7 +353,7 @@ const rom_entry *rom_first_parameter(const device_t &device)
const rom_entry *romp = &device.rom_region_vector().front();
while (romp && !ROMENTRY_ISEND(romp) && !ROMENTRY_ISPARAMETER(romp))
romp++;
- return (romp != nullptr && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
+ return (romp && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
}
@@ -282,17 +378,17 @@ const rom_entry *rom_next_parameter(const rom_entry *romp)
u32 rom_file_size(const rom_entry *romp)
{
- u32 maxlength = 0;
+ u32 maxlength(0);
- /* loop until we run out of reloads */
+ // loop until we run out of reloads
do
{
- /* loop until we run out of continues/ignores */
+ // loop until we run out of continues/ignores
u32 curlength = ROM_GETLENGTH(romp++);
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
curlength += ROM_GETLENGTH(romp++);
- /* track the maximum length */
+ // track the maximum length
maxlength = std::max(maxlength, curlength);
}
while (ROMENTRY_ISRELOAD(romp));
@@ -301,27 +397,6 @@ u32 rom_file_size(const rom_entry *romp)
}
-/*-------------------------------------------------
- debugload - log data to a file
--------------------------------------------------*/
-
-static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
-{
- static int opened;
- va_list arg;
- FILE *f;
-
- f = fopen("romload.log", opened++ ? "a" : "w");
- if (f)
- {
- va_start(arg, string);
- vfprintf(f, string, arg);
- va_end(arg);
- fclose(f);
- }
-}
-
-
/***************************************************************************
HARD DISK HANDLING
***************************************************************************/
@@ -334,8 +409,10 @@ static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
chd_file *rom_load_manager::get_disk_handle(std::string_view region)
{
for (auto &curdisk : m_chd_list)
+ {
if (curdisk->region() == region)
return &curdisk->chd();
+ }
return nullptr;
}
@@ -345,37 +422,36 @@ chd_file *rom_load_manager::get_disk_handle(std::string_view region)
file associated with the given region
-------------------------------------------------*/
-std::error_condition rom_load_manager::set_disk_handle(std::string_view region, const char *fullpath)
+std::error_condition rom_load_manager::set_disk_handle(std::string_view region, std::string_view fullpath)
{
- auto chd = std::make_unique<open_chd>(region);
- auto err = chd->orig_chd().open(fullpath);
+ auto chd(std::make_unique<open_chd>(region));
+ std::error_condition const err(chd->orig_chd().open(fullpath));
if (!err)
- m_chd_list.push_back(std::move(chd));
+ m_chd_list.emplace_back(std::move(chd));
return err;
}
/*-------------------------------------------------
determine_bios_rom - determine system_bios
- from SystemBios structure and OPTION_BIOS
+ from SYSTEM_BIOS structure and OPTION_BIOS
-------------------------------------------------*/
-void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios)
+void rom_load_manager::determine_bios_rom(device_t &device, std::string_view specbios)
{
// default is applied by the device at config complete time
- if (specbios && *specbios && core_stricmp(specbios, "default"))
+ using namespace std::literals;
+ if (!specbios.empty() && !util::streqlower(specbios, "default"sv))
{
bool found(false);
- for (const rom_entry &rom : device.rom_region_vector())
+ for (rom_entry const &rom : device.rom_region_vector())
{
if (ROMENTRY_ISSYSTEM_BIOS(&rom))
{
char const *const biosname = ROM_GETNAME(&rom);
int const bios_flags = ROM_GETBIOSFLAGS(&rom);
- char bios_number[20];
// Allow '-bios n' to still be used
- sprintf(bios_number, "%d", bios_flags - 1);
- if (!core_stricmp(bios_number, specbios) || !core_stricmp(biosname, specbios))
+ if ((specbios == std::to_string(bios_flags - 1)) || util::streqlower(specbios, biosname))
{
found = true;
device.set_system_bios(bios_flags);
@@ -404,21 +480,29 @@ void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios
void rom_load_manager::count_roms()
{
- const rom_entry *region, *rom;
-
- /* start with 0 */
+ // start with 0
m_romstotal = 0;
m_romstotalsize = 0;
- /* loop over regions, then over files */
+ // loop over regions, and files within regions
for (device_t &device : device_enumerator(machine().config().root_device()))
- for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
- for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
- if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == device.system_bios())
+ {
+ rom_entry const *region(rom_first_region(device));
+ while (region)
+ {
+ rom_entry const *rom(rom_first_file(region));
+ while (rom)
+ {
+ if ((ROM_GETBIOSFLAGS(rom) == 0) || (ROM_GETBIOSFLAGS(rom) == device.system_bios()))
{
m_romstotal++;
m_romstotalsize += rom_file_size(rom);
}
+ rom = rom_next_file(rom);
+ }
+ region = rom_next_region(region);
+ }
+ }
}
@@ -456,7 +540,7 @@ void rom_load_manager::handle_missing_file(const rom_entry *romp, const std::vec
const bool is_chd(chderr);
const std::string name(is_chd ? romp->name() + ".chd" : romp->name());
- const bool is_chd_error(is_chd && chderr != std::errc::no_such_file_or_directory);
+ const bool is_chd_error(is_chd && (chderr != std::errc::no_such_file_or_directory));
if (is_chd_error)
m_errorstring.append(string_format("%s CHD ERROR: %s\n", name, chderr.message()));
@@ -509,7 +593,7 @@ void rom_load_manager::verify_length_and_hash(emu_file *file, std::string_view n
return;
// verify length
- u64 const actlength = file->size();
+ u64 const actlength(file->size());
if (explength != actlength)
{
m_errorstring.append(string_format("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength));
@@ -525,7 +609,7 @@ void rom_load_manager::verify_length_and_hash(emu_file *file, std::string_view n
else
{
// verify checksums
- util::hash_collection const &acthashes = file->hashes(hashes.hash_types());
+ util::hash_collection const &acthashes(file->hashes(hashes.hash_types()));
if (hashes != acthashes)
{
// otherwise, it's just bad
@@ -571,19 +655,19 @@ void rom_load_manager::display_loading_rom_message(const char *name, bool from_l
void rom_load_manager::display_rom_load_results(bool from_list)
{
- /* final status display */
+ // final status display
display_loading_rom_message(nullptr, from_list);
- /* if we had errors, they are fatal */
+ // if we had errors, they are fatal
if (m_errors != 0)
{
- /* create the error message and exit fatally */
+ // create the error message and exit fatally
osd_printf_error("%s", m_errorstring);
throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
}
- /* if we had warnings, output them, but continue */
- if ((m_warnings) || (m_knownbad))
+ // if we had warnings, output them, but continue
+ if (m_warnings || m_knownbad)
{
m_errorstring.append("WARNING: the machine might not run correctly.");
osd_printf_warning("%s\n", m_errorstring);
@@ -599,27 +683,28 @@ void rom_load_manager::display_rom_load_results(bool from_list)
void rom_load_manager::region_post_process(memory_region *region, bool invert)
{
// do nothing if no region
- if (region == nullptr)
+ if (!region)
return;
- LOG("+ datawidth=%dbit endian=%s\n", region->bitwidth(),
- region->endianness() == ENDIANNESS_LITTLE ? "little" : "big");
+ LOG("+ datawidth=%dbit endian=%s\n",
+ region->bitwidth(),
+ (region->endianness() == ENDIANNESS_LITTLE) ? "little" : "big");
- /* if the region is inverted, do that now */
+ // if the region is inverted, do that now
if (invert)
{
LOG("+ Inverting region\n");
- u8 *base = region->base();
+ u8 *base(region->base());
for (int i = 0; i < region->bytes(); i++)
*base++ ^= 0xff;
}
- /* swap the endianness if we need to */
- if (region->bytewidth() > 1 && region->endianness() != ENDIANNESS_NATIVE)
+ // swap the endianness if we need to
+ int const datawidth(region->bytewidth());
+ if ((datawidth > 1) && (region->endianness() != ENDIANNESS_NATIVE))
{
LOG("+ Byte swapping region\n");
- int datawidth = region->bytewidth();
- u8 *base = region->base();
+ u8 *base(region->base());
for (int i = 0; i < region->bytes(); i += datawidth)
{
u8 temp[8];
@@ -636,7 +721,11 @@ void rom_load_manager::region_post_process(memory_region *region, bool invert)
up the parent and loading by checksum
-------------------------------------------------*/
-std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<std::reference_wrapper<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> rom_load_manager::open_rom_file(
+ const std::vector<std::string> &searchpath,
+ const rom_entry *romp,
+ std::vector<std::string> &tried_file_names,
+ bool from_list)
{
std::error_condition filerr = std::errc::no_such_file_or_directory;
u32 const romsize = rom_file_size(romp);
@@ -651,13 +740,8 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<
// attempt reading up the chain through the parents
// it also automatically attempts any kind of load by checksum supported by the archives.
- std::unique_ptr<emu_file> result;
- for (const std::vector<std::string> &paths : searchpath)
- {
- result = open_rom_file(paths, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr);
- if (result)
- break;
- }
+ std::unique_ptr<emu_file> result(
+ open_rom_file(searchpath, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr));
// update counters
m_romsloaded++;
@@ -671,7 +755,13 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<
}
-std::unique_ptr<emu_file> rom_load_manager::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)
+std::unique_ptr<emu_file> rom_load_manager::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)
{
// record the set names we search
tried.insert(tried.end(), paths.begin(), paths.end());
@@ -714,50 +804,52 @@ int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const ro
entry
-------------------------------------------------*/
-int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp)
+int rom_load_manager::read_rom_data(
+ emu_file *file,
+ memory_region &region,
+ const rom_entry *parent_region,
+ const rom_entry *romp)
{
- int datashift = ROM_GETBITSHIFT(romp);
- int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift;
- int numbytes = ROM_GETLENGTH(romp);
- int groupsize = ROM_GETGROUPSIZE(romp);
- int skip = ROM_GETSKIPCOUNT(romp);
- int reversed = ROM_ISREVERSED(romp);
- int numgroups = (numbytes + groupsize - 1) / groupsize;
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
- u32 tempbufsize;
- int i;
+ int const datashift(ROM_GETBITSHIFT(romp));
+ int const datamask(((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift);
+ int numbytes(ROM_GETLENGTH(romp));
+ int const groupsize(ROM_GETGROUPSIZE(romp));
+ int skip(ROM_GETSKIPCOUNT(romp));
+ int const reversed(ROM_ISREVERSED(romp));
+ int const numgroups((numbytes + groupsize - 1) / groupsize);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
LOG("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed);
- /* make sure the length was an even multiple of the group size */
- if (numbytes % groupsize != 0)
+ // make sure the length was a whole multiple of the group size
+ if ((numbytes % groupsize) != 0)
osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", romp->name());
- /* make sure we only fill within the region space */
- if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes())
+ // make sure we only fill within the region space
+ if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > region.bytes())
throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", romp->name());
- /* make sure the length was valid */
+ // make sure the length was valid
if (numbytes == 0)
throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", romp->name());
- /* special case for simple loads */
- if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
+ // special case for simple loads
+ if ((datamask == 0xff) && ((groupsize == 1) || !reversed) && (skip == 0))
return rom_fread(file, base, numbytes, parent_region);
- /* use a temporary buffer for complex loads */
- tempbufsize = std::min(TEMPBUFFER_MAX_SIZE, numbytes);
- std::vector<u8> tempbuf(tempbufsize);
+ // use a temporary buffer for complex loads
+ u32 const tempbufsize(std::min(TEMPBUFFER_MAX_SIZE, numbytes));
+ std::unique_ptr<u8 []> const tempbuf(new u8 [tempbufsize]);
- /* chunky reads for complex loads */
+ // chunky reads for complex loads
skip += groupsize;
while (numbytes > 0)
{
- int evengroupcount = (tempbufsize / groupsize) * groupsize;
- int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes;
- u8 *bufptr = &tempbuf[0];
+ int evengroupcount((tempbufsize / groupsize) * groupsize);
+ int bytesleft((numbytes > evengroupcount) ? evengroupcount : numbytes);
+ u8 *bufptr(tempbuf.get());
- /* read as much as we can */
+ // read as much as we can
LOG(" Reading %X bytes into buffer\n", bytesleft);
if (rom_fread(file, bufptr, bytesleft, parent_region) != bytesleft)
return 0;
@@ -765,58 +857,65 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi
LOG(" Copying to %p\n", base);
- /* unmasked cases */
if (datamask == 0xff)
{
- /* non-grouped data */
+ // unmasked cases
if (groupsize == 1)
- for (i = 0; i < bytesleft; i++, base += skip)
+ {
+ // non-grouped data
+ for (int i = 0; i < bytesleft; i++, base += skip)
*base = *bufptr++;
-
- /* grouped data -- non-reversed case */
+ }
else if (!reversed)
+ {
+ // grouped data -- non-reversed case
while (bytesleft)
{
- for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--)
base[i] = *bufptr++;
base += skip;
}
-
- /* grouped data -- reversed case */
+ }
else
+ {
+ // grouped data -- reversed case
while (bytesleft)
{
- for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
base[i] = *bufptr++;
base += skip;
}
+ }
}
-
- /* masked cases */
else
{
- /* non-grouped data */
+ // masked cases
if (groupsize == 1)
- for (i = 0; i < bytesleft; i++, base += skip)
+ {
+ // non-grouped data
+ for (int i = 0; i < bytesleft; i++, base += skip)
*base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask);
-
- /* grouped data -- non-reversed case */
+ }
else if (!reversed)
+ {
+ // grouped data -- non-reversed case
while (bytesleft)
{
- for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--)
base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
base += skip;
}
-
- /* grouped data -- reversed case */
+ }
else
+ {
+ // grouped data -- reversed case
while (bytesleft)
{
- for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
base += skip;
}
+ }
}
}
@@ -829,14 +928,14 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi
fill_rom_data - fill a region of ROM space
-------------------------------------------------*/
-void rom_load_manager::fill_rom_data(const rom_entry *romp)
+void rom_load_manager::fill_rom_data(memory_region &region, const rom_entry *romp)
{
u32 numbytes = ROM_GETLENGTH(romp);
int skip = ROM_GETSKIPCOUNT(romp);
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
// make sure we fill within the region space
- if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
+ if (ROM_GETOFFSET(romp) + numbytes > region.bytes())
throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n");
// make sure the length was valid
@@ -861,15 +960,15 @@ void rom_load_manager::fill_rom_data(const rom_entry *romp)
copy_rom_data - copy a region of ROM space
-------------------------------------------------*/
-void rom_load_manager::copy_rom_data(const rom_entry *romp)
+void rom_load_manager::copy_rom_data(memory_region &region, const rom_entry *romp)
{
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
const std::string &srcrgntag = romp->name();
u32 numbytes = ROM_GETLENGTH(romp);
u32 srcoffs = u32(strtol(romp->hashdata().c_str(), nullptr, 0)); /* srcoffset in place of hashdata */
/* make sure we copy within the region space */
- if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
+ if (ROM_GETOFFSET(romp) + numbytes > region.bytes())
throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
/* make sure the length was valid */
@@ -877,16 +976,16 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
throw emu_fatalerror("Error in RomModule definition: COPY has an invalid length\n");
/* make sure the source was valid */
- memory_region *region = machine().root_device().memregion(srcrgntag);
- if (region == nullptr)
+ memory_region *src = machine().root_device().memregion(srcrgntag);
+ if (!src)
throw emu_fatalerror("Error in RomModule definition: COPY from an invalid region\n");
/* make sure we find within the region space */
- if (srcoffs + numbytes > region->bytes())
+ if (srcoffs + numbytes > src->bytes())
throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
/* fill the data */
- memcpy(base, region->base() + srcoffs, numbytes);
+ memcpy(base, src->base() + srcoffs, numbytes);
}
@@ -895,7 +994,13 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
for a region
-------------------------------------------------*/
-void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list)
+void rom_load_manager::process_rom_entries(
+ const std::vector<std::string> &searchpath,
+ u8 bios,
+ memory_region &region,
+ const rom_entry *parent_region,
+ const rom_entry *romp,
+ bool from_list)
{
u32 lastflags = 0;
std::vector<std::string> tried_file_names;
@@ -917,13 +1022,13 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
if (ROMENTRY_ISFILL(romp))
{
if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
- fill_rom_data(romp);
+ fill_rom_data(region, romp);
romp++;
}
else if (ROMENTRY_ISCOPY(romp))
{
- copy_rom_data(romp++);
+ copy_rom_data(region, romp++);
}
else if (ROMENTRY_ISFILE(romp))
{
@@ -961,7 +1066,7 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
// attempt to read using the modified entry
if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios)
- /*readresult = */read_rom_data(file.get(), parent_region, &modified_romp);
+ /*readresult = */read_rom_data(file.get(), region, parent_region, &modified_romp);
}
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
@@ -1000,7 +1105,11 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
-std::error_condition rom_load_manager::open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd)
+std::error_condition rom_load_manager::open_disk_diff(
+ emu_options &options,
+ const rom_entry *romp,
+ chd_file &source,
+ chd_file &diff_chd)
{
// TODO: use system name and/or software list name in the path - the current setup doesn't scale
std::string fname = romp->name() + ".dif";
@@ -1046,41 +1155,55 @@ std::error_condition rom_load_manager::open_disk_diff(emu_options &options, cons
for a region
-------------------------------------------------*/
-void rom_load_manager::process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent)
+void rom_load_manager::process_disk_entries(
+ search_paths searchpath,
+ std::string_view regiontag,
+ rom_entry const *romp,
+ std::function<rom_entry const * ()> next_parent,
+ chd_file::open_parent_func const &open_parent)
{
- /* remove existing disk entries for this region */
- m_chd_list.erase(std::remove_if(m_chd_list.begin(), m_chd_list.end(),
- [regiontag] (std::unique_ptr<open_chd> &chd) { return chd->region() == regiontag; }), m_chd_list.end());
+ // remove existing disk entries for this region
+ m_chd_list.erase(
+ std::remove_if(
+ m_chd_list.begin(),
+ m_chd_list.end(),
+ [&regiontag] (std::unique_ptr<open_chd> &chd) { return chd->region() == regiontag; }),
+ m_chd_list.end());
- /* loop until we hit the end of this region */
+ // loop until we hit the end of this region
for ( ; !ROMENTRY_ISREGIONEND(romp); romp++)
{
- /* handle files */
+ // handle files
if (ROMENTRY_ISFILE(romp))
{
- auto chd = std::make_unique<open_chd>(regiontag);
+ auto chd(std::make_unique<open_chd>(regiontag));
std::error_condition err;
- /* make the filename of the source */
- const std::string filename = romp->name() + ".chd";
+ // make the filename of the source
+ std::string const filename(romp->name() + ".chd");
- /* first open the source drive */
- // FIXME: we've lost the ability to search parents here
+ // first open the reference disk image
LOG("Opening disk image: %s\n", filename.c_str());
- err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent);
+ err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent, open_parent);
+ if (!err && chd->orig_chd().parent_missing())
+ err = chd_file::error::REQUIRES_PARENT;
if (err)
{
- handle_missing_file(romp, std::vector<std::string>(), err);
- chd = nullptr;
+ std::vector<std::string> tried;
+ for (auto const &paths : searchpath)
+ {
+ for (std::string const &path : paths.get())
+ tried.emplace_back(path);
+ }
+ handle_missing_file(romp, tried, err);
+ chd.reset();
continue;
}
- /* get the header and extract the SHA1 */
+ // get the header and verify the SHA1 digest
util::hash_collection acthashes;
acthashes.add_sha1(chd->orig_chd().sha1());
-
- /* verify the hash */
- const util::hash_collection hashes(romp->hashdata());
+ util::hash_collection const hashes(romp->hashdata());
if (hashes != acthashes)
{
m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename));
@@ -1093,23 +1216,22 @@ void rom_load_manager::process_disk_entries(std::initializer_list<std::reference
m_knownbad++;
}
- /* if not read-only, make the diff file */
+ // if not read-only, open or create the diff file
if (!DISK_ISREADONLY(romp))
{
- /* try to open or create the diff */
err = open_disk_diff(machine().options(), romp, chd->orig_chd(), chd->diff_chd());
if (err)
{
m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, err.message()));
m_errors++;
- chd = nullptr;
+ chd.reset();
continue;
}
}
- /* we're okay, add to the list of disks */
+ // we're okay, add to the list of disks
LOG("Assigning to handle %d\n", DISK_GETINDEX(romp));
- m_chd_list.push_back(std::move(chd));
+ m_chd_list.emplace_back(std::move(chd));
}
}
}
@@ -1132,7 +1254,11 @@ std::vector<std::string> rom_load_manager::get_software_searchpath(software_list
device
-------------------------------------------------*/
-std::error_condition rom_load_manager::open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd)
+std::error_condition rom_load_manager::open_disk_image(
+ emu_options &options,
+ const device_t &device,
+ const rom_entry *romp,
+ chd_file &image_chd)
{
const std::vector<std::string> searchpath(device.searchpath());
@@ -1141,8 +1267,14 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option
if (driver)
next_parent = next_parent_system(driver->system());
else
- next_parent = [] () { return nullptr; };
- return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent));
+ next_parent = next_parent_device(device, options);
+ chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent));
+ std::error_condition const err(
+ do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent));
+ if (!err && image_chd.parent_missing())
+ return chd_file::error::REQUIRES_PARENT;
+ else
+ return err;
}
@@ -1151,12 +1283,24 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option
software item
-------------------------------------------------*/
-std::error_condition rom_load_manager::open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd)
+std::error_condition rom_load_manager::open_disk_image(
+ emu_options &options,
+ software_list_device &swlist,
+ const software_info &swinfo,
+ const rom_entry *romp,
+ chd_file &image_chd)
{
std::vector<software_info const *> parents;
- std::vector<std::string> searchpath = make_software_searchpath(swlist, swinfo, parents);
+ std::vector<std::string> searchpath(make_software_searchpath(swlist, swinfo, parents));
searchpath.emplace_back(swlist.list_name()); // look for loose disk images in software list directory
- return do_open_disk(options, { searchpath }, romp, image_chd, next_parent_software(parents));
+ std::function<const rom_entry * ()> next_parent(next_parent_software(parents));
+ chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent));
+ std::error_condition const err(
+ do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent));
+ if (!err && image_chd.parent_missing())
+ return chd_file::error::REQUIRES_PARENT;
+ else
+ return err;
}
@@ -1216,11 +1360,11 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
m_romsloadedsize = 0;
std::vector<const software_info *> parents;
- std::vector<std::string> swsearch, disksearch, devsearch;
+ std::vector<std::string> swsearch, disksearch;
const software_info *const swinfo = swlist.find(std::string(swname));
if (swinfo)
{
- // dispay a warning for unsupported software
+ // display a warning for unsupported software
// TODO: list supported clones like we do for machines?
if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED)
{
@@ -1245,13 +1389,9 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
// this is convenient for CD-only lists so you don't need an extra level of directories containing one file each
disksearch.emplace_back(swlist.list_name());
- // for historical reasons, add the search path for the software list device's owner
- const device_t *const listowner = swlist.owner();
- if (listowner)
- devsearch = listowner->searchpath();
-
// loop until we hit the end
std::function<const rom_entry * ()> next_parent;
+ chd_file::open_parent_func open_parent;
for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
{
u32 regionlength = ROMREGION_GETLENGTH(region);
@@ -1266,7 +1406,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
u8 width = ROMREGION_GETWIDTH(region) / 8;
memory_region *memregion = machine().root_device().memregion(regiontag);
- if (memregion != nullptr)
+ if (memregion)
{
normalize_flags_for_device(regiontag, width, endianness);
@@ -1275,16 +1415,16 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
}
// remember the base and length
- m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
+ memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
+ LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base());
if (ROMREGION_ISERASE(region)) // clear the region if it's requested
- memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
- else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
- memset(m_region->base(), 0, m_region->bytes());
+ memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes());
+ else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
+ memset(memregion->base(), 0, memregion->bytes());
#ifdef MAME_DEBUG
else // if we're debugging, fill region with random data to catch errors
- fill_random(m_region->base(), m_region->bytes());
+ fill_random(memregion->base(), memregion->bytes());
#endif
// update total number of roms
@@ -1297,10 +1437,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
// now process the entries in the region
if (ROMREGION_ISROMDATA(region))
{
- if (devsearch.empty())
- process_rom_entries({ swsearch }, 0U, region, region + 1, true);
- else
- process_rom_entries({ swsearch, devsearch }, 0U, region, region + 1, true);
+ process_rom_entries(swsearch, 0U, *memregion, region, region + 1, true);
}
else if (ROMREGION_ISDISKDATA(region))
{
@@ -1310,11 +1447,9 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
next_parent = next_parent_software(parents);
else
next_parent = [] () { return nullptr; };
+ open_parent = open_parent_disk(machine().options(), { swsearch, disksearch }, next_parent);
}
- if (devsearch.empty())
- process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent);
- else
- process_disk_entries({ swsearch, disksearch, devsearch }, regiontag, region + 1, next_parent);
+ process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent, open_parent);
}
}
@@ -1340,6 +1475,7 @@ void rom_load_manager::process_region_list()
{
searchpath.clear();
std::function<const rom_entry * ()> next_parent;
+ chd_file::open_parent_func open_parent;
for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
{
u32 regionlength = ROMREGION_GETLENGTH(region);
@@ -1358,23 +1494,23 @@ void rom_load_manager::process_region_list()
normalize_flags_for_device(regiontag, width, endianness);
// remember the base and length
- m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
+ memory_region *const memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
+ LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base());
if (ROMREGION_ISERASE(region)) // clear the region if it's requested
- memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
- else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
- memset(m_region->base(), 0, m_region->bytes());
+ memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes());
+ else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
+ memset(memregion->base(), 0, memregion->bytes());
#ifdef MAME_DEBUG
else // if we're debugging, fill region with random data to catch errors
- fill_random(m_region->base(), m_region->bytes());
+ fill_random(memregion->base(), memregion->bytes());
#endif
// now process the entries in the region
if (searchpath.empty())
searchpath = device.searchpath();
assert(!searchpath.empty());
- process_rom_entries({ searchpath }, device.system_bios(), region, region + 1, false);
+ process_rom_entries(searchpath, device.system_bios(), *memregion, region, region + 1, false);
}
else if (ROMREGION_ISDISKDATA(region))
{
@@ -1387,9 +1523,10 @@ void rom_load_manager::process_region_list()
if (driver)
next_parent = next_parent_system(driver->system());
else
- next_parent = [] () { return nullptr; };
+ next_parent = next_parent_device(device, machine().options());
+ open_parent = open_parent_disk(machine().options(), { searchpath }, next_parent);
}
- process_disk_entries({ searchpath }, regiontag, region + 1, next_parent);
+ process_disk_entries({ searchpath }, regiontag, region + 1, next_parent, open_parent);
}
}
}
@@ -1426,7 +1563,6 @@ rom_load_manager::rom_load_manager(running_machine &machine)
, m_romsloadedsize(0)
, m_romstotalsize(0)
, m_chd_list()
- , m_region(nullptr)
, m_errorstring()
, m_softwarningstring()
{
@@ -1459,7 +1595,7 @@ rom_load_manager::rom_load_manager(running_machine &machine)
card_bios.erase(found);
}
}
- determine_bios_rom(device, specbios.c_str());
+ determine_bios_rom(device, specbios);
}
}
diff --git a/src/emu/romload.h b/src/emu/romload.h
index 76fdb111cc6..4ad0303a9f6 100644
--- a/src/emu/romload.h
+++ b/src/emu/romload.h
@@ -17,7 +17,9 @@
#include <functional>
#include <initializer_list>
+#include <memory>
#include <string>
+#include <string_view>
#include <system_error>
#include <type_traits>
#include <vector>
@@ -102,11 +104,11 @@ protected:
const_entry_iterator &operator=(const_entry_iterator &&) noexcept = default;
public:
- typedef T value_type;
- typedef value_type const *pointer;
- typedef value_type const &reference;
- typedef std::ptrdiff_t difference_type;
- typedef std::forward_iterator_tag iterator_category;
+ 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); }
@@ -387,6 +389,7 @@ class rom_load_manager
{
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; }
@@ -394,9 +397,9 @@ class rom_load_manager
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 */
+ 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:
@@ -420,7 +423,7 @@ public:
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, const char *fullpath);
+ 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);
@@ -428,11 +431,13 @@ public:
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(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd);
- static std::error_condition open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd);
+ 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:
- void determine_bios_rom(device_t &device, const char *specbios);
+ 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);
@@ -441,15 +446,40 @@ private:
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(std::initializer_list<std::reference_wrapper<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);
+ 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, const rom_entry *parent_region, const rom_entry *romp);
- void fill_rom_data(const rom_entry *romp);
- void copy_rom_data(const rom_entry *romp);
- void process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, 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(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent);
+ 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(memory_region &region, const rom_entry *romp);
+ void process_rom_entries(
+ 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();
@@ -467,8 +497,6 @@ private:
std::vector<std::unique_ptr<open_chd>> m_chd_list; /* disks */
- memory_region * m_region; // info about current region
-
std::string m_errorstring; // error string
std::string m_softwarningstring; // software warning string
};
diff --git a/src/emu/save.cpp b/src/emu/save.cpp
index a27a98ee23c..8c3329e7b38 100644
--- a/src/emu/save.cpp
+++ b/src/emu/save.cpp
@@ -25,7 +25,8 @@
#include "emu.h"
#include "emuopts.h"
-#include "util/coreutil.h"
+#include "main.h"
+
#include "util/ioprocs.h"
#include "util/ioprocsfilter.h"
@@ -66,7 +67,6 @@ enum
save_manager::save_manager(running_machine &machine)
: m_machine(machine)
, m_reg_allowed(true)
- , m_illegal_regs(0)
{
m_rewind = std::make_unique<rewinder>(*this);
}
@@ -185,9 +185,7 @@ void save_manager::save_memory(device_t *device, const char *module, const char
if (!m_reg_allowed)
{
machine().logerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name);
- if (machine().system().flags & machine_flags::SUPPORTS_SAVE)
- fatalerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name);
- m_illegal_regs++;
+ fatalerror("Attempt to register save state entry after state registration is closed!\nModule %s tag %s name %s\n", module, tag, name);
return;
}
@@ -208,7 +206,7 @@ void save_manager::save_memory(device_t *device, const char *module, const char
// state
//-------------------------------------------------
-save_error save_manager::check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...))
+save_error save_manager::check_file(running_machine &machine, util::core_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...))
{
// if we want to validate the signature, compute it
u32 sig;
@@ -217,10 +215,11 @@ save_error save_manager::check_file(running_machine &machine, emu_file &file, co
// seek to the beginning and read the header
file.seek(0, SEEK_SET);
u8 header[HEADER_SIZE];
- if (file.read(header, sizeof(header)) != sizeof(header))
+ auto const [err, actual] = read(file, header, sizeof(header));
+ if (err || (actual != sizeof(header)))
{
if (errormsg != nullptr)
- (*errormsg)("Could not read %s save file header",emulator_info::get_appname());
+ (*errormsg)("Could not read %s save file header", emulator_info::get_appname());
return STATERR_READ_ERROR;
}
@@ -257,16 +256,15 @@ void save_manager::dispatch_presave()
// write_file - writes the data to a file
//-------------------------------------------------
-save_error save_manager::write_file(emu_file &file)
+save_error save_manager::write_file(util::core_file &file)
{
util::write_stream::ptr writer;
save_error err = do_write(
[] (size_t total_size) { return true; },
[&writer] (const void *data, size_t size)
{
- size_t written;
- std::error_condition filerr = writer->write(data, size, written);
- return !filerr && (size == written);
+ auto const [filerr, written] = write(*writer, data, size);
+ return !filerr;
},
[&file, &writer] ()
{
@@ -290,16 +288,15 @@ save_error save_manager::write_file(emu_file &file)
// read_file - read the data from a file
//-------------------------------------------------
-save_error save_manager::read_file(emu_file &file)
+save_error save_manager::read_file(util::core_file &file)
{
util::read_stream::ptr reader;
return do_read(
[] (size_t total_size) { return true; },
[&reader] (void *data, size_t size)
{
- std::size_t read;
- std::error_condition filerr = reader->read(data, size, read);
- return !filerr && (read == size);
+ auto const [filerr, actual] = read(*reader, data, size);
+ return !filerr && (actual == size);
},
[&file, &reader] ()
{
@@ -405,10 +402,6 @@ save_error save_manager::read_buffer(const void *buf, size_t size)
template <typename T, typename U, typename V, typename W>
inline save_error save_manager::do_write(T check_space, U write_block, V start_header, W start_data)
{
- // if we have illegal registrations, return an error
- if (m_illegal_regs > 0)
- return STATERR_ILLEGAL_REGISTRATIONS;
-
// check for sufficient space
size_t total_size = HEADER_SIZE;
for (const auto &entry : m_entry_list)
@@ -452,10 +445,6 @@ inline save_error save_manager::do_write(T check_space, U write_block, V start_h
template <typename T, typename U, typename V, typename W>
inline save_error save_manager::do_read(T check_length, U read_block, V start_header, W start_data)
{
- // if we have illegal registrations, return an error
- if (m_illegal_regs > 0)
- return STATERR_ILLEGAL_REGISTRATIONS;
-
// check for sufficient space
size_t total_size = HEADER_SIZE;
for (const auto &entry : m_entry_list)
@@ -505,11 +494,11 @@ inline save_error save_manager::do_read(T check_length, U read_block, V start_he
u32 save_manager::signature() const
{
// iterate over entries
- u32 crc = 0;
+ util::crc32_creator crc;
for (auto &entry : m_entry_list)
{
// add the entry name to the CRC
- crc = core_crc32(crc, (u8 *)entry->m_name.c_str(), entry->m_name.length());
+ crc.append(entry->m_name.data(), entry->m_name.length());
// add the type and size to the CRC
u32 temp[4];
@@ -517,9 +506,9 @@ u32 save_manager::signature() const
temp[1] = little_endianize_int32(entry->m_typecount);
temp[2] = little_endianize_int32(entry->m_blockcount);
temp[3] = little_endianize_int32(entry->m_stride);
- crc = core_crc32(crc, (u8 *)&temp[0], sizeof(temp));
+ crc.append(&temp[0], sizeof(temp));
}
- return crc;
+ return crc.finish();
}
@@ -547,7 +536,7 @@ save_error save_manager::validate_header(const u8 *header, const char *gamename,
if (memcmp(header, STATE_MAGIC_NUM, 8))
{
if (errormsg != nullptr)
- (*errormsg)("%sThis is not a %s save file", error_prefix,emulator_info::get_appname());
+ (*errormsg)("%sThis is not a %s save file", error_prefix, emulator_info::get_appname());
return STATERR_INVALID_HEADER;
}
@@ -660,10 +649,6 @@ save_error ram_state::load()
// initialize
m_data.seekg(0);
- // if we have illegal registrations, return an error
- if (m_save.m_illegal_regs > 0)
- return STATERR_ILLEGAL_REGISTRATIONS;
-
// get the save manager to load state
return m_save.read_stream(m_data);
}
@@ -913,11 +898,6 @@ void rewinder::report_error(save_error error, rewind_operation operation)
switch (error)
{
// internal saveload failures
- case STATERR_ILLEGAL_REGISTRATIONS:
- m_save.machine().logerror("Rewind error: Unable to %s state due to illegal registrations.", opname);
- m_save.machine().popmessage("Rewind error occured. See error.log for details.");
- break;
-
case STATERR_INVALID_HEADER:
m_save.machine().logerror("Rewind error: Unable to %s state due to an invalid header. "
"Make sure the save state is correct for this machine.\n", opname);
diff --git a/src/emu/save.h b/src/emu/save.h
index 2ea17ab9921..e473f408317 100644
--- a/src/emu/save.h
+++ b/src/emu/save.h
@@ -34,7 +34,6 @@ enum save_error
{
STATERR_NONE,
STATERR_NOT_FOUND,
- STATERR_ILLEGAL_REGISTRATIONS,
STATERR_INVALID_HEADER,
STATERR_READ_ERROR,
STATERR_WRITE_ERROR,
@@ -300,9 +299,9 @@ public:
{ save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), element, valname, count); }
// file processing
- static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
- save_error write_file(emu_file &file);
- save_error read_file(emu_file &file);
+ static save_error check_file(running_machine &machine, util::core_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
+ save_error write_file(util::core_file &file);
+ save_error read_file(util::core_file &file);
save_error write_stream(std::ostream &str);
save_error read_stream(std::istream &str);
@@ -334,7 +333,6 @@ private:
running_machine & m_machine; // reference to our machine
std::unique_ptr<rewinder> m_rewind; // rewinder
bool m_reg_allowed; // are registrations allowed?
- s32 m_illegal_regs; // number of illegal registrations
std::vector<std::unique_ptr<state_entry>> m_entry_list; // list of registered entries
std::vector<std::unique_ptr<ram_state>> m_ramstate_list; // list of ram states
diff --git a/src/emu/schedule.cpp b/src/emu/schedule.cpp
index e32afb68f00..acc596d6798 100644
--- a/src/emu/schedule.cpp
+++ b/src/emu/schedule.cpp
@@ -44,19 +44,16 @@ enum
// emu_timer - constructor
//-------------------------------------------------
-emu_timer::emu_timer() :
- m_machine(nullptr),
+inline emu_timer::emu_timer() noexcept :
+ m_scheduler(nullptr),
m_next(nullptr),
m_prev(nullptr),
m_param(0),
- m_ptr(nullptr),
m_enabled(false),
m_temporary(false),
m_period(attotime::zero),
m_start(attotime::zero),
- m_expire(attotime::never),
- m_device(nullptr),
- m_id(0)
+ m_expire(attotime::never)
{
}
@@ -75,74 +72,35 @@ emu_timer::~emu_timer()
// re-allocated as a non-device timer
//-------------------------------------------------
-inline emu_timer &emu_timer::init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary)
+inline emu_timer &emu_timer::init(
+ running_machine &machine,
+ timer_expired_delegate &&callback,
+ attotime start_delay,
+ s32 param,
+ bool temporary)
{
// ensure the entire timer state is clean
- m_machine = &machine;
+ m_scheduler = &machine.scheduler();
m_next = nullptr;
m_prev = nullptr;
- m_callback = callback;
- m_param = 0;
- m_ptr = ptr;
- m_enabled = false;
+ m_callback = std::move(callback);
+ m_param = param;
m_temporary = temporary;
m_period = attotime::never;
- m_start = machine.time();
- m_expire = attotime::never;
- m_device = nullptr;
- m_id = 0;
-
- // if we're not temporary, register ourselves with the save state system
- if (!m_temporary)
- register_save();
-
- // insert into the list
- machine.scheduler().timer_list_insert(*this);
- return *this;
-}
-
-
-//-------------------------------------------------
-// init - completely initialize the state when
-// re-allocated as a device timer
-//-------------------------------------------------
-inline emu_timer &emu_timer::init(device_t &device, device_timer_id id, void *ptr, bool temporary)
-{
- // ensure the entire timer state is clean
- m_machine = &device.machine();
- m_next = nullptr;
- m_prev = nullptr;
- m_callback = timer_expired_delegate(FUNC(emu_timer::device_timer_expired), this);
- m_param = 0;
- m_ptr = ptr;
- m_enabled = false;
- m_temporary = temporary;
- m_period = attotime::never;
- m_start = machine().time();
- m_expire = attotime::never;
- m_device = &device;
- m_id = id;
+ m_start = m_scheduler->time();
+ m_expire = m_start + start_delay;
+ m_enabled = !m_expire.is_never();
// if we're not temporary, register ourselves with the save state system
if (!m_temporary)
- register_save();
+ register_save(machine.save());
// insert into the list
- machine().scheduler().timer_list_insert(*this);
- return *this;
-}
-
+ m_scheduler->timer_list_insert(*this);
+ if (this == m_scheduler->first_timer())
+ m_scheduler->abort_timeslice();
-//-------------------------------------------------
-// release - release us from the global list
-// management when deallocating
-//-------------------------------------------------
-
-inline emu_timer &emu_timer::release()
-{
- // unhook us from the global list
- machine().scheduler().timer_list_remove(*this);
return *this;
}
@@ -151,8 +109,10 @@ inline emu_timer &emu_timer::release()
// enable - enable/disable a timer
//-------------------------------------------------
-bool emu_timer::enable(bool enable)
+bool emu_timer::enable(bool enable) noexcept
{
+ assert(m_scheduler);
+
// reschedule only if the state has changed
const bool old = m_enabled;
if (old != enable)
@@ -161,8 +121,8 @@ bool emu_timer::enable(bool enable)
m_enabled = enable;
// remove the timer and insert back into the list
- machine().scheduler().timer_list_remove(*this);
- machine().scheduler().timer_list_insert(*this);
+ m_scheduler->timer_list_remove(*this);
+ m_scheduler->timer_list_insert(*this);
}
return old;
}
@@ -174,12 +134,13 @@ bool emu_timer::enable(bool enable)
// firings
//-------------------------------------------------
-void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period)
+void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period) noexcept
{
+ assert(m_scheduler);
+
// if this is the callback timer, mark it modified
- device_scheduler &scheduler = machine().scheduler();
- if (scheduler.m_callback_timer == this)
- scheduler.m_callback_timer_modified = true;
+ if (m_scheduler->m_callback_timer == this)
+ m_scheduler->m_callback_timer_modified = true;
// compute the time of the next firing and insert into the list
m_param = param;
@@ -190,17 +151,17 @@ void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period)
start_delay = attotime::zero;
// set the start and expire times
- m_start = scheduler.time();
+ m_start = m_scheduler->time();
m_expire = m_start + start_delay;
m_period = period;
// remove and re-insert the timer in its new order
- scheduler.timer_list_remove(*this);
- scheduler.timer_list_insert(*this);
+ m_scheduler->timer_list_remove(*this);
+ m_scheduler->timer_list_insert(*this);
// if this was inserted as the head, abort the current timeslice and resync
- if (this == scheduler.first_timer())
- scheduler.abort_timeslice();
+ if (this == m_scheduler->first_timer())
+ m_scheduler->abort_timeslice();
}
@@ -211,7 +172,9 @@ void emu_timer::adjust(attotime start_delay, s32 param, const attotime &period)
attotime emu_timer::elapsed() const noexcept
{
- return machine().time() - m_start;
+ assert(m_scheduler);
+
+ return m_scheduler->time() - m_start;
}
@@ -222,7 +185,9 @@ attotime emu_timer::elapsed() const noexcept
attotime emu_timer::remaining() const noexcept
{
- attotime curtime = machine().time();
+ assert(m_scheduler);
+
+ const attotime curtime = m_scheduler->time();
if (curtime >= m_expire)
return attotime::zero;
return m_expire - curtime;
@@ -234,40 +199,37 @@ attotime emu_timer::remaining() const noexcept
// state system
//-------------------------------------------------
-void emu_timer::register_save()
+void emu_timer::register_save(save_manager &manager)
{
- // determine our instance number and name
+ // determine our instance number - timers are indexed based on the callback function name
int index = 0;
- std::string name;
-
- if (m_device == nullptr)
+ std::string name = m_callback.name() ? m_callback.name() : "unnamed";
+ for (const emu_timer *curtimer = m_scheduler->first_timer(); curtimer; curtimer = curtimer->m_next)
{
- // for non-device timers, it is an index based on the callback function name
- name = m_callback.name() ? m_callback.name() : "unnamed";
- for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
- if (!curtimer->m_temporary && curtimer->m_device == nullptr)
- {
- if (curtimer->m_callback.name() != nullptr && m_callback.name() != nullptr && strcmp(curtimer->m_callback.name(), m_callback.name()) == 0)
- index++;
- else if (curtimer->m_callback.name() == nullptr && m_callback.name() == nullptr)
- index++;
- }
+ if (!curtimer->m_temporary)
+ {
+ if (curtimer->m_callback.name() && m_callback.name() && !strcmp(curtimer->m_callback.name(), m_callback.name()))
+ index++;
+ else if (!curtimer->m_callback.name() && !m_callback.name())
+ index++;
+ }
}
- else
+ for (const emu_timer *curtimer = m_scheduler->m_inactive_timers; curtimer; curtimer = curtimer->m_next)
{
- // for device timers, it is an index based on the device and timer ID
- name = string_format("%s/%d", m_device->tag(), m_id);
- for (emu_timer *curtimer = machine().scheduler().first_timer(); curtimer != nullptr; curtimer = curtimer->next())
- if (!curtimer->m_temporary && curtimer->m_device == m_device && curtimer->m_id == m_id)
- index++;
+ assert(!curtimer->m_temporary);
+
+ if (curtimer->m_callback.name() && m_callback.name() && !strcmp(curtimer->m_callback.name(), m_callback.name()))
+ index++;
+ else if (!curtimer->m_callback.name() && !m_callback.name())
+ index++;
}
// save the bits
- machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_param));
- machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_enabled));
- machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_period));
- machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_start));
- machine().save().save_item(m_device, "timer", name.c_str(), index, NAME(m_expire));
+ manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_param));
+ manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_enabled));
+ manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_period));
+ manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_start));
+ manager.save_item(nullptr, "timer", name.c_str(), index, NAME(m_expire));
}
@@ -276,16 +238,17 @@ void emu_timer::register_save()
// period
//-------------------------------------------------
-inline void emu_timer::schedule_next_period()
+inline void emu_timer::schedule_next_period() noexcept
{
+ assert(m_scheduler);
+
// advance by one period
m_start = m_expire;
m_expire += m_period;
// remove and re-insert us
- device_scheduler &scheduler = machine().scheduler();
- scheduler.timer_list_remove(*this);
- scheduler.timer_list_insert(*this);
+ m_scheduler->timer_list_remove(*this);
+ m_scheduler->timer_list_insert(*this);
}
@@ -296,25 +259,13 @@ inline void emu_timer::schedule_next_period()
void emu_timer::dump() const
{
- machine().logerror("%p: en=%d temp=%d exp=%15s start=%15s per=%15s param=%d ptr=%p", this, m_enabled, m_temporary, m_expire.as_string(PRECISION), m_start.as_string(PRECISION), m_period.as_string(PRECISION), m_param, m_ptr);
- if (m_device == nullptr)
- if (m_callback.name() == nullptr)
- machine().logerror(" cb=NULL\n");
- else
- machine().logerror(" cb=%s\n", m_callback.name());
- else
- machine().logerror(" dev=%s id=%d\n", m_device->tag(), m_id);
-}
+ assert(m_scheduler);
-
-//-------------------------------------------------
-// device_timer_expired - trampoline to avoid a
-// conditional jump on the hot path
-//-------------------------------------------------
-
-void emu_timer::device_timer_expired(emu_timer &timer, void *ptr, s32 param)
-{
- timer.m_device->timer_expired(timer, timer.m_id, param, ptr);
+ m_scheduler->machine().logerror("%p: en=%d temp=%d exp=%15s start=%15s per=%15s param=%d", this, m_enabled, m_temporary, m_expire.as_string(PRECISION), m_start.as_string(PRECISION), m_period.as_string(PRECISION), m_param);
+ if (!m_callback.name())
+ m_scheduler->machine().logerror(" cb=NULL\n");
+ else
+ m_scheduler->machine().logerror(" cb=%s\n", m_callback.name());
}
@@ -333,6 +284,7 @@ device_scheduler::device_scheduler(running_machine &machine) :
m_execute_list(nullptr),
m_basetime(attotime::zero),
m_timer_list(nullptr),
+ m_inactive_timers(nullptr),
m_callback_timer(nullptr),
m_callback_timer_modified(false),
m_callback_timer_expire_time(attotime::zero),
@@ -340,8 +292,13 @@ device_scheduler::device_scheduler(running_machine &machine) :
m_quantum_minimum(ATTOSECONDS_IN_NSEC(1) / 1000)
{
// append a single never-expiring timer so there is always one in the list
- m_timer_list = &m_timer_allocator.alloc()->init(machine, timer_expired_delegate(), nullptr, true);
- m_timer_list->adjust(attotime::never);
+ // need to subvert it because it would naturally be inserted in the inactive list
+ m_timer_list = &timer_list_remove(m_timer_allocator.alloc()->init(machine, timer_expired_delegate(), attotime::never, 0, true));
+
+ assert(m_timer_list);
+ assert(!m_timer_list->m_prev);
+ assert(!m_timer_list->m_next);
+ assert(!m_inactive_timers);
// register global states
machine.save().save_item(NAME(m_basetime));
@@ -357,8 +314,10 @@ device_scheduler::device_scheduler(running_machine &machine) :
device_scheduler::~device_scheduler()
{
// remove all timers
- while (m_timer_list != nullptr)
- m_timer_allocator.reclaim(m_timer_list->release());
+ while (m_inactive_timers)
+ m_timer_allocator.reclaim(timer_list_remove(*m_inactive_timers));
+ while (m_timer_list)
+ m_timer_allocator.reclaim(timer_list_remove(*m_timer_list));
}
@@ -386,13 +345,15 @@ attotime device_scheduler::time() const noexcept
bool device_scheduler::can_save() const
{
// if any live temporary timers exit, fail
- for (emu_timer *timer = m_timer_list; timer != nullptr; timer = timer->next())
+ for (emu_timer *timer = m_timer_list; timer; timer = timer->m_next)
+ {
if (timer->m_temporary && !timer->expire().is_never())
{
machine().logerror("Failed save state attempt due to anonymous timers:\n");
dump_timers();
return false;
}
+ }
// otherwise, we're good
return true;
@@ -484,7 +445,7 @@ void device_scheduler::timeslice()
// if we're not suspended, actually execute
if (exec->m_suspend == 0)
{
- g_profiler.start(exec->m_profiler);
+ auto profile = g_profiler.start(exec->m_profiler);
// note that this global variable cycles_stolen can be modified
// via the call to cpu_execute
@@ -505,7 +466,6 @@ void device_scheduler::timeslice()
ran -= *exec->m_icountptr;
assert(ran >= exec->m_cycles_stolen);
ran -= exec->m_cycles_stolen;
- g_profiler.stop();
}
// account for these cycles
@@ -550,7 +510,7 @@ void device_scheduler::timeslice()
// current timeslice
//-------------------------------------------------
-void device_scheduler::abort_timeslice()
+void device_scheduler::abort_timeslice() noexcept
{
if (m_executing_device != nullptr)
m_executing_device->abort_timeslice();
@@ -567,74 +527,117 @@ void device_scheduler::trigger(int trigid, const attotime &after)
if (m_execute_list == nullptr)
rebuild_execute_list();
- // if we have a non-zero time, schedule a timer
if (after != attotime::zero)
+ {
+ // if we have a non-zero time, schedule a timer
timer_set(after, timer_expired_delegate(FUNC(device_scheduler::timed_trigger), this), trigid);
-
- // send the trigger to everyone who cares
+ }
else
- for (device_execute_interface *exec = m_execute_list; exec != nullptr; exec = exec->m_nextexec)
+ {
+ // send the trigger to everyone who cares
+ for (device_execute_interface *exec = m_execute_list; exec; exec = exec->m_nextexec)
exec->trigger(trigid);
+ }
}
//-------------------------------------------------
-// boost_interleave - temporarily boosts the
-// interleave factor
+// add_quantum - add a scheduling quantum;
+// the smallest active one is the one that is in use
//-------------------------------------------------
-void device_scheduler::boost_interleave(const attotime &timeslice_time, const attotime &boost_duration)
+void device_scheduler::add_quantum(const attotime &quantum, const attotime &duration)
{
- // ignore timeslices > 1 second
- if (timeslice_time.seconds() > 0)
- return;
- add_scheduling_quantum(timeslice_time, boost_duration);
+ assert(quantum.seconds() == 0);
+
+ attotime curtime = time();
+ attotime expire = curtime + duration;
+ const attoseconds_t quantum_attos = quantum.attoseconds();
+
+ // figure out where to insert ourselves, expiring any quanta that are out-of-date
+ quantum_slot *insert_after = nullptr;
+ quantum_slot *next;
+ for (quantum_slot *quant = m_quantum_list.first(); quant != nullptr; quant = next)
+ {
+ // if this quantum is expired, nuke it
+ next = quant->next();
+ if (curtime >= quant->m_expire)
+ m_quantum_allocator.reclaim(m_quantum_list.detach(*quant));
+
+ // if this quantum is shorter than us, we need to be inserted afterwards
+ else if (quant->m_requested <= quantum_attos)
+ insert_after = quant;
+ }
+
+ // if we found an exact match, just take the maximum expiry time
+ if (insert_after != nullptr && insert_after->m_requested == quantum_attos)
+ insert_after->m_expire = std::max(insert_after->m_expire, expire);
+
+ // otherwise, allocate a new quantum and insert it after the one we picked
+ else
+ {
+ quantum_slot &quant = *m_quantum_allocator.alloc();
+ quant.m_requested = quantum_attos;
+ quant.m_actual = std::max(quantum_attos, m_quantum_minimum);
+ quant.m_expire = expire;
+ m_quantum_list.insert_after(quant, insert_after);
+ }
}
//-------------------------------------------------
-// timer_alloc - allocate a global non-device
-// timer and return a pointer
+// perfect_quantum - add a (temporary) minimum
+// scheduling quantum to boost the interleave
//-------------------------------------------------
-emu_timer *device_scheduler::timer_alloc(timer_expired_delegate callback, void *ptr)
+void device_scheduler::perfect_quantum(const attotime &duration)
{
- return &m_timer_allocator.alloc()->init(machine(), callback, ptr, false);
+ add_quantum(attotime::zero, duration);
}
//-------------------------------------------------
-// timer_set - allocate an anonymous non-device
-// timer and set it to go off after the given
-// amount of time
+// timer_alloc - allocate a global non-device
+// timer and return a pointer
//-------------------------------------------------
-void device_scheduler::timer_set(const attotime &duration, timer_expired_delegate callback, int param, void *ptr)
+emu_timer *device_scheduler::timer_alloc(timer_expired_delegate callback)
{
- m_timer_allocator.alloc()->init(machine(), callback, ptr, true).adjust(duration, param);
+ return &m_timer_allocator.alloc()->init(machine(), std::move(callback), attotime::never, 0, false);
}
//-------------------------------------------------
-// timer_alloc - allocate a global device timer
-// and return a pointer
+// timer_set - allocate an anonymous non-device
+// timer and set it to go off after the given
+// amount of time
//-------------------------------------------------
-emu_timer *device_scheduler::timer_alloc(device_t &device, device_timer_id id, void *ptr)
+void device_scheduler::timer_set(const attotime &duration, timer_expired_delegate callback, s32 param)
{
- return &m_timer_allocator.alloc()->init(device, id, ptr, false);
+ [[maybe_unused]] emu_timer &timer = m_timer_allocator.alloc()->init(
+ machine(),
+ std::move(callback),
+ duration,
+ param,
+ true);
+ assert(!timer.m_expire.is_never()); // this is not handled
}
//-------------------------------------------------
-// timer_set - allocate an anonymous device timer
-// and set it to go off after the given amount of
-// time
+// synchronize - allocate an anonymous non-device
+// timer and set it to go off as soon as possible
//-------------------------------------------------
-void device_scheduler::timer_set(const attotime &duration, device_t &device, device_timer_id id, int param, void *ptr)
+void device_scheduler::synchronize(timer_expired_delegate callback, s32 param)
{
- m_timer_allocator.alloc()->init(device, id, ptr, true).adjust(duration, param);
+ m_timer_allocator.alloc()->init(
+ machine(),
+ std::move(callback),
+ attotime::zero,
+ param,
+ true);
}
@@ -655,7 +658,7 @@ void device_scheduler::eat_all_cycles()
// given amount of time
//-------------------------------------------------
-void device_scheduler::timed_trigger(void *ptr, s32 param)
+void device_scheduler::timed_trigger(s32 param)
{
trigger(param);
}
@@ -682,24 +685,47 @@ void device_scheduler::presave()
void device_scheduler::postload()
{
// remove all timers and make a private list of permanent ones
- simple_list<emu_timer> private_list;
- while (m_timer_list != nullptr)
+ emu_timer *private_list = nullptr;
+ while (m_inactive_timers)
+ {
+ emu_timer &timer = *m_inactive_timers;
+ assert(!timer.m_temporary);
+
+ timer_list_remove(timer).m_next = private_list;
+ private_list = &timer;
+ }
+ while (m_timer_list->m_next)
{
emu_timer &timer = *m_timer_list;
- // temporary timers go away entirely (except our special never-expiring one)
- if (timer.m_temporary && !timer.expire().is_never())
- m_timer_allocator.reclaim(timer.release());
+ if (timer.m_temporary)
+ {
+ assert(!timer.expire().is_never());
- // permanent ones get added to our private list
+ // temporary timers go away entirely (except our special never-expiring one)
+ timer.m_callback.reset();
+ m_timer_allocator.reclaim(timer_list_remove(timer));
+ }
else
- private_list.append(timer_list_remove(timer));
+ {
+ // permanent ones get added to our private list
+ timer_list_remove(timer).m_next = private_list;
+ private_list = &timer;
+ }
}
+ // special dummy timer
+ assert(!m_timer_list->m_enabled);
+ assert(m_timer_list->m_temporary);
+ assert(m_timer_list->m_expire.is_never());
+
// now re-insert them; this effectively re-sorts them by time
- emu_timer *timer;
- while ((timer = private_list.detach_head()) != nullptr)
- timer_list_insert(*timer);
+ while (private_list)
+ {
+ emu_timer &timer = *private_list;
+ private_list = timer.m_next;
+ timer_list_insert(timer);
+ }
m_suspend_changes_pending = true;
rebuild_execute_list();
@@ -775,7 +801,7 @@ void device_scheduler::rebuild_execute_list()
min_quantum = (std::min)(attotime(0, exec->minimum_quantum()), min_quantum);
// inform the timer system of our decision
- add_scheduling_quantum(min_quantum, attotime::never);
+ add_quantum(min_quantum, attotime::never);
}
// start with an empty list
@@ -815,38 +841,50 @@ void device_scheduler::rebuild_execute_list()
inline emu_timer &device_scheduler::timer_list_insert(emu_timer &timer)
{
- // disabled timers sort to the end
- const attotime expire = timer.m_enabled ? timer.m_expire : attotime::never;
-
- // loop over the timer list
- emu_timer *prevtimer = nullptr;
- for (emu_timer *curtimer = m_timer_list; curtimer != nullptr; prevtimer = curtimer, curtimer = curtimer->next())
+ // disabled timers never expire
+ if (!timer.m_expire.is_never() && timer.m_enabled)
{
- // if the current list entry expires after us, we should be inserted before it
- if (curtimer->m_expire > expire)
+ // loop over the timer list
+ emu_timer *prevtimer = nullptr;
+ for (emu_timer *curtimer = m_timer_list; curtimer; prevtimer = curtimer, curtimer = curtimer->m_next)
{
- // link the new guy in before the current list entry
- timer.m_prev = prevtimer;
- timer.m_next = curtimer;
+ // if the current list entry expires after us, we should be inserted before it
+ if (curtimer->m_expire > timer.m_expire)
+ {
+ // link the new guy in before the current list entry
+ timer.m_prev = prevtimer;
+ timer.m_next = curtimer;
- if (prevtimer != nullptr)
- prevtimer->m_next = &timer;
- else
- m_timer_list = &timer;
+ if (prevtimer)
+ prevtimer->m_next = &timer;
+ else
+ m_timer_list = &timer;
- curtimer->m_prev = &timer;
- return timer;
+ curtimer->m_prev = &timer;
+ return timer;
+ }
}
- }
- // need to insert after the last one
- if (prevtimer != nullptr)
- prevtimer->m_next = &timer;
+ // need to insert after the last one
+ if (prevtimer)
+ prevtimer->m_next = &timer;
+ else
+ m_timer_list = &timer;
+
+ timer.m_prev = prevtimer;
+ timer.m_next = nullptr;
+ }
else
- m_timer_list = &timer;
+ {
+ // keep inactive timers in a separate list
+ if (m_inactive_timers)
+ m_inactive_timers->m_prev = &timer;
+
+ timer.m_next = m_inactive_timers;
+ timer.m_prev = nullptr;
- timer.m_prev = prevtimer;
- timer.m_next = nullptr;
+ m_inactive_timers = &timer;
+ }
return timer;
}
@@ -859,12 +897,21 @@ inline emu_timer &device_scheduler::timer_list_insert(emu_timer &timer)
inline emu_timer &device_scheduler::timer_list_remove(emu_timer &timer)
{
// remove it from the list
- if (timer.m_prev != nullptr)
+ if (timer.m_prev)
+ {
timer.m_prev->m_next = timer.m_next;
- else
+ }
+ else if (&timer == m_timer_list)
+ {
m_timer_list = timer.m_next;
+ }
+ else
+ {
+ assert(&timer == m_inactive_timers);
+ m_inactive_timers = timer.m_next;
+ }
- if (timer.m_next != nullptr)
+ if (timer.m_next)
timer.m_next->m_prev = timer.m_prev;
return timer;
@@ -896,30 +943,29 @@ inline void device_scheduler::execute_timers()
// call the callback
if (was_enabled)
{
- g_profiler.start(PROFILER_TIMER_CALLBACK);
+ auto profile = g_profiler.start(PROFILER_TIMER_CALLBACK);
if (!timer.m_callback.isnull())
{
- if (timer.m_device != nullptr)
- LOG("execute_timers: timer device %s timer %d\n", timer.m_device->tag(), timer.m_id);
- else
- LOG("execute_timers: timer callback %s\n", timer.m_callback.name());
- timer.m_callback(timer.m_ptr, timer.m_param);
+ LOG("execute_timers: timer callback %s\n", timer.m_callback.name());
+ timer.m_callback(timer.m_param);
}
-
- g_profiler.stop();
}
// reset or remove the timer, but only if it wasn't modified during the callback
if (!m_callback_timer_modified)
{
- // if the timer is temporary, remove it now
- if (timer.m_temporary)
- m_timer_allocator.reclaim(timer.release());
-
- // otherwise, reschedule it
- else
+ if (!timer.m_temporary)
+ {
+ // if the timer is not temporary, reschedule it
timer.schedule_next_period();
+ }
+ else
+ {
+ // otherwise, remove it now
+ timer.m_callback.reset();
+ m_timer_allocator.reclaim(timer_list_remove(timer));
+ }
}
}
@@ -929,51 +975,6 @@ inline void device_scheduler::execute_timers()
//-------------------------------------------------
-// add_scheduling_quantum - add a scheduling
-// quantum; the smallest active one is the one
-// that is in use
-//-------------------------------------------------
-
-void device_scheduler::add_scheduling_quantum(const attotime &quantum, const attotime &duration)
-{
- assert(quantum.seconds() == 0);
-
- attotime curtime = time();
- attotime expire = curtime + duration;
- const attoseconds_t quantum_attos = quantum.attoseconds();
-
- // figure out where to insert ourselves, expiring any quanta that are out-of-date
- quantum_slot *insert_after = nullptr;
- quantum_slot *next;
- for (quantum_slot *quant = m_quantum_list.first(); quant != nullptr; quant = next)
- {
- // if this quantum is expired, nuke it
- next = quant->next();
- if (curtime >= quant->m_expire)
- m_quantum_allocator.reclaim(m_quantum_list.detach(*quant));
-
- // if this quantum is shorter than us, we need to be inserted afterwards
- else if (quant->m_requested <= quantum_attos)
- insert_after = quant;
- }
-
- // if we found an exact match, just take the maximum expiry time
- if (insert_after != nullptr && insert_after->m_requested == quantum_attos)
- insert_after->m_expire = std::max(insert_after->m_expire, expire);
-
- // otherwise, allocate a new quantum and insert it after the one we picked
- else
- {
- quantum_slot &quant = *m_quantum_allocator.alloc();
- quant.m_requested = quantum_attos;
- quant.m_actual = std::max(quantum_attos, m_quantum_minimum);
- quant.m_expire = expire;
- m_quantum_list.insert_after(quant, insert_after);
- }
-}
-
-
-//-------------------------------------------------
// dump_timers - dump the current timer state
//-------------------------------------------------
@@ -981,7 +982,9 @@ void device_scheduler::dump_timers() const
{
machine().logerror("=============================================\n");
machine().logerror("Timer Dump: Time = %15s\n", time().as_string(PRECISION));
- for (emu_timer *timer = first_timer(); timer != nullptr; timer = timer->next())
+ for (emu_timer *timer = m_timer_list; timer; timer = timer->m_next)
+ timer->dump();
+ for (emu_timer *timer = m_inactive_timers; timer; timer = timer->m_next)
timer->dump();
machine().logerror("=============================================\n");
}
diff --git a/src/emu/schedule.h b/src/emu/schedule.h
index 9e90ed68ed5..e13fc18d573 100644
--- a/src/emu/schedule.h
+++ b/src/emu/schedule.h
@@ -22,7 +22,7 @@
// MACROS
//**************************************************************************
-#define TIMER_CALLBACK_MEMBER(name) void name(void *ptr, s32 param)
+#define TIMER_CALLBACK_MEMBER(name) void name(s32 param)
//**************************************************************************
@@ -30,70 +30,65 @@
//**************************************************************************
// timer callbacks look like this
-typedef named_delegate<void (void *, s32)> timer_expired_delegate;
+typedef named_delegate<void (s32)> timer_expired_delegate;
// ======================> emu_timer
class emu_timer
{
- friend class device_scheduler;
- friend class simple_list<emu_timer>;
- friend class fixed_allocator<emu_timer>;
-
- // construction/destruction
- emu_timer();
- ~emu_timer();
-
- // allocation and re-use
- emu_timer &init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary);
- emu_timer &init(device_t &device, device_timer_id id, void *ptr, bool temporary);
- emu_timer &release();
-
public:
// getters
- emu_timer *next() const { return m_next; }
- running_machine &machine() const noexcept { assert(m_machine != nullptr); return *m_machine; }
- bool enabled() const { return m_enabled; }
- int param() const { return m_param; }
- void *ptr() const { return m_ptr; }
+ bool enabled() const noexcept { return m_enabled; }
+ s32 param() const noexcept { return m_param; }
// setters
- bool enable(bool enable = true);
- void set_param(int param) { m_param = param; }
- void set_ptr(void *ptr) { m_ptr = ptr; }
+ bool enable(bool enable = true) noexcept;
+ void set_param(s32 param) noexcept { m_param = param; }
// control
- void reset(const attotime &duration = attotime::never) { adjust(duration, m_param, m_period); }
- void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never);
+ void reset(const attotime &duration = attotime::never) noexcept { adjust(duration, m_param, m_period); }
+ void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never) noexcept;
// timing queries
attotime elapsed() const noexcept;
attotime remaining() const noexcept;
- attotime start() const { return m_start; }
- attotime expire() const { return m_expire; }
- attotime period() const { return m_period; }
+ attotime start() const noexcept { return m_start; }
+ attotime expire() const noexcept { return m_expire; }
+ attotime period() const noexcept { return m_period; }
private:
+ // construction/destruction
+ emu_timer() noexcept;
+ ~emu_timer();
+
+ // allocation and re-use
+ emu_timer &init(
+ running_machine &machine,
+ timer_expired_delegate &&callback,
+ attotime start_delay,
+ s32 param,
+ bool temporary);
+
// internal helpers
- void register_save();
- void schedule_next_period();
+ void register_save(save_manager &manager) ATTR_COLD;
+ void schedule_next_period() noexcept;
void dump() const;
- static void device_timer_expired(emu_timer &timer, void *ptr, s32 param);
// internal state
- running_machine * m_machine; // reference to the owning machine
+ device_scheduler * m_scheduler; // reference to the owning machine
emu_timer * m_next; // next timer in order in the list
emu_timer * m_prev; // previous timer in order in the list
timer_expired_delegate m_callback; // callback function
s32 m_param; // integer parameter
- void * m_ptr; // pointer parameter
bool m_enabled; // is the timer enabled?
bool m_temporary; // is the timer temporary?
attotime m_period; // the repeat frequency of the timer
attotime m_start; // time when the timer was started
attotime m_expire; // time when the timer will expire
- device_t * m_device; // for device timers, a pointer to the device
- device_timer_id m_id; // for device timers, the ID of the timer
+
+ friend class device_scheduler;
+ friend class fixed_allocator<emu_timer>;
+ friend class simple_list<emu_timer>; // FIXME: fixed_allocator requires this
};
@@ -112,25 +107,23 @@ public:
// getters
running_machine &machine() const noexcept { return m_machine; }
attotime time() const noexcept;
- emu_timer *first_timer() const { return m_timer_list; }
+ emu_timer *first_timer() const noexcept { return m_timer_list; }
device_execute_interface *currently_executing() const noexcept { return m_executing_device; }
bool can_save() const;
// execution
void timeslice();
- void abort_timeslice();
+ void abort_timeslice() noexcept;
void trigger(int trigid, const attotime &after = attotime::zero);
- void boost_interleave(const attotime &timeslice_time, const attotime &boost_duration);
+ void add_quantum(const attotime &quantum, const attotime &duration);
+ void perfect_quantum(const attotime &duration);
void suspend_resume_changed() { m_suspend_changes_pending = true; }
// timers, specified by callback/name
- emu_timer *timer_alloc(timer_expired_delegate callback, void *ptr = nullptr);
- void timer_set(const attotime &duration, timer_expired_delegate callback, int param = 0, void *ptr = nullptr);
- void synchronize(timer_expired_delegate callback = timer_expired_delegate(), int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, callback, param, ptr); }
-
- // timers, specified by device/id; generally devices should use the device_t methods instead
- emu_timer *timer_alloc(device_t &device, device_timer_id id = 0, void *ptr = nullptr);
- void timer_set(const attotime &duration, device_t &device, device_timer_id id = 0, int param = 0, void *ptr = nullptr);
+ emu_timer *timer_alloc(timer_expired_delegate callback);
+ [[deprecated("timer_set is deprecated; please avoid anonymous timers. Use an allocated emu_timer instead.")]]
+ void timer_set(const attotime &duration, timer_expired_delegate callback, s32 param = 0);
+ void synchronize(timer_expired_delegate callback = timer_expired_delegate(), s32 param = 0);
// debugging
void dump_timers() const;
@@ -140,7 +133,7 @@ public:
private:
// callbacks
- void timed_trigger(void *ptr, s32 param);
+ void timed_trigger(s32 param);
void presave();
void postload();
@@ -148,7 +141,6 @@ private:
void compute_perfect_interleave();
void rebuild_execute_list();
void apply_suspend_changes();
- void add_scheduling_quantum(const attotime &quantum, const attotime &duration);
// timer helpers
emu_timer &timer_list_insert(emu_timer &timer);
@@ -163,6 +155,7 @@ private:
// list of active timers
emu_timer * m_timer_list; // head of the active list
+ emu_timer * m_inactive_timers; // head of the inactive timer list
fixed_allocator<emu_timer> m_timer_allocator; // allocator for timers
// other internal states
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index 5a9c055bbbb..cf311fb21eb 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -12,6 +12,8 @@
#include "screen.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "render.h"
#include "rendutil.h"
@@ -554,7 +556,7 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev
, m_curtexture(0)
, m_changed(true)
, m_last_partial_scan(0)
- , m_partial_scan_hpos(-1)
+ , m_partial_scan_hpos(0)
, m_color(rgb_t(0xff, 0xff, 0xff, 0xff))
, m_brightness(0xff)
, m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds())
@@ -683,9 +685,9 @@ void screen_device::device_validity_check(validity_checker &valid) const
osd_printf_error("Non-raster display cannot have a variable width\n");
}
- // check for zero frame rate
- if (m_refresh == 0)
- osd_printf_error("Invalid (zero) refresh rate\n");
+ // check for invalid frame rate
+ if (m_refresh == 0 || m_refresh > ATTOSECONDS_PER_SECOND)
+ osd_printf_error("Invalid (under 1Hz) refresh rate\n");
texture_format texformat = !m_screen_update_ind16.isnull() ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32;
if (m_palette.finder_tag() != finder_base::DUMMY_TAG)
@@ -770,8 +772,6 @@ void screen_device::device_resolve_objects()
// bind our handlers
m_screen_update_ind16.resolve();
m_screen_update_rgb32.resolve();
- m_screen_vblank.resolve_safe();
- m_scanline_cb.resolve();
// assign our format to the palette before it starts
if (m_palette)
@@ -834,15 +834,15 @@ void screen_device::device_start()
m_container->set_user_settings(settings);
// allocate the VBLANK timers
- m_vblank_begin_timer = timer_alloc(TID_VBLANK_START);
- m_vblank_end_timer = timer_alloc(TID_VBLANK_END);
+ m_vblank_begin_timer = timer_alloc(FUNC(screen_device::vblank_begin), this);
+ m_vblank_end_timer = timer_alloc(FUNC(screen_device::vblank_end), this);
// allocate a timer to reset partial updates
- m_scanline0_timer = timer_alloc(TID_SCANLINE0);
+ m_scanline0_timer = timer_alloc(FUNC(screen_device::first_scanline_tick), this);
// allocate a timer to generate per-scanline updates
- if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb)
- m_scanline_timer = timer_alloc(TID_SCANLINE);
+ if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset())
+ m_scanline_timer = timer_alloc(FUNC(screen_device::scanline_tick), this);
// configure the screen with the default parameters
configure(m_width, m_height, m_visarea, m_refresh);
@@ -852,7 +852,7 @@ void screen_device::device_start()
m_vblank_end_time = attotime(0, m_vblank_period);
// start the timer to generate per-scanline updates
- if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb)
+ if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset())
m_scanline_timer->adjust(time_until_pos(0));
// create burn-in bitmap
@@ -887,7 +887,7 @@ void screen_device::device_start()
save_item(NAME(m_vblank_end_time));
save_item(NAME(m_frame_number));
if (m_oldstyle_vblank_supplied)
- logerror("%s: Deprecated legacy Old Style screen configured (MCFG_SCREEN_VBLANK_TIME), please use MCFG_SCREEN_RAW_PARAMS instead.\n",this->tag());
+ logerror("%s: Deprecated legacy Old Style screen configured (set_vblank_time), please use set_raw instead.\n",this->tag());
m_is_primary_screen = (this == screen_device_enumerator(machine().root_device()).first());
}
@@ -930,54 +930,39 @@ void screen_device::device_post_load()
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
+// timer events
//-------------------------------------------------
-void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(screen_device::first_scanline_tick)
{
- switch (id)
+ // first scanline
+ reset_partial_updates();
+ if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
- // signal VBLANK start
- case TID_VBLANK_START:
- vblank_begin();
- break;
-
- // signal VBLANK end
- case TID_VBLANK_END:
- vblank_end();
- break;
-
- // first scanline
- case TID_SCANLINE0:
- reset_partial_updates();
- if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
- {
- pre_update_scanline(0);
- }
- break;
+ pre_update_scanline(0);
+ }
+}
- // subsequent scanlines when scanline updates are enabled
- case TID_SCANLINE:
- if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
- {
- pre_update_scanline(param);
- }
- if (m_video_attributes & VIDEO_UPDATE_SCANLINE)
- {
- // force a partial update to the current scanline
- update_partial(param);
- }
- if (m_scanline_cb)
- m_scanline_cb(param);
-
- // compute the next visible scanline
- param++;
- if (param > m_visarea.bottom())
- param = m_visarea.top();
- m_scanline_timer->adjust(time_until_pos(param), param);
- break;
+TIMER_CALLBACK_MEMBER(screen_device::scanline_tick)
+{
+ // subsequent scanlines when scanline updates are enabled
+ if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
+ {
+ pre_update_scanline(param);
+ }
+ if (m_video_attributes & VIDEO_UPDATE_SCANLINE)
+ {
+ // force a partial update to the current scanline
+ update_partial(param);
}
+ if (!m_scanline_cb.isunset())
+ m_scanline_cb(param);
+
+ // compute the next visible scanline
+ param++;
+ if (param > m_visarea.bottom())
+ param = m_visarea.top();
+ m_scanline_timer->adjust(time_until_pos(param), param);
}
@@ -1026,7 +1011,7 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a
// call the VBLANK start timer now; otherwise, adjust it for the future
attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds();
if (delta >= m_frame_period)
- vblank_begin();
+ vblank_begin(0);
else
m_vblank_begin_timer->adjust(time_until_vblank_start());
@@ -1064,7 +1049,7 @@ void screen_device::reset_origin(int beamy, int beamx)
// if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start,
// call the VBLANK start timer now; otherwise, adjust it for the future
if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0)
- vblank_begin();
+ vblank_begin(0);
else
m_vblank_begin_timer->adjust(time_until_vblank_start());
}
@@ -1196,55 +1181,56 @@ bool screen_device::update_partial(int scanline)
// otherwise, render
LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom()));
- g_profiler.start(PROFILER_VIDEO);
u32 flags = 0;
- if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
- rectangle scan_clip(clip);
- for (int y = clip.top(); y <= clip.bottom(); y++)
+ auto profile = g_profiler.start(PROFILER_VIDEO);
+ if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
- scan_clip.sety(y, y);
- pre_update_scanline(y);
-
- screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
- switch (curbitmap.format())
+ rectangle scan_clip(clip);
+ for (int y = clip.top(); y <= clip.bottom(); y++)
{
- default:
- case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
- case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
- }
+ scan_clip.sety(y, y);
+ pre_update_scanline(y);
- m_partial_updates_this_frame++;
- }
- }
- else
- {
- if (m_type != SCREEN_TYPE_SVG)
- {
- screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
- switch (curbitmap.format())
- {
- default:
- case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
- case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
+ screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
+ switch (curbitmap.format())
+ {
+ default:
+ case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
+ case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break;
+ }
+
+ m_partial_updates_this_frame++;
}
}
else
{
- flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
+ if (m_type != SCREEN_TYPE_SVG)
+ {
+ screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
+ switch (curbitmap.format())
+ {
+ default:
+ case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
+ case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
+ }
+ }
+ else
+ {
+ flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip);
+ }
+ m_partial_updates_this_frame++;
}
- m_partial_updates_this_frame++;
+ // stop profiling
}
- g_profiler.stop();
-
// if we modified the bitmap, we have to commit
m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
// remember where we left off
m_last_partial_scan = scanline + 1;
- m_partial_scan_hpos = -1;
+ m_partial_scan_hpos = 0;
return true;
}
@@ -1298,10 +1284,10 @@ void screen_device::update_now()
if (current_vpos > m_last_partial_scan)
{
// if the line before us was incomplete, we must do it in two pieces
- if (m_partial_scan_hpos >= 0)
+ if (m_partial_scan_hpos > 0)
{
// now finish the previous partial scanline
- clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1),
+ clip.set((std::max)(clip.left(), m_partial_scan_hpos),
clip.right(),
(std::max)(clip.top(), m_last_partial_scan),
(std::min)(clip.bottom(), m_last_partial_scan));
@@ -1309,7 +1295,7 @@ void screen_device::update_now()
// if there's something to draw, do it
if (!clip.empty())
{
- g_profiler.start(PROFILER_VIDEO);
+ auto profile = g_profiler.start(PROFILER_VIDEO);
u32 flags = 0;
screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
@@ -1333,14 +1319,13 @@ void screen_device::update_now()
}
}
- g_profiler.stop();
m_partial_updates_this_frame++;
// if we modified the bitmap, we have to commit
m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
}
- m_partial_scan_hpos = -1;
+ m_partial_scan_hpos = 0;
m_last_partial_scan++;
}
if (current_vpos > m_last_partial_scan)
@@ -1350,47 +1335,49 @@ void screen_device::update_now()
}
// now draw this partial scanline
- clip = m_visarea;
-
- clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1),
- (std::min)(clip.right(), current_hpos),
- (std::max)(clip.top(), current_vpos),
- (std::min)(clip.bottom(), current_vpos));
-
- // and if there's something to draw, do it
- if (!clip.empty())
+ if (current_hpos > 0)
{
- g_profiler.start(PROFILER_VIDEO);
+ clip = m_visarea;
- LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right()));
+ clip.set((std::max)(clip.left(), m_partial_scan_hpos),
+ (std::min)(clip.right(), current_hpos - 1),
+ (std::max)(clip.top(), current_vpos),
+ (std::min)(clip.bottom(), current_vpos));
- u32 flags = 0;
- screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
- if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
+ // and if there's something to draw, do it
+ if (!clip.empty())
{
- pre_update_scanline(current_vpos);
- switch (curbitmap.format())
+ auto profile = g_profiler.start(PROFILER_VIDEO);
+
+ LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right()));
+
+ u32 flags = 0;
+ screen_bitmap &curbitmap = m_bitmap[m_curbitmap];
+ if (m_video_attributes & VIDEO_VARIABLE_WIDTH)
{
- default:
- case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
- case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
+ pre_update_scanline(current_vpos);
+ switch (curbitmap.format())
+ {
+ default:
+ case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
+ case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break;
+ }
}
- }
- else
- {
- switch (curbitmap.format())
+ else
{
- default:
- case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
- case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
+ switch (curbitmap.format())
+ {
+ default:
+ case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break;
+ case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break;
+ }
}
- }
- m_partial_updates_this_frame++;
- g_profiler.stop();
+ m_partial_updates_this_frame++;
- // if we modified the bitmap, we have to commit
- m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
+ // if we modified the bitmap, we have to commit
+ m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED;
+ }
}
// remember where we left off
@@ -1407,7 +1394,7 @@ void screen_device::update_now()
void screen_device::reset_partial_updates()
{
m_last_partial_scan = 0;
- m_partial_scan_hpos = -1;
+ m_partial_scan_hpos = 0;
m_partial_updates_this_frame = 0;
m_scanline0_timer->adjust(time_until_pos(0));
}
@@ -1646,7 +1633,7 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap)
// signal the VBLANK period has begun
//-------------------------------------------------
-void screen_device::vblank_begin()
+TIMER_CALLBACK_MEMBER(screen_device::vblank_begin)
{
// reset the starting VBLANK time
m_vblank_start_time = machine().time();
@@ -1666,7 +1653,7 @@ void screen_device::vblank_begin()
// if no VBLANK period, call the VBLANK end callback immediately, otherwise reset the timer
if (m_vblank_period == 0)
- vblank_end();
+ vblank_end(0);
else
m_vblank_end_timer->adjust(time_until_vblank_end());
}
@@ -1677,7 +1664,7 @@ void screen_device::vblank_begin()
// signal the VBLANK period has ended
//-------------------------------------------------
-void screen_device::vblank_end()
+TIMER_CALLBACK_MEMBER(screen_device::vblank_end)
{
// call the screen specific callbacks
for (auto &item : m_callback_list)
diff --git a/src/emu/screen.h b/src/emu/screen.h
index b909c25cecc..a2d9e7f7f2e 100644
--- a/src/emu/screen.h
+++ b/src/emu/screen.h
@@ -13,6 +13,8 @@
#pragma once
+#include "rendertypes.h"
+
#include <type_traits>
#include <utility>
@@ -31,16 +33,6 @@ enum screen_type_enum
SCREEN_TYPE_SVG
};
-// texture formats
-enum texture_format
-{
- TEXFORMAT_UNDEFINED = 0, // require a format to be specified
- TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha
- TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB
- TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB
- TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence
-};
-
// screen_update callback flags
constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed
@@ -233,7 +225,7 @@ public:
screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart)
{
assert(pixclock != 0);
- m_clock = pixclock;
+ set_clock(pixclock);
m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal;
m_vblank = m_refresh / vtotal * (vtotal - (vbstart - vbend));
m_width = htotal;
@@ -246,6 +238,10 @@ public:
xtal.validate(std::string("Configuring screen ") + tag());
return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart);
}
+ screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea)
+ {
+ return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1);
+ }
void set_refresh(attoseconds_t rate) { m_refresh = rate; }
/// \brief Set refresh rate in Hertz
@@ -389,8 +385,8 @@ public:
// beam positioning and state
int vpos() const;
int hpos() const;
- DECLARE_READ_LINE_MEMBER(vblank) const { return (machine().time() < m_vblank_end_time) ? 1 : 0; }
- DECLARE_READ_LINE_MEMBER(hblank) const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; }
+ int vblank() const { return (machine().time() < m_vblank_end_time) ? 1 : 0; }
+ int hblank() const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; }
// timing
attotime time_until_pos(int vpos, int hpos = 0) const;
@@ -428,15 +424,6 @@ public:
private:
class svg_renderer;
- // timer IDs
- enum
- {
- TID_VBLANK_START,
- TID_VBLANK_END,
- TID_SCANLINE0,
- TID_SCANLINE
- };
-
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_config_complete() override;
@@ -445,13 +432,14 @@ private:
virtual void device_reset() override;
virtual void device_stop() override;
virtual void device_post_load() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// internal helpers
void set_container(render_container &container) { m_container = &container; }
void realloc_screen_bitmaps();
- void vblank_begin();
- void vblank_end();
+ TIMER_CALLBACK_MEMBER(vblank_begin);
+ TIMER_CALLBACK_MEMBER(vblank_end);
+ TIMER_CALLBACK_MEMBER(first_scanline_tick);
+ TIMER_CALLBACK_MEMBER(scanline_tick);
void finalize_burnin();
void load_effect_overlay(const char *filename);
void update_scan_bitmap_size(int y);
diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp
index 4892a5ca5d8..c6bb7161be3 100644
--- a/src/emu/softlist.cpp
+++ b/src/emu/softlist.cpp
@@ -286,8 +286,7 @@ softlist_parser::softlist_parser(
char buffer[1024];
for (bool done = false; !done; )
{
- size_t length;
- file.read(buffer, sizeof(buffer), length); // TODO: better error handling
+ auto const [err, length] = read(file, buffer, sizeof(buffer)); // TODO: better error handling
if (!length)
done = true;
if (XML_Parse(m_parser, buffer, length, done) == XML_STATUS_ERROR)
diff --git a/src/emu/softlist_dev.cpp b/src/emu/softlist_dev.cpp
index 7d25dd17013..b65f5f28300 100644
--- a/src/emu/softlist_dev.cpp
+++ b/src/emu/softlist_dev.cpp
@@ -13,6 +13,7 @@
#include "diimage.h"
#include "emuopts.h"
+#include "fileio.h"
#include "romload.h"
#include "validity.h"
@@ -49,9 +50,9 @@ image_software_list_loader image_software_list_loader::s_instance;
// false_software_list_loader::load_software
//-------------------------------------------------
-bool false_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
+std::error_condition false_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
{
- return false;
+ return image_error::UNSUPPORTED;
}
@@ -59,10 +60,10 @@ bool false_software_list_loader::load_software(device_image_interface &image, so
// rom_software_list_loader::load_software
//-------------------------------------------------
-bool rom_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
+std::error_condition rom_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
{
swlist.machine().rom_load().load_software_part_region(image.device(), swlist, swname, start_entry);
- return true;
+ return std::error_condition();
}
@@ -70,7 +71,7 @@ bool rom_software_list_loader::load_software(device_image_interface &image, soft
// image_software_list_loader::load_software
//-------------------------------------------------
-bool image_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
+std::error_condition image_software_list_loader::load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const
{
return image.load_software(swlist, swname, start_entry);
}
@@ -249,7 +250,7 @@ void software_list_device::display_matches(const machine_config &config, const c
// from an intermediate point
//-------------------------------------------------
-const software_info *software_list_device::find(const std::string &look_for)
+const software_info *software_list_device::find(std::string_view look_for)
{
// empty search returns nothing
if (look_for.empty())
@@ -264,9 +265,9 @@ const software_info *software_list_device::find(const std::string &look_for)
info_list.end(),
[&look_for, iswild] (const software_info &info)
{
- const char *shortname = info.shortname().c_str();
- return (iswild && core_strwildcmp(look_for.c_str(), shortname) == 0)
- || core_stricmp(look_for.c_str(), shortname) == 0;
+ std::string_view shortname = info.shortname();
+ return (iswild && core_strwildcmp(look_for, shortname) == 0)
+ || util::streqlower(look_for, shortname);
});
return iter != info_list.end() ? &*iter : nullptr;
@@ -453,6 +454,9 @@ void software_list_device::internal_validity_check(validity_checker &valid)
if (m_shortname.length() > NAME_LEN_LIST)
osd_printf_error("%s: %s software list name must be %d characters or less\n", m_filename, m_shortname, NAME_LEN_LIST);
+
+ if (std::find_if_not(m_shortname.begin(), m_shortname.end(), valid_name_char) != m_shortname.end())
+ osd_printf_error("%s: %s software list name contains invalid characters\n", m_filename, m_shortname);
}
// now check the software items
@@ -572,6 +576,8 @@ void software_list_device::internal_validity_check(validity_checker &valid)
current_length = ROMREGION_GETLENGTH(romp);
if (!data_area_map.emplace(romp->name(), current_length).second)
osd_printf_error("%s: %s part %s data area has duplicate name '%s'\n", m_filename, shortname, part.name(), romp->name());
+ if (current_length == 0)
+ osd_printf_error("%s: %s part %s data area '%s' has zero length\n", m_filename, shortname, part.name(), romp->name());
}
else if (ROMENTRY_ISFILE(romp)) // if this is a file, make sure it is properly formatted
{
diff --git a/src/emu/softlist_dev.h b/src/emu/softlist_dev.h
index e0e912a67f1..772bb970c99 100644
--- a/src/emu/softlist_dev.h
+++ b/src/emu/softlist_dev.h
@@ -43,7 +43,7 @@ enum software_compatibility
class software_list_loader
{
public:
- virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const = 0;
+ virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const = 0;
};
@@ -52,7 +52,7 @@ public:
class false_software_list_loader : public software_list_loader
{
public:
- virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
+ virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
static const software_list_loader &instance() { return s_instance; }
private:
@@ -65,7 +65,7 @@ private:
class rom_software_list_loader : public software_list_loader
{
public:
- virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
+ virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
static const software_list_loader &instance() { return s_instance; }
private:
@@ -78,7 +78,7 @@ private:
class image_software_list_loader : public software_list_loader
{
public:
- virtual bool load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
+ virtual std::error_condition load_software(device_image_interface &image, software_list_device &swlist, std::string_view swname, const rom_entry *start_entry) const override;
static const software_list_loader &instance() { return s_instance; }
private:
@@ -121,7 +121,7 @@ public:
const std::list<software_info> &get_info() { if (!m_parsed) parse(); return m_infolist; }
// operations
- const software_info *find(const std::string &look_for);
+ const software_info *find(std::string_view look_for);
void find_approx_matches(std::string_view name, int matches, const software_info **list, const char *interface);
void release();
software_compatibility is_compatible(const software_part &part) const;
diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp
index 56b7d7ef071..c9626855197 100644
--- a/src/emu/sound.cpp
+++ b/src/emu/sound.cpp
@@ -9,32 +9,30 @@
***************************************************************************/
#include "emu.h"
-#include "speaker.h"
-#include "emuopts.h"
-#include "osdepend.h"
+
#include "config.h"
+#include "emuopts.h"
+#include "main.h"
+#include "speaker.h"
+
#include "wavwrite.h"
+#include "xmlfile.h"
+#include "osdepend.h"
//**************************************************************************
// DEBUGGING
//**************************************************************************
-#define VERBOSE (0)
+//#define VERBOSE 1
+#define LOG_OUTPUT_FUNC osd_printf_debug
-#define VPRINTF(x) do { if (VERBOSE) osd_printf_debug x; } while (0)
+#include "logmacro.h"
#define LOG_OUTPUT_WAV (0)
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-
-
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -42,7 +40,6 @@
const attotime sound_manager::STREAMS_UPDATE_ATTOTIME = attotime::from_hz(STREAMS_UPDATE_FREQUENCY);
-
//**************************************************************************
// STREAM BUFFER
//**************************************************************************
@@ -560,6 +557,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
m_synchronous((flags & STREAM_SYNCHRONOUS) != 0),
m_resampling_disabled((flags & STREAM_DISABLE_INPUT_RESAMPLING) != 0),
m_sync_timer(nullptr),
+ m_last_update_end_time(attotime::zero),
m_input(inputs),
m_input_view(inputs),
m_empty_buffer(100),
@@ -578,8 +576,10 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
// create a unique tag for saving
std::string state_tag = string_format("%d", m_device.machine().sound().unique_id());
auto &save = m_device.machine().save();
- save.save_item(&m_device, "stream.sample_rate", state_tag.c_str(), 0, NAME(m_sample_rate));
+ save.save_item(&m_device, "stream.sound_stream", state_tag.c_str(), 0, NAME(m_sample_rate));
+ save.save_item(&m_device, "stream.sound_stream", state_tag.c_str(), 0, NAME(m_last_update_end_time));
save.register_postload(save_prepost_delegate(FUNC(sound_stream::postload), this));
+ save.register_presave(save_prepost_delegate(FUNC(sound_stream::presave), this));
// initialize all inputs
for (unsigned int inputnum = 0; inputnum < m_input.size(); inputnum++)
@@ -602,7 +602,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
// create an update timer for synchronous streams
if (synchronous())
- m_sync_timer = m_device.machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sound_stream::sync_update), this));
+ m_sync_timer = m_device.timer_alloc(FUNC(sound_stream::sync_update), this);
// force an update to the sample rates
sample_rate_changed();
@@ -648,8 +648,8 @@ void sound_stream::set_sample_rate(u32 new_rate)
void sound_stream::set_input(int index, sound_stream *input_stream, int output_index, float gain)
{
- VPRINTF(("stream_set_input(%p, '%s', %d, %p, %d, %f)\n", (void *)this, m_device.tag(),
- index, (void *)input_stream, output_index, (double) gain));
+ LOG("stream_set_input(%p, '%s', %d, %p, %d, %f)\n", (void *)this, m_device.tag(),
+ index, (void *)input_stream, output_index, gain);
// make sure it's a valid input
if (index >= m_input.size())
@@ -704,7 +704,7 @@ read_stream_view sound_stream::update_view(attotime start, attotime end, u32 out
if (start > end)
start = end;
- g_profiler.start(PROFILER_SOUND);
+ auto profile = g_profiler.start(PROFILER_SOUND);
// reposition our start to coincide with the current buffer end
attotime update_start = m_output[outputnum].end_time();
@@ -752,7 +752,6 @@ read_stream_view sound_stream::update_view(attotime start, attotime end, u32 out
#endif
}
}
- g_profiler.stop();
// return the requested view
return read_stream_view(m_output_view[outputnum], start);
@@ -857,14 +856,24 @@ void sound_stream::sample_rate_changed()
void sound_stream::postload()
{
- // set the end time of all of our streams to now
+ // set the end time of all of our streams to the value saved in m_last_update_end_time
for (auto &output : m_output)
- output.set_end_time(m_device.machine().time());
+ output.set_end_time(m_last_update_end_time);
// recompute the sample rate information
sample_rate_changed();
}
+//-------------------------------------------------
+// presave - save/restore callback
+//-------------------------------------------------
+
+void sound_stream::presave()
+{
+ // save the stream end time
+ m_last_update_end_time = m_output[0].end_time();
+}
+
//-------------------------------------------------
// reprime_sync_timer - set up the next sync
@@ -885,7 +894,7 @@ void sound_stream::reprime_sync_timer()
// synchronous stream
//-------------------------------------------------
-void sound_stream::sync_update(void *, s32)
+void sound_stream::sync_update(s32)
{
update();
reprime_sync_timer();
@@ -1076,18 +1085,10 @@ sound_manager::sound_manager(running_machine &machine) :
m_wavfile(),
m_first_reset(true)
{
- // get filename for WAV file or AVI file if specified
- const char *wavfile = machine.options().wav_write();
- const char *avifile = machine.options().avi_write();
-
- // handle -nosound and lower sample rate if not recording WAV or AVI
- if (m_nosound_mode && wavfile[0] == 0 && avifile[0] == 0)
- machine.m_sample_rate = 11025;
-
// count the mixers
#if VERBOSE
mixer_interface_enumerator iter(machine.root_device());
- VPRINTF(("total mixers = %d\n", iter.count()));
+ LOG("total mixers = %d\n", iter.count());
#endif
// register callbacks
@@ -1366,16 +1367,44 @@ void sound_manager::config_load(config_type cfg_type, config_level cfg_level, ut
if ((cfg_type != config_type::SYSTEM) || !parentnode)
return;
+ // master volume attenuation
+ if (util::xml::data_node const *node = parentnode->get_child("attenuation"))
+ {
+ // treat source INI files or more specific as higher priority than CFG
+ // FIXME: leaky abstraction - this depends on a front-end implementation detail
+ if ((OPTION_PRIORITY_NORMAL + 5) > machine().options().get_entry(OPTION_VOLUME)->priority())
+ set_attenuation(std::clamp(int(node->get_attribute_int("value", 0)), -32, 0));
+ }
+
// iterate over channel nodes
- for (util::xml::data_node const *channelnode = parentnode->get_child("channel"); channelnode != nullptr; channelnode = channelnode->get_next_sibling("channel"))
+ for (util::xml::data_node const *node = parentnode->get_child("channel"); node != nullptr; node = node->get_next_sibling("channel"))
{
mixer_input info;
- if (indexed_mixer_input(channelnode->get_attribute_int("index", -1), info))
+ if (indexed_mixer_input(node->get_attribute_int("index", -1), info))
+ {
+ // note that this doesn't disallow out-of-range values
+ float value = node->get_attribute_float("value", std::nanf(""));
+
+ if (!std::isnan(value))
+ info.stream->input(info.inputnum).set_user_gain(value);
+ }
+ }
+
+ // iterate over speaker panning nodes
+ for (util::xml::data_node const *node = parentnode->get_child("panning"); node != nullptr; node = node->get_next_sibling("panning"))
+ {
+ char const *const tag = node->get_attribute_string("tag", nullptr);
+ if (tag != nullptr)
{
- float defvol = channelnode->get_attribute_float("defvol", 1.0f);
- float newvol = channelnode->get_attribute_float("newvol", -1000.0f);
- if (newvol != -1000.0f)
- info.stream->input(info.inputnum).set_user_gain(newvol / defvol);
+ for (speaker_device &speaker : speaker_device_enumerator(machine().root_device()))
+ {
+ if (!strcmp(tag, speaker.tag()))
+ {
+ float value = node->get_attribute_float("value", speaker.defpan());
+ speaker.set_pan(value);
+ break;
+ }
+ }
}
}
}
@@ -1392,21 +1421,43 @@ void sound_manager::config_save(config_type cfg_type, util::xml::data_node *pare
if (cfg_type != config_type::SYSTEM)
return;
- // iterate over mixer channels
+ // master volume attenuation
+ if (m_attenuation != machine().options().volume())
+ {
+ if (util::xml::data_node *const node = parentnode->add_child("attenuation", nullptr))
+ node->set_attribute_int("value", m_attenuation);
+ }
+
+ // iterate over mixer channels for per-channel volume
for (int mixernum = 0; ; mixernum++)
{
mixer_input info;
if (!indexed_mixer_input(mixernum, info))
break;
- float const newvol = info.stream->input(info.inputnum).user_gain();
- if (newvol != 1.0f)
+ float const value = info.stream->input(info.inputnum).user_gain();
+ if (value != 1.0f)
{
- util::xml::data_node *const channelnode = parentnode->add_child("channel", nullptr);
- if (channelnode)
+ util::xml::data_node *const node = parentnode->add_child("channel", nullptr);
+ if (node)
{
- channelnode->set_attribute_int("index", mixernum);
- channelnode->set_attribute_float("newvol", newvol);
+ node->set_attribute_int("index", mixernum);
+ node->set_attribute_float("value", value);
+ }
+ }
+ }
+
+ // iterate over speakers for panning
+ for (speaker_device &speaker : speaker_device_enumerator(machine().root_device()))
+ {
+ float const value = speaker.pan();
+ if (value != speaker.defpan())
+ {
+ util::xml::data_node *const node = parentnode->add_child("panning", nullptr);
+ if (node)
+ {
+ node->set_attribute("tag", speaker.tag());
+ node->set_attribute_float("value", value);
}
}
}
@@ -1457,11 +1508,11 @@ stream_buffer::sample_t sound_manager::adjust_toward_compressor_scale(stream_buf
// and send it to the OSD layer
//-------------------------------------------------
-void sound_manager::update(void *ptr, int param)
+void sound_manager::update(s32 param)
{
- VPRINTF(("sound_update\n"));
+ LOG("sound_update\n");
- g_profiler.start(PROFILER_SOUND);
+ auto profile = g_profiler.start(PROFILER_SOUND);
// determine the duration of this update
attotime update_period = machine().time() - m_last_update;
@@ -1597,6 +1648,4 @@ void sound_manager::update(void *ptr, int param)
// notify that new samples have been generated
emulator_info::sound_hook();
-
- g_profiler.stop();
}
diff --git a/src/emu/sound.h b/src/emu/sound.h
index c1e66808ae6..15f6a5743a2 100644
--- a/src/emu/sound.h
+++ b/src/emu/sound.h
@@ -373,6 +373,7 @@ public:
// safely write a sample to the buffer
void put(s32 start, sample_t sample)
{
+ sound_assert(u32(start) < samples());
m_buffer->put(index_to_buffer_index(start), sample);
}
@@ -399,6 +400,7 @@ public:
// safely add a sample to the buffer
void add(s32 start, sample_t sample)
{
+ sound_assert(u32(start) < samples());
u32 index = index_to_buffer_index(start);
m_buffer->put(index, m_buffer->get(index) + sample);
}
@@ -458,7 +460,6 @@ private:
// given a stream starting offset, return the buffer index
u32 index_to_buffer_index(s32 start) const
{
- sound_assert(u32(start) < samples());
u32 index = start + m_start;
if (index >= m_buffer->size())
index -= m_buffer->size();
@@ -669,11 +670,14 @@ private:
// handle updates after a save state load
void postload();
+ // handle updates before a save state load
+ void presave();
+
// re-print the synchronization timer
void reprime_sync_timer();
// timer callback for synchronous streams
- void sync_update(void *, s32);
+ void sync_update(s32);
// return a view of 0 data covering the given time period
read_stream_view empty_view(attotime start, attotime end);
@@ -692,6 +696,8 @@ private:
bool m_resampling_disabled; // is resampling of input streams disabled?
emu_timer *m_sync_timer; // update timer for synchronous streams
+ attotime m_last_update_end_time; // last end_time() in update
+
// input information
std::vector<sound_stream_input> m_input; // list of streams we directly depend upon
std::vector<read_stream_view> m_input_view; // array of output views for passing to the callback
@@ -816,7 +822,7 @@ private:
stream_buffer::sample_t adjust_toward_compressor_scale(stream_buffer::sample_t curscale, stream_buffer::sample_t prevsample, stream_buffer::sample_t rawsample);
// periodic sound update, called STREAMS_UPDATE_FREQUENCY per second
- void update(void *ptr = nullptr, s32 param = 0);
+ void update(s32 param = 0);
// internal state
running_machine &m_machine; // reference to the running machine
diff --git a/src/emu/speaker.cpp b/src/emu/speaker.cpp
index 3cbb14355a4..33b1e8d329a 100644
--- a/src/emu/speaker.cpp
+++ b/src/emu/speaker.cpp
@@ -37,6 +37,8 @@ speaker_device::speaker_device(const machine_config &mconfig, const char *tag, d
, m_x(0.0)
, m_y(0.0)
, m_z(0.0)
+ , m_pan(0.0)
+ , m_defpan(0.0)
, m_current_max(0)
, m_samples_this_bucket(0)
{
@@ -53,6 +55,34 @@ speaker_device::~speaker_device()
//-------------------------------------------------
+// set_position - set speaker position
+//-------------------------------------------------
+
+speaker_device &speaker_device::set_position(double x, double y, double z)
+{
+ // as mentioned in the header file, y and z params currently have no effect
+ m_x = x;
+ m_y = y;
+ m_z = z;
+
+ // hard pan to left
+ if (m_x < 0.0)
+ set_pan(-1.0f);
+
+ // hard pan to right
+ else if (m_x > 0.0)
+ set_pan(1.0f);
+
+ // center (mono)
+ else
+ set_pan(0.0f);
+
+ m_defpan = m_pan;
+ return *this;
+}
+
+
+//-------------------------------------------------
// mix - mix in samples from the speaker's stream
//-------------------------------------------------
@@ -89,24 +119,29 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample
// mix if sound is enabled
if (!suppress)
{
- // if the speaker is centered, send to both left and right
- if (m_x == 0)
+ // if the speaker is hard panned to the left, send only to the left
+ if (m_pan == -1.0f)
for (int sample = 0; sample < expected_samples; sample++)
- {
- stream_buffer::sample_t cursample = view.get(sample);
- leftmix[sample] += cursample;
- rightmix[sample] += cursample;
- }
+ leftmix[sample] += view.get(sample);
- // if the speaker is to the left, send only to the left
- else if (m_x < 0)
+ // if the speaker is hard panned to the right, send only to the right
+ else if (m_pan == 1.0f)
for (int sample = 0; sample < expected_samples; sample++)
- leftmix[sample] += view.get(sample);
+ rightmix[sample] += view.get(sample);
- // if the speaker is to the right, send only to the right
+ // otherwise, send to both
else
+ {
+ const float leftpan = (m_pan <= 0.0f) ? 1.0f : 1.0f - m_pan;
+ const float rightpan = (m_pan >= 0.0f) ? 1.0f : 1.0f + m_pan;
+
for (int sample = 0; sample < expected_samples; sample++)
- rightmix[sample] += view.get(sample);
+ {
+ stream_buffer::sample_t cursample = view.get(sample);
+ leftmix[sample] += cursample * leftpan;
+ rightmix[sample] += cursample * rightpan;
+ }
+ }
}
}
@@ -117,7 +152,6 @@ void speaker_device::mix(stream_buffer::sample_t *leftmix, stream_buffer::sample
void speaker_device::device_start()
{
- // dummy save to make device.c happy
}
@@ -187,4 +221,3 @@ void speaker_device::device_stop()
}
}
}
-
diff --git a/src/emu/speaker.h b/src/emu/speaker.h
index 54aa00603c9..3cb0794d998 100644
--- a/src/emu/speaker.h
+++ b/src/emu/speaker.h
@@ -53,8 +53,8 @@ public:
speaker_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual ~speaker_device();
- // inline configuration helpers
- speaker_device &set_position(double x, double y, double z) { m_x = x; m_y = y; m_z = z; return *this; }
+ // configuration helpers
+ speaker_device &set_position(double x, double y, double z);
speaker_device &front_center() { set_position( 0.0, 0.0, 1.0); return *this; }
speaker_device &front_left() { set_position(-0.2, 0.0, 1.0); return *this; }
speaker_device &front_floor() { set_position( 0.0, -0.5, 1.0); return *this; }
@@ -71,15 +71,22 @@ public:
// internally for use by the sound system
void mix(stream_buffer::sample_t *leftmix, stream_buffer::sample_t *rightmix, attotime start, attotime end, int expected_samples, bool suppress);
+ // user panning configuration
+ void set_pan(float pan) { m_pan = std::clamp(pan, -1.0f, 1.0f); }
+ float pan() { return m_pan; }
+ float defpan() { return m_defpan; }
+
protected:
// device-level overrides
virtual void device_start() override ATTR_COLD;
virtual void device_stop() override ATTR_COLD;
- // inline configuration state
+ // configuration state
double m_x;
double m_y;
double m_z;
+ float m_pan;
+ float m_defpan;
// internal state
static constexpr int BUCKETS_PER_SECOND = 10;
diff --git a/src/emu/tilemap.cpp b/src/emu/tilemap.cpp
index 5757f35341f..1aa18eef168 100644
--- a/src/emu/tilemap.cpp
+++ b/src/emu/tilemap.cpp
@@ -772,7 +772,7 @@ void tilemap_t::pixmap_update()
if (m_all_tiles_clean)
return;
-g_profiler.start(PROFILER_TILEMAP_DRAW);
+ auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW);
// flush the dirty state to all tiles as appropriate
realize_all_dirty_tiles();
@@ -786,8 +786,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW);
// mark it all clean
m_all_tiles_clean = true;
-
-g_profiler.stop();
}
@@ -797,7 +795,7 @@ g_profiler.stop();
void tilemap_t::tile_update(logical_index logindex, u32 col, u32 row)
{
-g_profiler.start(PROFILER_TILEMAP_UPDATE);
+ auto profile = g_profiler.start(PROFILER_TILEMAP_UPDATE);
// call the get info callback for the associated memory index
tilemap_memory_index memindex = m_logical_to_memory[logindex];
@@ -822,8 +820,6 @@ g_profiler.start(PROFILER_TILEMAP_UPDATE);
m_gfx_used |= 1 << m_tileinfo.gfxnum;
m_gfx_dirtyseq[m_tileinfo.gfxnum] = m_tileinfo.decoder->gfx(m_tileinfo.gfxnum)->dirtyseq();
}
-
-g_profiler.stop();
}
@@ -997,7 +993,8 @@ void tilemap_t::draw_common(screen_device &screen, _BitmapClass &dest, const rec
if (!m_enable)
return;
-g_profiler.start(PROFILER_TILEMAP_DRAW);
+ auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW);
+
// configure the blit parameters based on the input parameters
blit_parameters blit;
configure_blit_parameters(blit, screen.priority(), cliprect, flags, priority, priority_mask);
@@ -1095,7 +1092,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW);
}
}
}
-g_profiler.stop();
}
void tilemap_t::draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, u32 flags, u8 priority, u8 priority_mask)
@@ -1134,7 +1130,8 @@ void tilemap_t::draw_roz_common(screen_device &screen, _BitmapClass &dest, const
return;
}
-g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ);
+ auto profile = g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ);
+
// configure the blit parameters
blit_parameters blit;
configure_blit_parameters(blit, screen.priority(), cliprect, flags, priority, priority_mask);
@@ -1146,7 +1143,6 @@ g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ);
// then do the roz copy
draw_roz_core(screen, dest, blit, startx, starty, incxx, incxy, incyx, incyy, wraparound);
-g_profiler.stop();
}
void tilemap_t::draw_roz(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect,
@@ -1182,7 +1178,16 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
// look up priority and destination base addresses for y1
bitmap_ind8 &priority_bitmap = *blit.priority;
- u8 *priority_baseaddr = &priority_bitmap.pix(y1, xpos);
+ u8 *priority_baseaddr = nullptr;
+ int prio_rowpixels = 0;
+ if (priority_bitmap.valid())
+ {
+ prio_rowpixels = priority_bitmap.rowpixels();
+ priority_baseaddr = &priority_bitmap.pix(y1, xpos);
+ }
+ else
+ assert((blit.tilemap_priority_code & 0xffff) == 0xff00);
+
typename _BitmapClass::pixel_t *dest_baseaddr = nullptr;
int dest_rowpixels = 0;
if (dest.valid())
@@ -1260,7 +1265,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
{
const u16 *source0 = source_baseaddr + x_start;
typename _BitmapClass::pixel_t *dest0 = dest_baseaddr + x_start;
- u8 *pmap0 = priority_baseaddr + x_start;
+ u8 *pmap0 = priority_baseaddr ? (priority_baseaddr + x_start) : nullptr;
// if we were opaque, use the opaque renderer
if (prev_trans == WHOLLY_OPAQUE)
@@ -1278,7 +1283,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
dest0 += dest_rowpixels;
source0 += m_pixmap.rowpixels();
- pmap0 += priority_bitmap.rowpixels();
+ pmap0 += prio_rowpixels;
}
}
@@ -1300,7 +1305,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
dest0 += dest_rowpixels;
source0 += m_pixmap.rowpixels();
mask0 += m_flagsmap.rowpixels();
- pmap0 += priority_bitmap.rowpixels();
+ pmap0 += prio_rowpixels;
}
}
}
@@ -1315,7 +1320,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
break;
// advance to the next row on all our bitmaps
- priority_baseaddr += priority_bitmap.rowpixels() * (nexty - y);
+ priority_baseaddr += prio_rowpixels * (nexty - y);
source_baseaddr += m_pixmap.rowpixels() * (nexty - y);
mask_baseaddr += m_flagsmap.rowpixels() * (nexty - y);
dest_baseaddr += dest_rowpixels * (nexty - y);
@@ -1559,10 +1564,14 @@ void tilemap_t::get_info_debug(u32 col, u32 row, u8 &gfxnum, u32 &code, u32 &col
// get the GFX number and code
gfxnum = m_tileinfo.gfxnum;
code = m_tileinfo.code;
+ color = m_tileinfo.palette_base;
- // work back from the palette base to get the color
- const gfx_element &gfx = *m_tileinfo.decoder->gfx(gfxnum);
- color = (m_tileinfo.palette_base - gfx.colorbase()) / gfx.granularity();
+ if (gfxnum != 0xff)
+ {
+ // work back from the palette base to get the color
+ const gfx_element &gfx = *m_tileinfo.decoder->gfx(gfxnum);
+ color = (color - gfx.colorbase()) / gfx.granularity();
+ }
}
@@ -1604,8 +1613,7 @@ tilemap_manager::~tilemap_manager()
//-------------------------------------------------
-// set_flip_all - set a global flip for all the
-// tilemaps
+// create - allocate a tilemap
//-------------------------------------------------
tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_mapper_delegate mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated)
diff --git a/src/emu/ui/uimain.h b/src/emu/ui/uimain.h
index bf10957d743..e45c71f9468 100644
--- a/src/emu/ui/uimain.h
+++ b/src/emu/ui/uimain.h
@@ -13,6 +13,8 @@
#pragma once
+#include <functional>
+
/***************************************************************************
TYPE DEFINITIONS
@@ -35,6 +37,8 @@ public:
virtual void menu_reset() { }
+ virtual bool set_ui_event_handler(std::function<bool ()> &&handler) { return false; }
+
template <typename Format, typename... Params> void popup_time(int seconds, Format &&fmt, Params &&... args);
protected:
diff --git a/src/emu/uiinput.cpp b/src/emu/uiinput.cpp
index d1398591687..12ba8a08bb0 100644
--- a/src/emu/uiinput.cpp
+++ b/src/emu/uiinput.cpp
@@ -36,19 +36,11 @@ enum
ui_input_manager::ui_input_manager(running_machine &machine)
: m_machine(machine)
, m_presses_enabled(true)
- , m_current_mouse_target(nullptr)
- , m_current_mouse_x(-1)
- , m_current_mouse_y(-1)
- , m_current_mouse_down(false)
- , m_current_mouse_field(nullptr)
, m_events_start(0)
, m_events_end(0)
{
std::fill(std::begin(m_next_repeat), std::end(m_next_repeat), 0);
std::fill(std::begin(m_seqpressed), std::end(m_seqpressed), 0);
-
- // add a frame callback to poll inputs
- machine.add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&ui_input_manager::frame_update, this));
}
@@ -58,12 +50,12 @@ ui_input_manager::ui_input_manager(running_machine &machine)
***************************************************************************/
/*-------------------------------------------------
- frame_update - looks through pressed
- input as per events pushed our way and posts
+ check_ui_inputs - looks through pressed input
+ as per events pushed our way and posts
corresponding IPT_UI_* events
-------------------------------------------------*/
-void ui_input_manager::frame_update()
+void ui_input_manager::check_ui_inputs()
{
// update the state of all the UI keys
for (ioport_type code = ioport_type(IPT_UI_FIRST + 1); code < IPT_UI_LAST; ++code)
@@ -80,22 +72,6 @@ void ui_input_manager::frame_update()
m_seqpressed[code] = false;
}
}
-
- // perform mouse hit testing
- ioport_field *mouse_field = m_current_mouse_down ? find_mouse_field() : nullptr;
- if (m_current_mouse_field != mouse_field)
- {
- // clear the old field if there was one
- if (m_current_mouse_field != nullptr)
- m_current_mouse_field->set_value(0);
-
- // set the new field if it exists and isn't already being pressed
- if (mouse_field != nullptr && !mouse_field->digital_value())
- mouse_field->set_value(1);
-
- // update internal state
- m_current_mouse_field = mouse_field;
- }
}
@@ -106,37 +82,6 @@ void ui_input_manager::frame_update()
bool ui_input_manager::push_event(ui_event evt)
{
- // some pre-processing (this is an icky place to do this stuff!)
- switch (evt.event_type)
- {
- case ui_event::type::MOUSE_MOVE:
- m_current_mouse_target = evt.target;
- m_current_mouse_x = evt.mouse_x;
- m_current_mouse_y = evt.mouse_y;
- break;
-
- case ui_event::type::MOUSE_LEAVE:
- if (m_current_mouse_target == evt.target)
- {
- m_current_mouse_target = nullptr;
- m_current_mouse_x = -1;
- m_current_mouse_y = -1;
- }
- break;
-
- case ui_event::type::MOUSE_DOWN:
- m_current_mouse_down = true;
- break;
-
- case ui_event::type::MOUSE_UP:
- m_current_mouse_down = false;
- break;
-
- default:
- /* do nothing */
- break;
- }
-
// is the queue filled up?
if ((m_events_end + 1) % std::size(m_events) == m_events_start)
return false;
@@ -186,64 +131,12 @@ void ui_input_manager::reset()
}
-/*-------------------------------------------------
- find_mouse - retrieves the current
- location of the mouse
--------------------------------------------------*/
-
-render_target *ui_input_manager::find_mouse(s32 *x, s32 *y, bool *button) const
-{
- if (x != nullptr)
- *x = m_current_mouse_x;
- if (y != nullptr)
- *y = m_current_mouse_y;
- if (button != nullptr)
- *button = m_current_mouse_down;
- return m_current_mouse_target;
-}
-
-
-/*-------------------------------------------------
- find_mouse_field - retrieves the input field
- the mouse is currently pointing at
--------------------------------------------------*/
-
-ioport_field *ui_input_manager::find_mouse_field() const
-{
- // map the point and determine what was hit
- if (m_current_mouse_target != nullptr)
- {
- ioport_port *port = nullptr;
- ioport_value mask;
- float x, y;
- if (m_current_mouse_target->map_point_input(m_current_mouse_x, m_current_mouse_y, port, mask, x, y))
- {
- if (port != nullptr)
- return port->field(mask);
- }
- }
- return nullptr;
-}
-
-
/***************************************************************************
USER INTERFACE SEQUENCE READING
***************************************************************************/
/*-------------------------------------------------
- pressed - return true if a key down
- for the given user interface sequence is
- detected
--------------------------------------------------*/
-
-bool ui_input_manager::pressed(int code)
-{
- return pressed_repeat(code, 0);
-}
-
-
-/*-------------------------------------------------
pressed_repeat - return true if a key
down for the given user interface sequence is
detected, or if autorepeat at the given speed
@@ -254,10 +147,10 @@ bool ui_input_manager::pressed_repeat(int code, int speed)
{
bool pressed;
-g_profiler.start(PROFILER_INPUT);
+ auto profile = g_profiler.start(PROFILER_INPUT);
/* get the status of this key (assumed to be only in the defaults) */
- assert(code >= IPT_UI_CONFIGURE && code <= IPT_OSD_16);
+ assert(code > IPT_UI_FIRST && code < IPT_UI_LAST);
pressed = (m_seqpressed[code] == SEQ_PRESSED_TRUE);
/* if down, handle it specially */
@@ -272,7 +165,7 @@ g_profiler.start(PROFILER_INPUT);
/* if this is an autorepeat case, set a 1x delay and leave pressed = 1 */
else if (speed > 0 && (osd_ticks() + tps - m_next_repeat[code]) >= tps)
{
- // In the autorepeatcase, we need to double check the key is still pressed
+ // In the autorepeat case, we need to double-check the key is still pressed
// as there can be a delay between the key polling and our processing of the event
m_seqpressed[code] = machine().ioport().type_pressed(ioport_type(code));
pressed = (m_seqpressed[code] == SEQ_PRESSED_TRUE);
@@ -289,8 +182,6 @@ g_profiler.start(PROFILER_INPUT);
else
m_next_repeat[code] = 0;
-g_profiler.stop();
-
return pressed;
}
@@ -321,105 +212,84 @@ void ui_input_manager::push_window_defocus_event(render_target *target)
}
/*-------------------------------------------------
- push_mouse_move_event - pushes a mouse
- move event to the specified render_target
--------------------------------------------------*/
-
-void ui_input_manager::push_mouse_move_event(render_target *target, s32 x, s32 y)
-{
- ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_MOVE;
- event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
- push_event(event);
-}
-
-/*-------------------------------------------------
- push_mouse_leave_event - pushes a
- mouse leave event to the specified render_target
--------------------------------------------------*/
-
-void ui_input_manager::push_mouse_leave_event(render_target *target)
-{
- ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_LEAVE;
- event.target = target;
- push_event(event);
-}
-
-/*-------------------------------------------------
- push_mouse_down_event - pushes a mouse
- down event to the specified render_target
--------------------------------------------------*/
-
-void ui_input_manager::push_mouse_down_event(render_target *target, s32 x, s32 y)
-{
- ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_DOWN;
- event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
- push_event(event);
-}
-
-/*-------------------------------------------------
- push_mouse_down_event - pushes a mouse
- down event to the specified render_target
--------------------------------------------------*/
-
-void ui_input_manager::push_mouse_up_event(render_target *target, s32 x, s32 y)
-{
- ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_UP;
- event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
- push_event(event);
-}
-
-/*-------------------------------------------------
-push_mouse_down_event - pushes a mouse
-down event to the specified render_target
+ push_pointer_update - pushes a pointer update
+ event to the specified render_target
-------------------------------------------------*/
-void ui_input_manager::push_mouse_rdown_event(render_target *target, s32 x, s32 y)
+void ui_input_manager::push_pointer_update(
+ render_target *target,
+ pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 buttons,
+ u32 pressed,
+ u32 released,
+ s16 clicks)
{
ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_RDOWN;
+ event.event_type = ui_event::type::POINTER_UPDATE;
event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
+ event.pointer_type = type;
+ event.pointer_id = ptrid;
+ event.pointer_device = device;
+ event.pointer_x = x;
+ event.pointer_y = y;
+ event.pointer_buttons = buttons;
+ event.pointer_pressed = pressed;
+ event.pointer_released = released;
+ event.pointer_clicks = clicks;
push_event(event);
}
-/*-------------------------------------------------
-push_mouse_down_event - pushes a mouse
-down event to the specified render_target
--------------------------------------------------*/
-
-void ui_input_manager::push_mouse_rup_event(render_target *target, s32 x, s32 y)
+void ui_input_manager::push_pointer_leave(
+ render_target *target,
+ pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 released,
+ s16 clicks)
{
ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_RUP;
+ event.event_type = ui_event::type::POINTER_LEAVE;
event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
+ event.pointer_type = type;
+ event.pointer_id = ptrid;
+ event.pointer_device = device;
+ event.pointer_x = x;
+ event.pointer_y = y;
+ event.pointer_buttons = 0U;
+ event.pointer_pressed = 0U;
+ event.pointer_released = released;
+ event.pointer_clicks = clicks;
push_event(event);
}
-/*-------------------------------------------------
- push_mouse_double_click_event - pushes
- a mouse double-click event to the specified
- render_target
--------------------------------------------------*/
-void ui_input_manager::push_mouse_double_click_event(render_target *target, s32 x, s32 y)
+void ui_input_manager::push_pointer_abort(
+ render_target *target,
+ pointer type,
+ u16 ptrid,
+ u16 device,
+ s32 x,
+ s32 y,
+ u32 released,
+ s16 clicks)
{
ui_event event = { ui_event::type::NONE };
- event.event_type = ui_event::type::MOUSE_DOUBLE_CLICK;
+ event.event_type = ui_event::type::POINTER_ABORT;
event.target = target;
- event.mouse_x = x;
- event.mouse_y = y;
+ event.pointer_type = type;
+ event.pointer_id = ptrid;
+ event.pointer_device = device;
+ event.pointer_x = x;
+ event.pointer_y = y;
+ event.pointer_buttons = 0U;
+ event.pointer_pressed = 0U;
+ event.pointer_released = released;
+ event.pointer_clicks = clicks;
push_event(event);
}
@@ -441,7 +311,7 @@ void ui_input_manager::push_char_event(render_target *target, char32_t ch)
wheel event to the specified render_target
-------------------------------------------------*/
-void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int ucNumLines)
+void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int lines)
{
ui_event event = { ui_event::type::NONE };
event.event_type = ui_event::type::MOUSE_WHEEL;
@@ -449,7 +319,7 @@ void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32
event.mouse_x = x;
event.mouse_y = y;
event.zdelta = delta;
- event.num_lines = ucNumLines;
+ event.num_lines = lines;
push_event(event);
}
diff --git a/src/emu/uiinput.h b/src/emu/uiinput.h
index 3fc89d7a4ff..54170bad7ec 100644
--- a/src/emu/uiinput.h
+++ b/src/emu/uiinput.h
@@ -13,6 +13,8 @@
#pragma once
+#include "interface/uievents.h"
+
/***************************************************************************
TYPE DEFINITIONS
@@ -25,17 +27,15 @@ struct ui_event
NONE,
WINDOW_FOCUS,
WINDOW_DEFOCUS,
- MOUSE_MOVE,
- MOUSE_LEAVE,
- MOUSE_DOWN,
- MOUSE_UP,
- MOUSE_RDOWN,
- MOUSE_RUP,
- MOUSE_DOUBLE_CLICK,
MOUSE_WHEEL,
+ POINTER_UPDATE,
+ POINTER_LEAVE,
+ POINTER_ABORT,
IME_CHAR
};
+ using pointer = osd::ui_event_handler::pointer;
+
type event_type;
render_target * target;
s32 mouse_x;
@@ -44,17 +44,27 @@ struct ui_event
char32_t ch;
short zdelta;
int num_lines;
+
+ pointer pointer_type; // type of input controlling this pointer
+ u16 pointer_id; // pointer ID - will be recycled aggressively
+ u16 pointer_device; // for grouping pointers for multi-touch gesture recognition
+ s32 pointer_x; // pointer X coordinate
+ s32 pointer_y; // pointer Y coordinate
+ u32 pointer_buttons; // currently depressed buttons
+ u32 pointer_pressed; // buttons pressed since last update (primary action in LSB)
+ u32 pointer_released; // buttons released since last update (primary action in LSB)
+ s16 pointer_clicks; // positive for multi-click, negative on release if turned into hold or drag
};
// ======================> ui_input_manager
-class ui_input_manager
+class ui_input_manager final : public osd::ui_event_handler
{
public:
// construction/destruction
ui_input_manager(running_machine &machine);
- void frame_update();
+ void check_ui_inputs();
// pushes a single event onto the queue
bool push_event(ui_event event);
@@ -68,17 +78,13 @@ public:
// clears all outstanding events
void reset();
- // retrieves the current location of the mouse
- render_target *find_mouse(s32 *x, s32 *y, bool *button) const;
- ioport_field *find_mouse_field() const;
-
- // return true if a key down for the given user interface sequence is detected
- bool pressed(int code);
-
// enable/disable UI key presses
bool presses_enabled() const { return m_presses_enabled; }
void set_presses_enabled(bool enabled) { m_presses_enabled = enabled; }
+ // return true if a key down for the given user interface sequence is detected
+ bool pressed(int code) { return pressed_repeat(code, 0); }
+
// return true if a key down for the given user interface sequence is detected, or if autorepeat at the given speed is triggered
bool pressed_repeat(int code, int speed);
@@ -86,44 +92,32 @@ public:
running_machine &machine() const { return m_machine; }
// queueing events
- void push_window_focus_event(render_target *target);
- void push_window_defocus_event(render_target *target);
- void push_mouse_move_event(render_target *target, s32 x, s32 y);
- void push_mouse_leave_event(render_target *target);
- void push_mouse_down_event(render_target *target, s32 x, s32 y);
- void push_mouse_up_event(render_target *target, s32 x, s32 y);
- void push_mouse_rdown_event(render_target *target, s32 x, s32 y);
- void push_mouse_rup_event(render_target *target, s32 x, s32 y);
- void push_mouse_double_click_event(render_target *target, s32 x, s32 y);
- void push_char_event(render_target *target, char32_t ch);
- void push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int ucNumLines);
+ virtual void push_window_focus_event(render_target *target) override;
+ virtual void push_window_defocus_event(render_target *target) override;
+ virtual void push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int lines) override;
+ virtual void push_pointer_update(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 buttons, u32 pressed, u32 released, s16 clicks) override;
+ virtual void push_pointer_leave(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) override;
+ virtual void push_pointer_abort(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) override;
+ virtual void push_char_event(render_target *target, char32_t ch) override;
void mark_all_as_pressed();
private:
-
// constants
- static constexpr unsigned EVENT_QUEUE_SIZE = 128;
+ static constexpr unsigned EVENT_QUEUE_SIZE = 256;
// internal state
- running_machine & m_machine; // reference to our machine
-
- // pressed states; retrieved with ui_input_pressed()
- bool m_presses_enabled;
- osd_ticks_t m_next_repeat[IPT_COUNT];
- u8 m_seqpressed[IPT_COUNT];
-
- // mouse position/info
- render_target * m_current_mouse_target;
- s32 m_current_mouse_x;
- s32 m_current_mouse_y;
- bool m_current_mouse_down;
- ioport_field * m_current_mouse_field;
-
- // popped states; ring buffer of ui_events
- ui_event m_events[EVENT_QUEUE_SIZE];
- int m_events_start;
- int m_events_end;
+ running_machine & m_machine;
+
+ // pressed states; retrieved with pressed() or pressed_repeat()
+ bool m_presses_enabled;
+ osd_ticks_t m_next_repeat[IPT_COUNT];
+ u8 m_seqpressed[IPT_COUNT];
+
+ // ring buffer of ui_events
+ ui_event m_events[EVENT_QUEUE_SIZE];
+ int m_events_start;
+ int m_events_end;
};
#endif // MAME_EMU_UIINPUT_H
diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp
index 18ba2c6fc6b..4cb6202b4d9 100644
--- a/src/emu/validity.cpp
+++ b/src/emu/validity.cpp
@@ -11,10 +11,14 @@
#include "emu.h"
#include "validity.h"
-#include "corestr.h"
#include "emuopts.h"
+#include "main.h"
#include "romload.h"
+#include "speaker.h"
#include "video/rgbutil.h"
+
+#include "corestr.h"
+#include "path.h"
#include "unicode.h"
#include <cctype>
@@ -47,12 +51,10 @@ using test_delegate = delegate<char (void const *&)>;
// type
//-------------------------------------------------
-#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000)
test_delegate make_diamond_class_delegate(char (diamond_inheritance::*func)(void const *&), diamond_inheritance *obj)
{
return test_delegate(func, obj);
}
-#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000)
//-------------------------------------------------
@@ -319,6 +321,34 @@ void validate_inlines()
if (resultu8 != i)
osd_printf_error("Error testing count_leading_ones_32 %08x=%02x (expected %02x)\n", t, resultu8, i);
}
+
+ u32 expected32 = testu32a << 1 | testu32a >> 31;
+ for (int i = -33; i <= 33; i++)
+ {
+ u32 resultu32r = rotr_32(testu32a, i);
+ u32 resultu32l = rotl_32(testu32a, -i);
+
+ if (resultu32r != expected32)
+ osd_printf_error("Error testing rotr_32 %08x, %d=%08x (expected %08x)\n", u32(testu32a), i, resultu32r, expected32);
+ if (resultu32l != expected32)
+ osd_printf_error("Error testing rotl_32 %08x, %d=%08x (expected %08x)\n", u32(testu32a), -i, resultu32l, expected32);
+
+ expected32 = expected32 >> 1 | expected32 << 31;
+ }
+
+ u64 expected64 = testu64a << 1 | testu64a >> 63;
+ for (int i = -65; i <= 65; i++)
+ {
+ u64 resultu64r = rotr_64(testu64a, i);
+ u64 resultu64l = rotl_64(testu64a, -i);
+
+ if (resultu64r != expected64)
+ osd_printf_error("Error testing rotr_64 %016x, %d=%016x (expected %016x)\n", u64(testu64a), i, resultu64r, expected64);
+ if (resultu64l != expected64)
+ osd_printf_error("Error testing rotl_64 %016x, %d=%016x (expected %016x)\n", u64(testu64a), -i, resultu64l, expected64);
+
+ expected64 = expected64 >> 1 | expected64 << 63;
+ }
}
@@ -804,6 +834,15 @@ void validate_rgb()
rgb.shl(rgbaint_t(19, 3, 21, 6));
check_expected("rgbaint_t::shl");
+ // test shift left out of range
+ expected_a = (actual_a = random_i32()) & 0;
+ expected_r = (actual_r = random_i32()) & 0;
+ expected_g = (actual_g = random_i32()) & 0;
+ expected_b = (actual_b = random_i32()) & 0;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.shl(rgbaint_t(-19, 32, -21, 38));
+ check_expected("rgbaint_t::shl");
+
// test shift left immediate
expected_a = (actual_a = random_i32()) << 7;
expected_r = (actual_r = random_i32()) << 7;
@@ -813,6 +852,15 @@ void validate_rgb()
rgb.shl_imm(7);
check_expected("rgbaint_t::shl_imm");
+ // test shift left immediate out of range
+ expected_a = (actual_a = random_i32()) & 0;
+ expected_r = (actual_r = random_i32()) & 0;
+ expected_g = (actual_g = random_i32()) & 0;
+ expected_b = (actual_b = random_i32()) & 0;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.shl_imm(32);
+ check_expected("rgbaint_t::shl_imm");
+
// test logical shift right
expected_a = s32(u32(actual_a = random_i32()) >> 8);
expected_r = s32(u32(actual_r = random_i32()) >> 18);
@@ -831,6 +879,15 @@ void validate_rgb()
rgb.shr(rgbaint_t(21, 13, 11, 17));
check_expected("rgbaint_t::shr");
+ // test logical shift right out of range
+ expected_a = (actual_a = random_i32()) & 0;
+ expected_r = (actual_r = random_i32()) & 0;
+ expected_g = (actual_g = random_i32()) & 0;
+ expected_b = (actual_b = random_i32()) & 0;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.shr(rgbaint_t(40, -18, -26, 32));
+ check_expected("rgbaint_t::shr");
+
// test logical shift right immediate
expected_a = s32(u32(actual_a = random_i32()) >> 5);
expected_r = s32(u32(actual_r = random_i32()) >> 5);
@@ -849,6 +906,15 @@ void validate_rgb()
rgb.shr_imm(15);
check_expected("rgbaint_t::shr_imm");
+ // test logical shift right immediate out of range
+ expected_a = (actual_a = random_i32()) & 0;
+ expected_r = (actual_r = random_i32()) & 0;
+ expected_g = (actual_g = random_i32()) & 0;
+ expected_b = (actual_b = random_i32()) & 0;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.shr_imm(35);
+ check_expected("rgbaint_t::shr_imm");
+
// test arithmetic shift right
expected_a = (actual_a = random_i32()) >> 16;
expected_r = (actual_r = random_i32()) >> 20;
@@ -867,6 +933,15 @@ void validate_rgb()
rgb.sra(rgbaint_t(1, 29, 10, 22));
check_expected("rgbaint_t::sra");
+ // test arithmetic shift right out of range
+ expected_a = (actual_a = random_i32()) >> 31;
+ expected_r = (actual_r = random_i32()) >> 31;
+ expected_g = (actual_g = random_i32()) >> 31;
+ expected_b = (actual_b = random_i32()) >> 31;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.sra(rgbaint_t(-16, -20, 46, 32));
+ check_expected("rgbaint_t::sra");
+
// test arithmetic shift right immediate (method)
expected_a = (actual_a = random_i32()) >> 12;
expected_r = (actual_r = random_i32()) >> 12;
@@ -885,6 +960,15 @@ void validate_rgb()
rgb.sra_imm(9);
check_expected("rgbaint_t::sra_imm");
+ // test arithmetic shift right immediate out of range (method)
+ expected_a = (actual_a = random_i32()) >> 31;
+ expected_r = (actual_r = random_i32()) >> 31;
+ expected_g = (actual_g = random_i32()) >> 31;
+ expected_b = (actual_b = random_i32()) >> 31;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb.sra_imm(38);
+ check_expected("rgbaint_t::sra_imm");
+
// test arithmetic shift right immediate (operator)
expected_a = (actual_a = random_i32()) >> 7;
expected_r = (actual_r = random_i32()) >> 7;
@@ -903,6 +987,15 @@ void validate_rgb()
rgb >>= 11;
check_expected("rgbaint_t::operator>>=");
+ // test arithmetic shift right immediate out of range (operator)
+ expected_a = (actual_a = random_i32()) >> 31;
+ expected_r = (actual_r = random_i32()) >> 31;
+ expected_g = (actual_g = random_i32()) >> 31;
+ expected_b = (actual_b = random_i32()) >> 31;
+ rgb.set(actual_a, actual_r, actual_g, actual_b);
+ rgb >>= 41;
+ check_expected("rgbaint_t::operator>>=");
+
// test RGB equality comparison
actual_a = random_i32_nolimit();
actual_r = random_i32_nolimit();
@@ -1393,7 +1486,6 @@ void validate_delegates_mfp()
if (&o != addr)
osd_printf_error("Error testing delegate this pointer adjustment for virtual member function through base class pointer %p -> %p (expected %p)\n", static_cast<void const *>(static_cast<base_b *>(&o)), addr, static_cast<void const *>(&o));
-#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000)
// test creating delegates for a forward-declared class
cb1 = make_diamond_class_delegate(&diamond_inheritance::get_derived_a, &d);
cb2 = make_diamond_class_delegate(&diamond_inheritance::get_derived_b, &d);
@@ -1423,7 +1515,6 @@ void validate_delegates_mfp()
if (static_cast<virtual_base *>(&d) != addr)
osd_printf_error("Error testing delegate this pointer adjustment for incomplete class %p -> %p (expected %p)\n", static_cast<void const *>(&d), addr, static_cast<void const *>(static_cast<virtual_base *>(&d)));
#endif // defined(_MSC_VER) && !defined(__clang__)
-#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000)
}
@@ -1868,6 +1959,7 @@ void validity_checker::validate_begin()
m_defstr_map.clear();
m_region_map.clear();
m_ioport_set.clear();
+ m_slotcard_set.clear();
// reset internal state
m_errors = 0;
@@ -2044,7 +2136,7 @@ void validity_checker::validate_driver(device_t &root)
device_t::feature_type const imperfect(m_current_driver->type.imperfect_features());
if (!(m_current_driver->flags & (machine_flags::IS_BIOS_ROOT | machine_flags::NO_SOUND_HW)) && !(unemulated & device_t::feature::SOUND))
{
- sound_interface_enumerator iter(root);
+ speaker_device_enumerator iter(root);
if (!iter.first())
osd_printf_error("Driver is missing MACHINE_NO_SOUND or MACHINE_NO_SOUND_HW flag\n");
}
@@ -2079,7 +2171,6 @@ void validity_checker::validate_roms(device_t &root)
u32 current_length = 0;
int items_since_region = 1;
int last_bios = 0, max_bios = 0;
- int total_files = 0;
std::unordered_map<std::string, int> bios_names;
std::unordered_map<std::string, std::string> bios_descs;
char const *defbios = nullptr;
@@ -2113,34 +2204,46 @@ void validity_checker::validate_roms(device_t &root)
current_length = ROMREGION_GETLENGTH(romp);
if (!m_region_map.emplace(fulltag, current_length).second)
osd_printf_error("Multiple ROM_REGIONs with the same tag '%s' defined\n", fulltag);
+ if (current_length == 0)
+ osd_printf_error("ROM region '%s' has zero length\n", fulltag);
}
else if (ROMENTRY_ISSYSTEM_BIOS(romp)) // If this is a system bios, make sure it is using the next available bios number
{
int const bios_flags = ROM_GETBIOSFLAGS(romp);
char const *const biosname = romp->name;
if (bios_flags != last_bios + 1)
- osd_printf_error("Non-sequential BIOS %s (specified as %d, expected to be %d)\n", biosname, bios_flags - 1, last_bios);
+ osd_printf_error("Non-sequential BIOS %s (specified as %d, expected to be %d)\n", biosname ? biosname : "UNNAMED", bios_flags - 1, last_bios);
last_bios = bios_flags;
// validate the name
- if (strlen(biosname) > 16)
- osd_printf_error("BIOS name %s exceeds maximum 16 characters\n", biosname);
- for (char const *s = biosname; *s; ++s)
+ if (!biosname || biosname[0] == 0)
+ osd_printf_error("BIOS %d is missing a name\n", bios_flags - 1);
+ else
{
- if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '.') && (*s != '_') && (*s != '-'))
+ if (strlen(biosname) > 16)
+ osd_printf_error("BIOS name %s exceeds maximum 16 characters\n", biosname);
+ for (char const *s = biosname; *s; ++s)
{
- osd_printf_error("BIOS name %s contains invalid characters\n", biosname);
- break;
+ if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '.') && (*s != '_') && (*s != '-'))
+ {
+ osd_printf_error("BIOS name %s contains invalid characters\n", biosname);
+ break;
+ }
}
- }
- // check for duplicate names/descriptions
- auto const nameins = bios_names.emplace(biosname, bios_flags);
- if (!nameins.second)
- osd_printf_error("Duplicate BIOS name %s specified (%d and %d)\n", biosname, nameins.first->second, bios_flags - 1);
- auto const descins = bios_descs.emplace(romp->hashdata, biosname);
- if (!descins.second)
- osd_printf_error("BIOS %s has duplicate description '%s' (was %s)\n", biosname, romp->hashdata, descins.first->second);
+ // check for duplicate names/descriptions
+ auto const nameins = bios_names.emplace(biosname, bios_flags);
+ if (!nameins.second)
+ osd_printf_error("Duplicate BIOS name %s specified (%d and %d)\n", biosname, nameins.first->second, bios_flags - 1);
+ if (!romp->hashdata || romp->hashdata[0] == 0)
+ osd_printf_error("BIOS %s has empty description\n", biosname);
+ else
+ {
+ auto const descins = bios_descs.emplace(romp->hashdata, biosname);
+ if (!descins.second)
+ osd_printf_error("BIOS %s has duplicate description '%s' (was %s)\n", biosname, romp->hashdata, descins.first->second);
+ }
+ }
}
else if (ROMENTRY_ISDEFAULT_BIOS(romp)) // if this is a default BIOS setting, remember it so it to check at the end
{
@@ -2150,7 +2253,6 @@ void validity_checker::validate_roms(device_t &root)
{
// track the last filename we found
last_name = romp->name;
- total_files++;
max_bios = std::max<int>(max_bios, ROM_GETBIOSFLAGS(romp));
// validate the name
@@ -2292,8 +2394,9 @@ void validity_checker::validate_analog_input_field(const ioport_field &field)
void validity_checker::validate_dip_settings(const ioport_field &field)
{
- const char *demo_sounds = ioport_string_from_index(INPUT_STRING_Demo_Sounds);
- const char *flipscreen = ioport_string_from_index(INPUT_STRING_Flip_Screen);
+ char const *const demo_sounds = ioport_string_from_index(INPUT_STRING_Demo_Sounds);
+ char const *const flipscreen = ioport_string_from_index(INPUT_STRING_Flip_Screen);
+ char const *const name = field.specific_name() ? field.specific_name() : "UNNAMED";
u8 coin_list[__input_string_coinage_end + 1 - __input_string_coinage_start] = { 0 };
bool coin_error = false;
@@ -2306,15 +2409,15 @@ void validity_checker::validate_dip_settings(const ioport_field &field)
coin_list[strindex - __input_string_coinage_start] = 1;
// make sure demo sounds default to on
- if (field.name() == demo_sounds && strindex == INPUT_STRING_On && field.defvalue() != setting->value())
+ if (name == demo_sounds && strindex == INPUT_STRING_On && field.defvalue() != setting->value())
osd_printf_error("Demo Sounds must default to On\n");
// check for bad demo sounds options
- if (field.name() == demo_sounds && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
+ if (name == demo_sounds && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
osd_printf_error("Demo Sounds option must be Off/On, not %s\n", setting->name());
// check for bad flip screen options
- if (field.name() == flipscreen && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
+ if (name == flipscreen && (strindex == INPUT_STRING_Yes || strindex == INPUT_STRING_No))
osd_printf_error("Flip Screen option must be Off/On, not %s\n", setting->name());
// if we have a neighbor, compare ourselves to him
@@ -2324,21 +2427,21 @@ void validity_checker::validate_dip_settings(const ioport_field &field)
// check for inverted off/on DIP switch order
int next_strindex = get_defstr_index(nextsetting->name(), true);
if (strindex == INPUT_STRING_On && next_strindex == INPUT_STRING_Off)
- osd_printf_error("%s option must have Off/On options in the order: Off, On\n", field.name());
+ osd_printf_error("%s option must have Off/On options in the order: Off, On\n", name);
// check for inverted yes/no DIP switch order
else if (strindex == INPUT_STRING_Yes && next_strindex == INPUT_STRING_No)
- osd_printf_error("%s option must have Yes/No options in the order: No, Yes\n", field.name());
+ osd_printf_error("%s option must have Yes/No options in the order: No, Yes\n", name);
// check for inverted upright/cocktail DIP switch order
else if (strindex == INPUT_STRING_Cocktail && next_strindex == INPUT_STRING_Upright)
- osd_printf_error("%s option must have Upright/Cocktail options in the order: Upright, Cocktail\n", field.name());
+ osd_printf_error("%s option must have Upright/Cocktail options in the order: Upright, Cocktail\n", name);
// check for proper coin ordering
else if (strindex >= __input_string_coinage_start && strindex <= __input_string_coinage_end && next_strindex >= __input_string_coinage_start && next_strindex <= __input_string_coinage_end &&
strindex >= next_strindex && setting->condition() == nextsetting->condition())
{
- osd_printf_error("%s option has unsorted coinage %s > %s\n", field.name(), setting->name(), nextsetting->name());
+ osd_printf_error("%s option has unsorted coinage %s > %s\n", name, setting->name(), nextsetting->name());
coin_error = true;
}
}
@@ -2362,6 +2465,12 @@ void validity_checker::validate_dip_settings(const ioport_field &field)
void validity_checker::validate_condition(const ioport_condition &condition, device_t &device)
{
+ if (condition.tag() == nullptr)
+ {
+ osd_printf_error("Condition referencing null ioport tag\n");
+ return;
+ }
+
// resolve the tag, then find a matching port
if (m_ioport_set.find(device.subtag(condition.tag())) == m_ioport_set.end())
osd_printf_error("Condition referencing non-existent ioport tag '%s'\n", condition.tag());
@@ -2426,34 +2535,43 @@ void validity_checker::validate_inputs(device_t &root)
if (field.is_analog())
validate_analog_input_field(field);
- // look for invalid (0) types which should be mapped to IPT_OTHER
- if (field.type() == IPT_INVALID)
+ // checks based on field type
+ if ((field.type() > IPT_UI_FIRST) && (field.type() < IPT_UI_LAST))
+ {
+ osd_printf_error("Field has invalid UI control type\n");
+ }
+ else if (field.type() == IPT_INVALID)
+ {
osd_printf_error("Field has an invalid type (0); use IPT_OTHER instead\n");
-
- if (field.type() == IPT_SPECIAL)
+ }
+ else if (field.type() == IPT_SPECIAL)
+ {
osd_printf_error("Field has an invalid type IPT_SPECIAL\n");
-
- // verify dip switches
- if (field.type() == IPT_DIPSWITCH)
+ }
+ else if (field.type() == IPT_DIPSWITCH)
{
- // dip switch fields must have a specific name
+ // DIP switch fields must have a specific name
if (field.specific_name() == nullptr)
osd_printf_error("DIP switch has no specific name\n");
// verify the settings list
validate_dip_settings(field);
}
-
- // verify config settings
- if (field.type() == IPT_CONFIG)
+ else if (field.type() == IPT_CONFIG)
{
// config fields must have a specific name
if (field.specific_name() == nullptr)
osd_printf_error("Config switch has no specific name\n");
}
+ else if (field.type() == IPT_ADJUSTER)
+ {
+ // adjuster fields must have a specific name
+ if (field.specific_name() == nullptr)
+ osd_printf_error("Adjuster has no specific name\n");
+ }
// verify names
- const char *name = field.specific_name();
+ char const *const name = field.specific_name();
if (name != nullptr)
{
// check for empty string
@@ -2467,9 +2585,6 @@ void validity_checker::validate_inputs(device_t &root)
// check for invalid UTF-8
if (!utf8_is_valid_string(name))
osd_printf_error("Field '%s' has invalid characters\n", name);
-
- // look up the string and print an error if default strings are not used
- /*strindex =get_defstr_index(defstr_map, name, driver, &error);*/
}
// verify conditions on the field
@@ -2549,6 +2664,10 @@ void validity_checker::validate_devices(machine_config &config)
if (slot->default_option() != nullptr && option.first == slot->default_option())
continue;
+ // if we need to save time, instantiate and validate each slot card type at most once
+ if (m_quick && !m_slotcard_set.insert(option.second->devtype().shortname()).second)
+ continue;
+
m_checking_card = true;
device_t *card;
{
@@ -2774,7 +2893,7 @@ void validity_checker::build_output_prefix(std::ostream &str) const
// error_output - error message output override
//-------------------------------------------------
-void validity_checker::output_callback(osd_output_channel channel, const util::format_argument_pack<std::ostream> &args)
+void validity_checker::output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args)
{
std::ostringstream output;
switch (channel)
diff --git a/src/emu/validity.h b/src/emu/validity.h
index 3e6ff8e5a00..fbf5f239323 100644
--- a/src/emu/validity.h
+++ b/src/emu/validity.h
@@ -51,7 +51,7 @@ public:
protected:
// osd_output interface
- virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<std::ostream> &args) override;
+ virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override;
private:
// internal map types
@@ -109,6 +109,7 @@ private:
int_map m_region_map;
string_set m_ioport_set;
string_set m_already_checked;
+ string_set m_slotcard_set;
bool m_checking_card;
bool const m_quick;
};
diff --git a/src/emu/video.cpp b/src/emu/video.cpp
index 652272f680b..06a16b76cda 100644
--- a/src/emu/video.cpp
+++ b/src/emu/video.cpp
@@ -9,19 +9,26 @@
***************************************************************************/
#include "emu.h"
-#include "emuopts.h"
-#include "debugger.h"
-#include "ui/uimain.h"
+
#include "crsshair.h"
-#include "rendersw.hxx"
+#include "debugger.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "output.h"
+#include "screen.h"
+
+#include "ui/uimain.h"
#include "corestr.h"
+#include "path.h"
#include "png.h"
#include "xmlfile.h"
#include "osdepend.h"
+#include "rendersw.hxx"
+
//**************************************************************************
// DEBUGGING
@@ -211,8 +218,9 @@ void video_manager::frame_update(bool from_debugger)
bool const update_screens = (phase == machine_phase::RUNNING) && (!machine().paused() || machine().options().update_in_pause());
bool anything_changed = update_screens && finish_screen_updates();
- // draw the user interface
- emulator_info::draw_user_interface(machine());
+ // update inputs and draw the user interface
+ machine().osd().input_update(true);
+ anything_changed = emulator_info::draw_user_interface(machine()) || anything_changed;
// let plugins draw over the UI
anything_changed = emulator_info::frame_hook() || anything_changed;
@@ -227,21 +235,20 @@ void video_manager::frame_update(bool from_debugger)
// if we're throttling, synchronize before rendering
attotime current_time = machine().time();
- if (!from_debugger && !skipped_it && phase > machine_phase::INIT && !m_low_latency && effective_throttle())
+ if (!from_debugger && phase > machine_phase::INIT && !m_low_latency && effective_throttle())
update_throttle(current_time);
// ask the OSD to update
- g_profiler.start(PROFILER_BLIT);
- machine().osd().update(!from_debugger && skipped_it);
- g_profiler.stop();
+ {
+ auto profile = g_profiler.start(PROFILER_BLIT);
+ machine().osd().update(!from_debugger && skipped_it);
+ }
// we synchronize after rendering instead of before, if low latency mode is enabled
- if (!from_debugger && !skipped_it && phase > machine_phase::INIT && m_low_latency && effective_throttle())
+ if (!from_debugger && phase > machine_phase::INIT && m_low_latency && effective_throttle())
update_throttle(current_time);
- // get most recent input now
- machine().osd().input_update();
-
+ machine().osd().input_update(false);
emulator_info::periodic_check();
if (!from_debugger)
@@ -299,7 +306,7 @@ std::string video_manager::speed_text()
// append the speed for all cases except paused
if (!paused)
- util::stream_format(str, "%4d%%", (int)(100 * m_speed_percent + 0.5));
+ util::stream_format(str, " %3d%%", int(100 * m_speed_percent + 0.5));
// display the number of partial updates as well
int partials = 0;
@@ -317,7 +324,7 @@ std::string video_manager::speed_text()
// file handle
//-------------------------------------------------
-void video_manager::save_snapshot(screen_device *screen, emu_file &file)
+void video_manager::save_snapshot(screen_device *screen, util::core_file &file)
{
// validate
assert(!m_snap_native || screen != nullptr);
@@ -378,18 +385,15 @@ void video_manager::save_active_screen_snapshots()
void video_manager::begin_recording_screen(const std::string &filename, uint32_t index, screen_device *screen, movie_recording::format format)
{
- // determine the file extension
- const char *extension = movie_recording::format_file_extension(format);
-
// create the emu_file
- bool is_absolute_path = !filename.empty() && osd_is_absolute_path(filename);
+ bool const is_absolute_path = !filename.empty() && osd_is_absolute_path(filename);
std::unique_ptr<emu_file> movie_file = std::make_unique<emu_file>(
is_absolute_path ? "" : machine().options().snapshot_directory(),
OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
// and open the actual file
std::error_condition filerr = filename.empty()
- ? open_next(*movie_file, extension)
+ ? open_next(*movie_file, movie_recording::format_file_extension(format))
: movie_file->open(filename);
if (filerr)
{
@@ -427,26 +431,48 @@ void video_manager::begin_recording(const char *name, movie_recording::format fo
// clear out existing recordings
m_movie_recordings.clear();
+ // check if the supplied name already has the desired extension
+ std::string_view basename;
+ std::string extension;
+ if (name)
+ {
+ std::string_view const desired_ext = movie_recording::format_file_extension(format);
+ basename = name;
+ extension.reserve(1 + desired_ext.length());
+ extension.assign(1, '.').append(desired_ext);
+ if (core_filename_ends_with(basename, extension))
+ {
+ extension = basename.substr(basename.length() - extension.length());
+ basename.remove_suffix(extension.length());
+ }
+ }
+
if (m_snap_native)
{
+ std::string tempname;
for (uint32_t index = 0; index < count; index++, iter++)
{
- create_snapshot_bitmap(iter.current());
+ create_snapshot_bitmap(iter.current()); // TODO: only do this when starting on-the-fly, and make name match AVI file name
- std::string tempname;
if (name)
- tempname = index > 0 ? name : util::string_format("%s%d", name, index);
+ {
+ if (1 < count)
+ tempname = util::string_format("%s%d%s", basename, index, extension);
+ else
+ tempname.assign(name).append(extension);
+ }
+
begin_recording_screen(
- tempname,
- index,
- iter.current(),
- format);
+ tempname,
+ index,
+ iter.current(),
+ format);
}
}
else
{
create_snapshot_bitmap(nullptr);
- begin_recording_screen(name ? name : "", 0, iter.current(), format);
+ begin_recording_screen(std::string(basename) + extension, 0, iter.current(), format);
}
}
@@ -492,7 +518,7 @@ void video_manager::exit()
// when there are no screens to drive it
//-------------------------------------------------
-void video_manager::screenless_update_callback(void *ptr, int param)
+void video_manager::screenless_update_callback(s32 param)
{
// force an update
frame_update(false);
@@ -506,8 +532,13 @@ void video_manager::screenless_update_callback(void *ptr, int param)
void video_manager::postload()
{
+ attotime const emutime = machine().time();
for (const auto &x : m_movie_recordings)
- x->set_next_frame_time(machine().time());
+ x->set_next_frame_time(emutime);
+
+ // reset speed measurements
+ m_speed_last_realtime = osd_ticks();
+ m_speed_last_emutime = emutime;
}
@@ -590,7 +621,7 @@ bool video_manager::finish_screen_updates()
bool has_live_screen = false;
for (screen_device &screen : iter)
{
- if (screen.partial_scan_hpos() >= 0) // previous update ended mid-scanline
+ if (screen.partial_scan_hpos() > 0) // previous update ended mid-scanline
screen.update_now();
screen.update_partial(screen.visible_area().max_y);
@@ -776,7 +807,7 @@ osd_ticks_t video_manager::throttle_until_ticks(osd_ticks_t target_ticks)
bool const allowed_to_sleep = (machine().options().sleep() && (!effective_autoframeskip() || effective_frameskip() == 0)) || machine().paused();
// loop until we reach our target
- g_profiler.start(PROFILER_IDLE);
+ auto profile = g_profiler.start(PROFILER_IDLE);
osd_ticks_t current_ticks = osd_ticks();
while (current_ticks < target_ticks)
{
@@ -812,7 +843,6 @@ osd_ticks_t video_manager::throttle_until_ticks(osd_ticks_t target_ticks)
}
current_ticks = new_ticks;
}
- g_profiler.stop();
return current_ticks;
}
@@ -960,10 +990,23 @@ void video_manager::recompute_speed(const attotime &emutime)
if (m_seconds_to_run != 0 && emutime.seconds() >= m_seconds_to_run)
{
// create a final screenshot
- emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- std::error_condition const filerr = open_next(file, "png");
- if (!filerr)
- save_snapshot(nullptr, file);
+ if (m_snap_native)
+ {
+ for (screen_device &screen : screen_device_enumerator(machine().root_device()))
+ {
+ emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition const filerr = open_next(file, "png");
+ if (!filerr)
+ save_snapshot(&screen, file);
+ }
+ }
+ else
+ {
+ emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition const filerr = open_next(file, "png");
+ if (!filerr)
+ save_snapshot(nullptr, file);
+ }
//printf("Scheduled exit at %f\n", emutime.as_double());
// schedule our demise
@@ -1057,14 +1100,19 @@ std::error_condition video_manager::open_next(emu_file &file, const char *extens
// handle defaults
const char *snapname = machine().options().snap_name();
- if (snapname == nullptr || snapname[0] == 0)
+ if (!snapname || !snapname[0])
snapname = "%g/%i";
std::string snapstr(snapname);
- // strip any extension in the provided name
- int index = snapstr.find_last_of('.');
- if (index != -1)
- snapstr = snapstr.substr(0, index);
+ // strip desired extension if already present
+ std::string extstr;
+ extstr.reserve(1 + std::strlen(extension));
+ extstr.assign(1, '.').append(extension);
+ if (core_filename_ends_with(snapstr, extstr))
+ {
+ extstr = snapstr.substr(snapstr.length() - extstr.length());
+ snapstr.resize(snapstr.length() - extstr.length());
+ }
// handle %d in the template (for image devices)
std::string snapdev("%d_");
@@ -1129,27 +1177,30 @@ std::error_condition video_manager::open_next(emu_file &file, const char *extens
if (pos_time != -1)
{
- char t_str[15];
+ char t_str[16];
const std::time_t cur_time = std::time(nullptr);
strftime(t_str, sizeof(t_str), "%Y%m%d_%H%M%S", std::localtime(&cur_time));
strreplace(snapstr, "%t", t_str);
}
- // add our own extension
- snapstr.append(".").append(extension);
+ // append extension
+ snapstr.append(extstr);
// substitute path and gamename up front
strreplace(snapstr, "/", PATH_SEPARATOR);
strreplace(snapstr, "%g", machine().basename());
- // determine if the template has an index; if not, we always use the same name
+ // determine if the template has an index
std::string fname;
if (snapstr.find("%i") == -1)
+ {
+ // if not, we always use the same name
fname.assign(snapstr);
-
- // otherwise, we scan for the next available filename
+ }
else
{
+ // otherwise, we scan for the next available filename
+
// try until we succeed
file.set_openflags(OPEN_FLAG_WRITE);
for (int seq = 0; ; seq++)
@@ -1182,7 +1233,7 @@ void video_manager::record_frame()
return;
// start the profiler and get the current time
- g_profiler.start(PROFILER_MOVIE_REC);
+ auto profile = g_profiler.start(PROFILER_MOVIE_REC);
attotime curtime = machine().time();
bool error = false;
@@ -1201,7 +1252,6 @@ void video_manager::record_frame()
if (error)
end_recording();
- g_profiler.stop();
}
diff --git a/src/emu/video.h b/src/emu/video.h
index c6d69194ba1..efc819ae793 100644
--- a/src/emu/video.h
+++ b/src/emu/video.h
@@ -78,7 +78,7 @@ public:
// snapshots
bool snap_native() const { return m_snap_native; }
render_target &snapshot_target() { return *m_snap_target; }
- void save_snapshot(screen_device *screen, emu_file &file);
+ void save_snapshot(screen_device *screen, util::core_file &file);
void save_active_screen_snapshots();
// movies
@@ -90,7 +90,7 @@ public:
private:
// internal helpers
void exit();
- void screenless_update_callback(void *ptr, int param);
+ void screenless_update_callback(s32 param);
void postload();
// effective value helpers
diff --git a/src/emu/video/resnet.h b/src/emu/video/resnet.h
index 638f9909255..53ef41ee5dd 100644
--- a/src/emu/video/resnet.h
+++ b/src/emu/video/resnet.h
@@ -106,7 +106,7 @@ struct res_net_channel_info {
// - Least significant bit first
double R[8];
// Minimum output voltage
- // - Applicable if output is routed through a complimentary
+ // - Applicable if output is routed through a complementary
// - darlington circuit
// - typical value ~ 0.9V
double minout;
diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h
index e460208d9fd..b20d79c94d8 100644
--- a/src/emu/video/rgbgen.h
+++ b/src/emu/video/rgbgen.h
@@ -151,16 +151,21 @@ public:
inline void shl(const rgbaint_t& shift)
{
- m_a <<= shift.m_a;
- m_r <<= shift.m_r;
- m_g <<= shift.m_g;
- m_b <<= shift.m_b;
+ m_a = (u32(shift.m_a) > 31) ? 0 : (m_a << shift.m_a);
+ m_r = (u32(shift.m_r) > 31) ? 0 : (m_r << shift.m_r);
+ m_g = (u32(shift.m_g) > 31) ? 0 : (m_g << shift.m_g);
+ m_b = (u32(shift.m_b) > 31) ? 0 : (m_b << shift.m_b);
}
inline void shl_imm(const u8 shift)
{
if (shift == 0)
return;
+ if (shift > 31)
+ {
+ zero();
+ return;
+ }
m_a <<= shift;
m_r <<= shift;
@@ -170,16 +175,21 @@ public:
inline void shr(const rgbaint_t& shift)
{
- m_a = s32(u32(m_a) >> shift.m_a);
- m_r = s32(u32(m_r) >> shift.m_r);
- m_g = s32(u32(m_g) >> shift.m_g);
- m_b = s32(u32(m_b) >> shift.m_b);
+ m_a = (u32(shift.m_a) > 31) ? 0 : s32(u32(m_a) >> shift.m_a);
+ m_r = (u32(shift.m_r) > 31) ? 0 : s32(u32(m_r) >> shift.m_r);
+ m_g = (u32(shift.m_g) > 31) ? 0 : s32(u32(m_g) >> shift.m_g);
+ m_b = (u32(shift.m_b) > 31) ? 0 : s32(u32(m_b) >> shift.m_b);
}
inline void shr_imm(const u8 shift)
{
if (shift == 0)
return;
+ if (shift > 31)
+ {
+ zero();
+ return;
+ }
m_a = s32(u32(m_a) >> shift);
m_r = s32(u32(m_r) >> shift);
@@ -189,43 +199,19 @@ public:
inline void sra(const rgbaint_t& shift)
{
- m_a >>= shift.m_a;
- if (m_a & (1 << (31 - shift.m_a)))
- m_a |= ~0 << (32 - shift.m_a);
-
- m_r >>= shift.m_r;
- if (m_r & (1 << (31 - shift.m_r)))
- m_r |= ~0 << (32 - shift.m_r);
-
- m_g >>= shift.m_g;
- if (m_g & (1 << (31 - shift.m_g)))
- m_g |= ~0 << (32 - shift.m_g);
-
- m_b >>= shift.m_b;
- if (m_b & (1 << (31 - shift.m_b)))
- m_b |= ~0 << (32 - shift.m_b);
+ m_a >>= (u32(shift.m_a) > 31) ? 31 : shift.m_a;
+ m_r >>= (u32(shift.m_r) > 31) ? 31 : shift.m_r;
+ m_g >>= (u32(shift.m_g) > 31) ? 31 : shift.m_g;
+ m_b >>= (u32(shift.m_b) > 31) ? 31 : shift.m_b;
}
inline void sra_imm(const u8 shift)
{
- const u32 high_bit = 1 << (31 - shift);
- const u32 high_mask = ~0 << (32 - shift);
-
- m_a >>= shift;
- if (m_a & high_bit)
- m_a |= high_mask;
-
- m_r >>= shift;
- if (m_r & high_bit)
- m_r |= high_mask;
-
- m_g >>= shift;
- if (m_g & high_bit)
- m_g |= high_mask;
-
- m_b >>= shift;
- if (m_b & high_bit)
- m_b |= high_mask;
+ const u8 s = std::min<u8>(shift, 31);
+ m_a >>= s;
+ m_r >>= s;
+ m_g >>= s;
+ m_b >>= s;
}
void or_reg(const rgbaint_t& color) { or_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); }
diff --git a/src/emu/video/rgbvmx.cpp b/src/emu/video/rgbvmx.cpp
index 608f7024565..62bd25b3578 100644
--- a/src/emu/video/rgbvmx.cpp
+++ b/src/emu/video/rgbvmx.cpp
@@ -190,7 +190,7 @@ void rgbaint_t::scale_and_clamp(const rgbaint_t& scale)
clamp_to_uint8();
}
-void rgbaint_t::scale_imm_and_clamp(const s32 scale)
+void rgbaint_t::scale_imm_and_clamp(s32 scale)
{
mul_imm(scale);
sra_imm(8);
diff --git a/src/emu/video/rgbvmx.h b/src/emu/video/rgbvmx.h
index 05d26cd9e21..dd1946bfa28 100644
--- a/src/emu/video/rgbvmx.h
+++ b/src/emu/video/rgbvmx.h
@@ -76,7 +76,7 @@ public:
}
// This function sets all elements to the same val
- void set_all(const s32& val) { set(val, val, val, val); }
+ void set_all(const s32 &val) { set(val, val, val, val); }
// This function zeros all elements
void zero() { set_all(0); }
// This function zeros only the alpha element
@@ -100,31 +100,31 @@ public:
return result;
}
- void set_a16(const s32 value)
+ void set_a16(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, alpha_perm);
}
- void set_a(const s32 value)
+ void set_a(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, alpha_perm);
}
- void set_r(const s32 value)
+ void set_r(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, red_perm);
}
- void set_g(const s32 value)
+ void set_g(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, green_perm);
}
- void set_b(const s32 value)
+ void set_b(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, blue_perm);
@@ -229,13 +229,13 @@ public:
m_value = vec_add(m_value, color2.m_value);
}
- inline void add_imm(const s32 imm)
+ inline void add_imm(s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_add(m_value, temp);
}
- inline void add_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void add_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -250,13 +250,13 @@ public:
m_value = vec_sub(m_value, color2.m_value);
}
- inline void sub_imm(const s32 imm)
+ inline void sub_imm(s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_sub(m_value, temp);
}
- inline void sub_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void sub_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -271,13 +271,13 @@ public:
m_value = vec_sub(color2.m_value, m_value);
}
- inline void subr_imm(const s32 imm)
+ inline void subr_imm(s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_sub(temp, m_value);
}
- inline void subr_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void subr_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -298,7 +298,7 @@ public:
#endif
}
- inline void mul_imm(const s32 imm)
+ inline void mul_imm(s32 imm)
{
const VECU32 value = { u32(imm), u32(imm), u32(imm), u32(imm) };
const VECU32 shift = vec_splat_u32(-16);
@@ -310,7 +310,7 @@ public:
#endif
}
- inline void mul_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void mul_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECU32 value = { u32(b), u32(g), u32(r), u32(a) };
@@ -332,10 +332,17 @@ public:
m_value = vec_and(vec_sl(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value)));
}
- inline void shl_imm(const u8 shift)
+ inline void shl_imm(u8 shift)
{
- const VECU32 temp = { shift, shift, shift, shift };
- m_value = vec_sl(m_value, temp);
+ if (32 > shift)
+ {
+ const VECU32 temp = { shift, shift, shift, shift };
+ m_value = vec_sl(m_value, temp);
+ }
+ else
+ {
+ m_value = vec_splat_s32(0);
+ }
}
inline void shr(const rgbaint_t& shift)
@@ -344,10 +351,17 @@ public:
m_value = vec_and(vec_sr(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value)));
}
- inline void shr_imm(const u8 shift)
+ inline void shr_imm(u8 shift)
{
- const VECU32 temp = { shift, shift, shift, shift };
- m_value = vec_sr(m_value, temp);
+ if (32 > shift)
+ {
+ const VECU32 temp = { shift, shift, shift, shift };
+ m_value = vec_sr(m_value, temp);
+ }
+ else
+ {
+ m_value = vec_splat_s32(0);
+ }
}
inline void sra(const rgbaint_t& shift)
@@ -356,8 +370,9 @@ public:
m_value = vec_sra(m_value, vec_min(VECU32(shift.m_value), limit));
}
- inline void sra_imm(const u8 shift)
+ inline void sra_imm(u8 shift)
{
+ shift = std::min<u8>(shift, 31);
const VECU32 temp = { shift, shift, shift, shift };
m_value = vec_sra(m_value, temp);
}
@@ -367,13 +382,13 @@ public:
m_value = vec_or(m_value, color2.m_value);
}
- inline void or_imm(const s32 value)
+ inline void or_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_or(m_value, temp);
}
- inline void or_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void or_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -393,13 +408,13 @@ public:
m_value = vec_andc(m_value, color.m_value);
}
- inline void and_imm(const s32 value)
+ inline void and_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_and(m_value, temp);
}
- inline void and_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void and_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -414,13 +429,13 @@ public:
m_value = vec_xor(m_value, color2.m_value);
}
- inline void xor_imm(const s32 value)
+ inline void xor_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_xor(m_value, temp);
}
- inline void xor_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void xor_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -430,7 +445,7 @@ public:
m_value = vec_xor(m_value, temp);
}
- inline void clamp_and_clear(const u32 sign)
+ inline void clamp_and_clear(u32 sign)
{
const VECS32 vzero = { 0, 0, 0, 0 };
VECS32 vsign = { s32(sign), s32(sign), s32(sign), s32(sign) };
@@ -454,7 +469,7 @@ public:
#endif
}
- inline void sign_extend(const u32 compare, const u32 sign)
+ inline void sign_extend(u32 compare, u32 sign)
{
const VECS32 compare_vec = { s32(compare), s32(compare), s32(compare), s32(compare) };
const VECS32 compare_mask = VECS32(vec_cmpeq(vec_and(m_value, compare_vec), compare_vec));
@@ -462,13 +477,13 @@ public:
m_value = vec_or(m_value, vec_and(sign_vec, compare_mask));
}
- inline void min(const s32 value)
+ inline void min(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_min(m_value, temp);
}
- inline void max(const s32 value)
+ inline void max(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_max(m_value, temp);
@@ -477,7 +492,7 @@ public:
void blend(const rgbaint_t& other, u8 factor);
void scale_and_clamp(const rgbaint_t& scale);
- void scale_imm_and_clamp(const s32 scale);
+ void scale_imm_and_clamp(s32 scale);
void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
@@ -503,13 +518,13 @@ public:
m_value = VECS32(vec_cmpeq(m_value, value.m_value));
}
- inline void cmpeq_imm(const s32 value)
+ inline void cmpeq_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmpeq(m_value, temp));
}
- inline void cmpeq_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void cmpeq_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -524,13 +539,13 @@ public:
m_value = VECS32(vec_cmpgt(m_value, value.m_value));
}
- inline void cmpgt_imm(const s32 value)
+ inline void cmpgt_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmpgt(m_value, temp));
}
- inline void cmpgt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void cmpgt_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -545,13 +560,13 @@ public:
m_value = VECS32(vec_cmplt(m_value, value.m_value));
}
- inline void cmplt_imm(const s32 value)
+ inline void cmplt_imm(s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmplt(m_value, temp));
}
- inline void cmplt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
+ inline void cmplt_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
@@ -567,7 +582,7 @@ public:
return *this;
}
- inline rgbaint_t& operator+=(const s32 other)
+ inline rgbaint_t& operator+=(s32 other)
{
const VECS32 temp = { other, other, other, other };
m_value = vec_add(m_value, temp);
@@ -592,7 +607,7 @@ public:
return *this;
}
- inline rgbaint_t& operator*=(const s32 other)
+ inline rgbaint_t& operator*=(s32 other)
{
const VECS32 value = { other, other, other, other };
const VECU32 shift = vec_splat_u32(-16);
@@ -605,19 +620,20 @@ public:
return *this;
}
- inline rgbaint_t& operator>>=(const s32 shift)
+ inline rgbaint_t& operator>>=(s32 shift)
{
+ shift = s32(std::min<u32>(shift, 31));
const VECU32 temp = { u32(shift), u32(shift), u32(shift), u32(shift) };
m_value = vec_sra(m_value, temp);
return *this;
}
- inline void merge_alpha16(const rgbaint_t& alpha)
+ inline void merge_alpha16(const rgbaint_t &alpha)
{
m_value = vec_perm(m_value, alpha.m_value, alpha_perm);
}
- inline void merge_alpha(const rgbaint_t& alpha)
+ inline void merge_alpha(const rgbaint_t &alpha)
{
m_value = vec_perm(m_value, alpha.m_value, alpha_perm);
}
diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp
index 16178a2bfc7..ab4f13f11cf 100644
--- a/src/emu/xtal.cpp
+++ b/src/emu/xtal.cpp
@@ -80,10 +80,12 @@ const double XTAL::known_xtals[] = {
2'000'000, /* 2_MHz_XTAL - */
2'012'160, /* 2.01216_MHz_XTAL Cidelsa Draco sound board */
2'097'152, /* 2.097152_MHz_XTAL Icatel 1995 - Brazilian public payphone */
+ 2'250'000, /* 2.25_MHz_XTAL Resonator - YM2154 on Yamaha PSR-60 & PSR-70 */
2'376'000, /* 2.376_MHz_XTAL CIT-101 keyboard */
2'457'600, /* 2.4576_MHz_XTAL Atari ST MFP */
2'500'000, /* 2.5_MHz_XTAL Janken Man units */
2'600'000, /* 2.6_MHz_XTAL Sharp PC-1500 */
+ 2'700'000, /* 2.7_MHz_XTAL Resonator - YM2154 on Yamaha RX15 */
2'950'000, /* 2.95_MHz_XTAL Playmatic MPU-C, MPU-III & Sound-3 */
3'000'000, /* 3_MHz_XTAL Probably only used to drive 68705 or similar MCUs on 80's Taito PCBs */
3'072'000, /* 3.072_MHz_XTAL INS 8520 input clock rate */
@@ -100,6 +102,7 @@ const double XTAL::known_xtals[] = {
3'579'000, /* 3.579_MHz_XTAL BeebOPL */
3'579'545, /* 3.579545_MHz_XTAL NTSC color subcarrier, extremely common, used on 100's of PCBs (Keytronic custom part #48-300-010 is equivalent) */
3'579'575, /* 3.579575_MHz_XTAL Atari 2600 NTSC */
+ 3'680'000, /* 3.68_MHz_XTAL Resonator - Baud rate clock for the 6551 in the MTU-130 */
3'686'400, /* 3.6864_MHz_XTAL Baud rate clock for MC68681 and similar UARTs */
3'840'000, /* 3.84_MHz_XTAL Fairlight CMI Alphanumeric Keyboard */
3'900'000, /* 3.9_MHz_XTAL Resonator - Used on some Fidelity boards */
@@ -115,13 +118,16 @@ const double XTAL::known_xtals[] = {
4'433'619, /* 4.433619_MHz_XTAL PAL color subcarrier (technically 4.43361875mhz)*/
4'608'000, /* 4.608_MHz_XTAL Luxor ABC-77 keyboard (Keytronic custom part #48-300-107 is equivalent) */
4'915'200, /* 4.9152_MHz_XTAL - */
+ 4'952'000, /* 4.952_MHz_XTAL IGS M036 based mahjong games, for TT5665 sound chip */
5'000'000, /* 5_MHz_XTAL Mutant Night */
5'068'800, /* 5.0688_MHz_XTAL Usually used as MC2661 or COM8116 baud rate clock */
5'185'000, /* 5.185_MHz_XTAL Intel INTELLEC® 4 */
5'370'000, /* 5.37_MHz_XTAL HP 95LX */
5'460'000, /* 5.46_MHz_XTAL ec1840 and ec1841 keyboard */
+ 5'500'000, /* 5.5_MHz_XTAL Yamaha PSS-480 */
5'529'600, /* 5.5296_MHz_XTAL Kontron PSI98 keyboard */
5'626'000, /* 5.626_MHz_XTAL RCA CDP1869 PAL dot clock */
+ 5'659'200, /* 5.6592_MHz_XTAL Digilog 320 dot clock */
5'670'000, /* 5.67_MHz_XTAL RCA CDP1869 NTSC dot clock */
5'714'300, /* 5.7143_MHz_XTAL Cidelsa Destroyer, TeleVideo serial keyboards */
5'856'000, /* 5.856_MHz_XTAL HP 3478A Multimeter */
@@ -137,8 +143,9 @@ const double XTAL::known_xtals[] = {
7'000'000, /* 7_MHz_XTAL Jaleco Mega System PCBs */
7'056'000, /* 7.056_MHz_XTAL Alesis QS FXCHIP (LCM of 44.1 kHz and 48 kHz) */
7'159'090, /* 7.15909_MHz_XTAL Blood Bros (2x NTSC subcarrier) */
- 7'200'000, /* 7.2_MHz_XTAL Image Fight bootleg I80C031 MCU */
+ 7'200'000, /* 7.2_MHz_XTAL Novag Constellation (later models, with /2 divider), Kawai K1 keyscan IC */
7'372'800, /* 7.3728_MHz_XTAL - */
+ 7'680'000, /* 7.68_MHz_XTAL Psion Series 3 */
7'864'300, /* 7.8643_MHz_XTAL Used on InterFlip games as video clock */
7'987'000, /* 7.987_MHz_XTAL PC9801-86 YM2608 clock */
7'995'500, /* 7.9955_MHz_XTAL Used on Electronic Devices Italy Galaxy Gunners sound board */
@@ -158,6 +165,7 @@ const double XTAL::known_xtals[] = {
9'000'000, /* 9_MHz_XTAL Homedata PCBs */
9'216'000, /* 9.216_MHz_XTAL Univac UTS 20 */
9'400'000, /* 9.4_MHz_XTAL Yamaha MU-5 and TG-100 */
+ 9'426'500, /* 9.4265_MHz_XTAL Yamaha DX7, and DX9 */
9'600'000, /* 9.6_MHz_XTAL WD37C65 second clock (for 300 KB/sec rate) */
9'732'000, /* 9.732_MHz_XTAL CTA Invader */
9'828'000, /* 9.828_MHz_XTAL Universal PCBs */
@@ -172,6 +180,7 @@ const double XTAL::known_xtals[] = {
10'480'000, /* 10.48_MHz_XTAL System-80 (50 Hz) */
10'500'000, /* 10.5_MHz_XTAL Agat-7 */
10'595'000, /* 10.595_MHz_XTAL Mad Alien */
+ 10'644'000, /* 10.644_MHz_XTAL Northwest Digitial Systems GP-19 */
10'644'500, /* 10.6445_MHz_XTAL TRS-80 Model I */
10'687'500, /* 10.6875_MHz_XTAL BBC Bridge Companion */
10'694'250, /* 10.69425_MHz_XTAL Xerox 820 */
@@ -191,14 +200,16 @@ const double XTAL::known_xtals[] = {
11'289'600, /* 11.2896_MHz_XTAL Frantic Fred */
11'400'000, /* 11.4_MHz_XTAL HP 9845 */
11'668'800, /* 11.6688_MHz_XTAL Gameplan pixel clock */
+ 11'730'000, /* 11.73_MHz_XTAL Irem M-11 */
11'800'000, /* 11.8_MHz_XTAL IBM PC Music Feature Card */
11'980'800, /* 11.9808_MHz_XTAL Luxor ABC 80 */
12'000'000, /* 12_MHz_XTAL Extremely common, used on 100's of PCBs */
12'057'600, /* 12.0576_MHz_XTAL Poly 1 (38400 * 314) */
12'096'000, /* 12.096_MHz_XTAL Some early 80's Atari games */
12'288'000, /* 12.288_MHz_XTAL Sega Model 3 digital audio board */
+ 12'292'000, /* 12.292_MHz_XTAL Northwest Digitial Systems GP-19 */
12'324'000, /* 12.324_MHz_XTAL Otrona Attache */
- 12'432'000, /* 12.432_MHz_XTAL Kaneko Fly Boy/Fast Freddie Hardware */
+ 12'335'600, /* 12.3356_MHz_XTAL RasterOps ColorBoard 264 (~784x NTSC line rate) */
12'472'500, /* 12.4725_MHz_XTAL Bonanza's Mini Boy 7 */
12'480'000, /* 12.48_MHz_XTAL TRS-80 Model II */
12'500'000, /* 12.5_MHz_XTAL Red Alert audio board */
@@ -217,22 +228,27 @@ const double XTAL::known_xtals[] = {
13'495'200, /* 13.4952_MHz_XTAL Used on Shadow Force pcb and maybe other Technos pcbs? */
13'500'000, /* 13.5_MHz_XTAL Microbee */
13'516'800, /* 13.5168_MHz_XTAL Kontron KDT6 */
+ 13'560'000, /* 13.560_MHz_XTAL Tong Zi Maque */
13'608'000, /* 13.608_MHz_XTAL TeleVideo 910 & 925 */
13'824'000, /* 13.824_MHz_XTAL Robotron PC-1715 display circuit */
+ 13'977'600, /* 13.9776_MHz_XTAL Kaypro II dot clock */
14'000'000, /* 14_MHz_XTAL - */
14'112'000, /* 14.112_MHz_XTAL Timex/Sinclair TS2068 */
14'192'640, /* 14.19264_MHz_XTAL Central Data 2650 */
14'218'000, /* 14.218_MHz_XTAL Dragon */
+ 14'250'450, /* 14.25045_MHz_XTAL Apple II Europlus */
14'300'000, /* 14.3_MHz_XTAL Agat-7 */
14'314'000, /* 14.314_MHz_XTAL Taito TTL Board */
14'318'181, /* 14.318181_MHz_XTAL Extremely common, used on 100's of PCBs (4x NTSC subcarrier) */
14'349'600, /* 14.3496_MHz_XTAL Roland S-50 VDP */
+ 14'469'000, /* 14.469_MHz_XTAL Esprit Systems Executive 10/102 */
14'580'000, /* 14.58_MHz_XTAL Fortune 32:16 Video Controller */
14'705'882, /* 14.705882_MHz_XTAL Aleck64 */
14'728'000, /* 14.728_MHz_XTAL ADM 36 */
14'742'800, /* 14.7428_MHz_XTAL ADM 23 */
14'745'000, /* 14.745_MHz_XTAL Synertek KTM-3 */
14'745'600, /* 14.7456_MHz_XTAL Namco System 12 & System Super 22/23 for JVS */
+ 14'746'000, /* 14.746_MHz_XTAL Namco System 10 MGEXIO */
14'784'000, /* 14.784_MHz_XTAL Zenith Z-29 */
14'916'000, /* 14.916_MHz_XTAL ADDS Viewpoint 122 */
14'976'000, /* 14.976_MHz_XTAL CIT-101 80-column display clock */
@@ -245,6 +261,7 @@ const double XTAL::known_xtals[] = {
15'400'000, /* 15.4_MHz_XTAL DVK KSM */
15'468'480, /* 15.46848_MHz_XTAL Bank Panic h/w, Sega G80 */
15'582'000, /* 15.582_MHz_XTAL Zentec Zephyr */
+ 15'625'000, /* 15.625_MHz_XTAL Zaccaria The Invaders */
15'667'200, /* 15.6672_MHz_XTAL Apple Macintosh */
15'700'000, /* 15.7_MHz_XTAL Motogonki */
15'741'000, /* 15.741_MHz_XTAL DECmate II 80-column display clock */
@@ -261,16 +278,20 @@ const double XTAL::known_xtals[] = {
16'364'000, /* 16.364_MHz_XTAL Corvus Concept */
16'384'000, /* 16.384_MHz_XTAL - */
16'400'000, /* 16.4_MHz_XTAL MS 6102 */
+ 16'537'000, /* 16.537_MHz_XTAL Falco terminals 80-column clock */
16'572'000, /* 16.572_MHz_XTAL Micro-Term ACT-5A */
16'588'800, /* 16.5888_MHz_XTAL SM 7238 */
16'666'600, /* 16.6666_MHz_XTAL Firebeat GCU */
+ 16'667'000, /* 16.667_MHz_XTAL Visual XDS-19P */
16'669'800, /* 16.6698_MHz_XTAL Qume QVT-102 */
16'670'000, /* 16.67_MHz_XTAL - */
16'777'216, /* 16.777216_MHz_XTAL Nintendo Game Boy Advance */
16'934'400, /* 16.9344_MHz_XTAL Usually used to drive 90's Yamaha OPL/FM chips (44100 * 384) */
+ 16'960'000, /* 16.960_MHz_XTAL Esprit Systems Executive 10/102 */
17'010'000, /* 17.01_MHz_XTAL Epic 14E */
17'064'000, /* 17.064_MHz_XTAL Memorex 1377 */
17'074'800, /* 17.0748_MHz_XTAL SWTPC 8212 */
+ 17'320'000, /* 17.320_MHz_XTAL Visual 50 */
17'350'000, /* 17.35_MHz_XTAL ITT Courier 1700 */
17'360'000, /* 17.36_MHz_XTAL OMTI Series 10 SCSI controller */
17'430'000, /* 17.43_MHz_XTAL Videx Videoterm */
@@ -304,6 +325,7 @@ const double XTAL::known_xtals[] = {
20'000'000, /* 20_MHz_XTAL - */
20'160'000, /* 20.16_MHz_XTAL Nintendo 8080 */
20'275'200, /* 20.2752_MHz_XTAL TRS-80 Model III */
+ 20'282'000, /* 20.282_MHz_XTAL Northwest Digitial Systems GP-19 */
20'375'040, /* 20.37504_MHz_XTAL Apple Lisa dot clock (197-0019A) */
20'625'000, /* 20.625_MHz_XTAL SM 7238 */
20'790'000, /* 20.79_MHz_XTAL Blockade-hardware Gremlin games */
@@ -326,13 +348,16 @@ const double XTAL::known_xtals[] = {
22'321'000, /* 22.321_MHz_XTAL Apple LaserWriter II NT */
22'464'000, /* 22.464_MHz_XTAL CIT-101 132-column display clock */
22'579'000, /* 22.579_MHz_XTAL Sega System H1 SCSP clock */
+ 22'579'200, /* 22.5792_MHz_XTAL Enhanced Apple Digital Sound Chip clock (44100 * 512) */
22'656'000, /* 22.656_MHz_XTAL Super Pinball Action (~1440x NTSC line rate) */
+ 22'680'000, /* 22.680_MHz_XTAL HDS200 80-columns display clock */
22'896'000, /* 22.896_MHz_XTAL DEC VT220 132-column display clock */
23'200'000, /* 23.2_MHz_XTAL Roland JV-80 & JV-880 PCM clock */
23'814'000, /* 23.814_MHz_XTAL TeleVideo TVI-912, 920 & 950 */
23'961'600, /* 23.9616_MHz_XTAL Osborne 4 (Vixen) */
24'000'000, /* 24_MHz_XTAL Mario, 80's Data East games, 80's Konami games */
24'073'400, /* 24.0734_MHz_XTAL DEC Rainbow 100 */
+ 24'167'829, /* 24.167829_MHz_XTAL Neo Geo AES rev. 3-3 and later (~1536x NTSC line rate) */
24'270'000, /* 24.27_MHz_XTAL CIT-101XL */
24'300'000, /* 24.3_MHz_XTAL ADM 36 132-column display clock */
24'576'000, /* 24.576_MHz_XTAL Pole Position h/w, Model 3 CPU board */
@@ -355,7 +380,9 @@ const double XTAL::known_xtals[] = {
26'601'712, /* 26.601712_MHz_XTAL Astro Corp.'s Show Hand, PAL Vtech/Yeno Socrates (6x PAL subcarrier) */
26'666'000, /* 26.666_MHz_XTAL Imagetek I4220/I4300 */
26'666'666, /* 26.666666_MHz_XTAL Irem M92 but most use 27MHz */
+ 26'670'000, /* 26.670_MHz_XTAL Namco EVA */
26'686'000, /* 26.686_MHz_XTAL Typically used on 90's Taito PCBs to drive the custom chips */
+ 26'824'000, /* 26.824_MHz_XTAL Astro Corp.'s Zoo */
26'880'000, /* 26.88_MHz_XTAL Roland RF5C36/SA-16 clock (30000 * 896) */
26'989'200, /* 26.9892_MHz_XTAL TeleVideo 965 */
27'000'000, /* 27_MHz_XTAL Some Banpresto games macrossp, Irem M92 and 90's Toaplan games */
@@ -371,7 +398,7 @@ const double XTAL::known_xtals[] = {
28'475'000, /* 28.475_MHz_XTAL CoCo 3 PAL */
28'480'000, /* 28.48_MHz_XTAL Chromatics CGC-7900 */
28'636'000, /* 28.636_MHz_XTAL Super Kaneko Nova System */
- 28'636'363, /* 28.636363_MHz_XTAL Later Leland games and Atari GT, Amiga NTSC, Raiden2 h/w (8x NTSC subcarrier)*/
+ 28'636'363, /* 28.636363_MHz_XTAL Later Leland games and Atari GT, Amiga NTSC, Raiden2 h/w (8x NTSC subcarrier), NEC PC-88xx */
28'640'000, /* 28.64_MHz_XTAL Fuuki FG-1c AI AM-2 PCB */
28'700'000, /* 28.7_MHz_XTAL - */
29'376'000, /* 29.376_MHz_XTAL Qume QVT-103 */
@@ -391,6 +418,7 @@ const double XTAL::known_xtals[] = {
32'256'000, /* 32.256_MHz_XTAL Hitachi MB-6890 */
32'317'400, /* 32.3174_MHz_XTAL DEC VT330, VT340 */
32'530'470, /* 32.53047_MHz_XTAL Seta 2 */
+ 32'640'000, /* 32.64_MHz_XTAL Vector 4 */
32'768'000, /* 32.768_MHz_XTAL Roland D-50 audio clock */
33'000'000, /* 33_MHz_XTAL Sega Model 3 video board */
33'264'000, /* 33.264_MHz_XTAL Hazeltine 1500 terminal */
@@ -402,6 +430,8 @@ const double XTAL::known_xtals[] = {
34'000'000, /* 34_MHz_XTAL Gaelco PCBs */
34'291'712, /* 34.291712_MHz_XTAL Fairlight CMI master card */
34'846'000, /* 34.846_MHz_XTAL Visual 550 */
+ 35'469'000, /* 35.469_MHz_XTAL ZX Spectrum +2/+3 (~8x PAL subcarrier) */
+ 35'640'000, /* 35.640_MHz_XTAL HDS200 132-column display clock */
35'834'400, /* 35.8344_MHz_XTAL Tab Products E-22 132-column display clock */
35'840'000, /* 35.84_MHz_XTAL Akai MPC 60 voice PCB */
35'904'000, /* 35.904_MHz_XTAL Used on HP98543 graphics board */
@@ -450,6 +480,7 @@ const double XTAL::known_xtals[] = {
57'272'727, /* 57.272727_MHz_XTAL Psikyo SH2 with /2 divider (16x NTSC subcarrier)*/
57'283'200, /* 57.2832_MHz_XTAL Macintosh IIci RBV, 15-inch portrait display */
58'000'000, /* 58_MHz_XTAL Magic Reel (Play System) */
+ 58'982'400, /* 58.9824_MHz_XTAL Wyse WY-65 */
59'292'000, /* 59.292_MHz_XTAL Data General D461 */
60'000'000, /* 60_MHz_XTAL ARM610 */
61'440'000, /* 61.44_MHz_XTAL Donkey Kong */
@@ -463,6 +494,7 @@ const double XTAL::known_xtals[] = {
72'000'000, /* 72_MHz_XTAL Aristocrat MKV */
72'576'000, /* 72.576_MHz_XTAL Centipede, Millipede, Missile Command, Let's Go Bowling "Multipede" */
73'728'000, /* 73.728_MHz_XTAL Ms. Pac-Man/Galaga 20th Anniversary */
+ 75'000'000, /* 75_MHz_XTAL Sony NEWS NWS-5000X */
77'414'400, /* 77.4144_MHz_XTAL NCD17c */
80'000'000, /* 80_MHz_XTAL ARM710 */
87'183'360, /* 87.18336_MHz_XTAL AT&T 630 MTG */
@@ -473,6 +505,7 @@ const double XTAL::known_xtals[] = {
101'491'200, /* 101.4912_MHz_XTAL PSX-based Namco System 10 */
105'561'000, /* 105.561_MHz_XTAL Sun cgsix */
108'108'000, /* 108.108_MHz_XTAL HP 98550 high-res color card */
+ 120'000'000, /* 120_MHz_XTAL Astro Corp.'s Stone Age */
200'000'000 /* 200_MHz_XTAL Base SH4 CPU (Naomi, Hikaru etc.) */
};