summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-04-09 03:04:35 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-04-09 03:04:35 -0700
commitb8c568b279f9ebaedac014d51eb48ed9b530566a (patch)
tree2b7ece212eedac9271d6603bae4566b805411ccf
parentadf5af551b54e165d9d95370cc569f4bf63b54bc (diff)
Created new hierarchical save_registrar, which supports self-describing structs and arrays. Converted several core files and structures over to using it. Currently just for testing.
-rw-r--r--src/emu/attotime.cpp11
-rw-r--r--src/emu/attotime.h3
-rw-r--r--src/emu/bookkeeping.cpp6
-rw-r--r--src/emu/bookkeeping.h10
-rw-r--r--src/emu/device.cpp48
-rw-r--r--src/emu/device.h28
-rw-r--r--src/emu/diexec.cpp34
-rw-r--r--src/emu/diexec.h8
-rw-r--r--src/emu/dinetwork.cpp5
-rw-r--r--src/emu/dinetwork.h2
-rw-r--r--src/emu/dipalette.cpp23
-rw-r--r--src/emu/dipalette.h1
-rw-r--r--src/emu/dirom.h2
-rw-r--r--src/emu/dirom.ipp9
-rw-r--r--src/emu/diserial.cpp43
-rw-r--r--src/emu/diserial.h15
-rw-r--r--src/emu/divtlb.cpp12
-rw-r--r--src/emu/divtlb.h2
-rw-r--r--src/emu/driver.cpp4
-rw-r--r--src/emu/driver.h5
-rw-r--r--src/emu/emufwd.h3
-rw-r--r--src/emu/machine.cpp24
-rw-r--r--src/emu/machine.h3
-rw-r--r--src/emu/output.cpp7
-rw-r--r--src/emu/output.h5
-rw-r--r--src/emu/save.cpp336
-rw-r--r--src/emu/save.h221
-rw-r--r--src/emu/screen.cpp16
-rw-r--r--src/emu/screen.h16
-rw-r--r--src/emu/sound.cpp25
-rw-r--r--src/emu/sound.h35
-rw-r--r--src/emu/tilemap.cpp63
-rw-r--r--src/emu/tilemap.h50
33 files changed, 898 insertions, 177 deletions
diff --git a/src/emu/attotime.cpp b/src/emu/attotime.cpp
index a1ba4d9ed61..d25de380ab0 100644
--- a/src/emu/attotime.cpp
+++ b/src/emu/attotime.cpp
@@ -8,9 +8,7 @@
***************************************************************************/
-#include "emucore.h"
-#include "eminline.h"
-#include "attotime.h"
+#include "emu.h"
//**************************************************************************
// GLOBAL VARIABLES
@@ -170,3 +168,10 @@ std::string attotime::to_string() const
int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
return util::string_format("%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
}
+
+
+void attotime::register_save(save_registrar &save)
+{
+ save.reg(NAME(m_seconds))
+ .reg(NAME(m_attoseconds));
+}
diff --git a/src/emu/attotime.h b/src/emu/attotime.h
index c6fa441733c..f77f05edad1 100644
--- a/src/emu/attotime.h
+++ b/src/emu/attotime.h
@@ -164,6 +164,9 @@ public:
attotime &operator*=(u32 factor);
attotime &operator/=(u32 factor);
+ // save registration
+ void register_save(save_registrar &save);
+
// members
seconds_t m_seconds;
attoseconds_t m_attoseconds;
diff --git a/src/emu/bookkeeping.cpp b/src/emu/bookkeeping.cpp
index a26cf771c7e..c82e265ed1f 100644
--- a/src/emu/bookkeeping.cpp
+++ b/src/emu/bookkeeping.cpp
@@ -32,12 +32,6 @@ bookkeeping_manager::bookkeeping_manager(running_machine &machine)
m_coin_count[counternum] = 0;
}
- // register coin save state
- machine.save().save_item(NAME(m_coin_count));
- machine.save().save_item(NAME(m_coinlockedout));
- machine.save().save_item(NAME(m_lastcoin));
- machine.save().save_item(NAME(m_dispensed_tickets));
-
// register for configuration
machine.configuration().config_register("counters", config_load_delegate(&bookkeeping_manager::config_load, this), config_save_delegate(&bookkeeping_manager::config_save, this));
}
diff --git a/src/emu/bookkeeping.h b/src/emu/bookkeeping.h
index 760789fd536..d9cfa4c1f28 100644
--- a/src/emu/bookkeeping.h
+++ b/src/emu/bookkeeping.h
@@ -56,6 +56,16 @@ public:
// getters
running_machine &machine() const { return m_machine; }
+
+ // save states
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_coin_count))
+ .reg(NAME(m_coinlockedout))
+ .reg(NAME(m_lastcoin))
+ .reg(NAME(m_dispensed_tickets));
+ }
+
private:
void config_load(config_type cfg_type, util::xml::data_node const *parentnode);
void config_save(config_type cfg_type, util::xml::data_node *parentnode);
diff --git a/src/emu/device.cpp b/src/emu/device.cpp
index 51088b02d4a..edcfa116562 100644
--- a/src/emu/device.cpp
+++ b/src/emu/device.cpp
@@ -606,11 +606,6 @@ void device_t::start()
debug_setup();
}
- // register our save states
- save_item(NAME(m_clock));
- save_item(NAME(m_unscaled_clock));
- save_item(NAME(m_clock_scale));
-
// have the views register their state
if (!m_viewlist.empty())
osd_printf_verbose("%s: Registering %d views\n", m_tag, int(m_viewlist.size()));
@@ -696,6 +691,27 @@ void device_t::post_load()
//-------------------------------------------------
+// register_save - tell the device and its
+// interfaces to register their save states
+//-------------------------------------------------
+
+void device_t::register_save(save_registrar &save)
+{
+ // register our save states
+ save.reg(NAME(m_clock))
+ .reg(NAME(m_unscaled_clock))
+ .reg(NAME(m_clock_scale));
+
+ // notify the interface
+ for (device_interface &intf : interfaces())
+ intf.interface_register_save(save);
+
+ // notify the device
+ device_register_save(save);
+}
+
+
+//-------------------------------------------------
// notify_clock_changed - notify all interfaces
// that the clock has changed
//-------------------------------------------------
@@ -842,6 +858,17 @@ void device_t::device_post_load()
//-------------------------------------------------
+// device_register_save - called after startup
+// to register any state to be saved
+//-------------------------------------------------
+
+void device_t::device_register_save(save_registrar &save)
+{
+ // do nothing by default
+}
+
+
+//-------------------------------------------------
// device_clock_changed - called when the
// device clock is altered in any way; designed
// to be overridden by the actual device
@@ -1167,6 +1194,17 @@ void device_interface::interface_post_load()
//-------------------------------------------------
+// interface_register_save - called after startup
+// to register any state to be saved
+//-------------------------------------------------
+
+void device_interface::interface_register_save(save_registrar &save)
+{
+ // do nothing by default
+}
+
+
+//-------------------------------------------------
// interface_clock_changed - called when the
// device clock is altered in any way; designed
// to be overridden by the actual device
diff --git a/src/emu/device.h b/src/emu/device.h
index 774930690b7..41e99c461a8 100644
--- a/src/emu/device.h
+++ b/src/emu/device.h
@@ -614,28 +614,42 @@ public:
// state saving interfaces
template<typename ItemType>
- void ATTR_COLD save_item(ItemType &value, const char *valname, int index = 0)
+ void ATTR_COLD save_item(ItemType &value, const char *valname, int index = -1)
{
assert(m_save);
- m_save->save_item(this, name(), tag(), index, value, valname);
+ m_save->save_item(this, name(), tag(), (index == -1) ? 0 : index, value, valname);
+ if (m_legacy_save.get() == nullptr)
+ m_legacy_save = std::make_unique<save_registrar>(m_save->legacy_registrar(), tag());
+ if (index == -1)
+ m_legacy_save->reg(value, valname);
+ else
+ m_legacy_save->reg(value, string_format("%s[%d]", valname, index).c_str());
}
template<typename ItemType, typename StructType, typename ElementType>
void ATTR_COLD save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0)
{
assert(m_save);
m_save->save_item(this, name(), tag(), index, value, element, valname);
+ osd_printf_warning("Legacy save_item not supported of %s:%s/%X/%s\n", tag(), name(), index, valname);
}
template<typename ItemType>
- void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
+ void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = -1)
{
assert(m_save);
- m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count);
+ m_save->save_pointer(this, name(), tag(), (index == -1) ? 0 : index, std::forward<ItemType>(value), valname, count);
+ if (m_legacy_save.get() == nullptr)
+ m_legacy_save = std::make_unique<save_registrar>(m_save->legacy_registrar(), tag());
+ if (index == -1)
+ m_legacy_save->reg(value, valname, count);
+ else
+ m_legacy_save->reg(value, string_format("%s[%d]", valname, index).c_str(), count);
}
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);
m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), element, valname, count);
+ osd_printf_warning("Legacy save_pointer not supported of %s:%s/%X/%s\n", tag(), name(), index, valname);
}
// debugging
@@ -649,6 +663,9 @@ public:
template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const;
void view_register(memory_view *view);
+ // save helpers
+ virtual void register_save(save_registrar &save) final;
+
protected:
// miscellaneous helpers
void set_machine(running_machine &machine);
@@ -798,6 +815,7 @@ 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);
+ virtual void device_register_save(save_registrar &save);
//------------------- end derived class overrides
@@ -841,6 +859,7 @@ private:
mutable std::vector<rom_entry> m_rom_entries;
std::list<devcb_base *> m_callbacks;
std::vector<memory_view *> m_viewlist; // list of views
+ std::unique_ptr<save_registrar> m_legacy_save; // bucket for legacy save stuff
// string formatting buffer for logerror
mutable util::ovectorstream m_string_buffer;
@@ -1004,6 +1023,7 @@ public:
virtual void interface_clock_changed();
virtual void interface_debug_setup();
+ virtual void interface_register_save(save_registrar &save);
private:
// internal state
diff --git a/src/emu/diexec.cpp b/src/emu/diexec.cpp
index 49dee5f650e..799626fad3e 100644
--- a/src/emu/diexec.cpp
+++ b/src/emu/diexec.cpp
@@ -401,20 +401,6 @@ void device_execute_interface::interface_post_start()
if (!m_icountptr)
throw emu_fatalerror("m_icountptr never initialized!");
- // register for save states
- device().save_item(NAME(m_suspend));
- device().save_item(NAME(m_nextsuspend));
- device().save_item(NAME(m_eatcycles));
- device().save_item(NAME(m_nexteatcycles));
- device().save_item(NAME(m_trigger));
- device().save_item(NAME(m_totalcycles));
- device().save_item(NAME(m_localtime));
-
- // it's more efficient and causes less clutter to save these this way
- device().save_item(STRUCT_MEMBER(m_input, m_stored_vector));
- device().save_item(STRUCT_MEMBER(m_input, m_curvector));
- device().save_item(STRUCT_MEMBER(m_input, m_curstate));
-
// fill in the input states and IRQ callback information
for (int line = 0; line < std::size(m_input); line++)
m_input[line].start(*this, line);
@@ -508,6 +494,26 @@ void device_execute_interface::interface_clock_changed()
//-------------------------------------------------
+// interface_register_save - register items for
+// saving
+//-------------------------------------------------
+
+void device_execute_interface::interface_register_save(save_registrar &save)
+{
+ // put execute items in their own container
+ save_registrar(save, "execute")
+ .reg(NAME(m_suspend))
+ .reg(NAME(m_nextsuspend))
+ .reg(NAME(m_eatcycles))
+ .reg(NAME(m_nexteatcycles))
+ .reg(NAME(m_trigger))
+ .reg(NAME(m_totalcycles))
+ .reg(NAME(m_localtime))
+ .reg(NAME(m_input));
+}
+
+
+//-------------------------------------------------
// standard_irq_callback_member - IRQ acknowledge
// callback; handles HOLD_LINE case and signals
// to the debugger
diff --git a/src/emu/diexec.h b/src/emu/diexec.h
index 065248a9046..e94824c4ac5 100644
--- a/src/emu/diexec.h
+++ b/src/emu/diexec.h
@@ -217,6 +217,7 @@ protected:
virtual void interface_pre_reset() override;
virtual void interface_post_reset() override;
virtual void interface_clock_changed() override;
+ virtual void interface_register_save(save_registrar &save) override;
// for use by devcpu for now...
int current_input_state(unsigned i) const { return m_input[i].m_curstate; }
@@ -268,6 +269,13 @@ private:
s32 m_queue[32]; // queue of pending events
int m_qindex; // index within the queue
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_stored_vector));
+ save.reg(NAME(m_curvector));
+ save.reg(NAME(m_curstate));
+ }
+
private:
TIMER_CALLBACK_MEMBER(empty_event_queue);
};
diff --git a/src/emu/dinetwork.cpp b/src/emu/dinetwork.cpp
index 6e10e28ecbd..c9a81908b78 100644
--- a/src/emu/dinetwork.cpp
+++ b/src/emu/dinetwork.cpp
@@ -23,9 +23,10 @@ void device_network_interface::interface_pre_start()
m_recv_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_network_interface::recv_complete), this));
}
-void device_network_interface::interface_post_start()
+void device_network_interface::interface_register_save(save_registrar &save)
{
- device().save_item(NAME(m_loopback_control));
+ save_registrar(save, "network")
+ .reg(NAME(m_loopback_control));
}
int device_network_interface::send(u8 *buf, int len)
diff --git a/src/emu/dinetwork.h b/src/emu/dinetwork.h
index d165d752852..b2c0d692440 100644
--- a/src/emu/dinetwork.h
+++ b/src/emu/dinetwork.h
@@ -12,7 +12,7 @@ public:
virtual ~device_network_interface();
void interface_pre_start() override;
- void interface_post_start() override;
+ void interface_register_save(save_registrar &save) override;
void set_interface(int id);
void set_promisc(bool promisc);
diff --git a/src/emu/dipalette.cpp b/src/emu/dipalette.cpp
index 7cd58665a4d..d75a5ec598f 100644
--- a/src/emu/dipalette.cpp
+++ b/src/emu/dipalette.cpp
@@ -91,15 +91,26 @@ void device_palette_interface::interface_post_start()
// set up save/restore of the palette
m_save_pen.resize(m_palette->num_colors());
m_save_contrast.resize(m_palette->num_colors());
- device().save_item(NAME(m_save_pen));
- device().save_item(NAME(m_save_contrast));
+}
+
+
+
+//-------------------------------------------------
+// interface_register_save - register for save
+// states
+//-------------------------------------------------
+
+void device_palette_interface::interface_register_save(save_registrar &save)
+{
+ save_registrar container(save, "palette");
// save indirection tables if we have them
+ container.reg(NAME(m_save_pen))
+ .reg(NAME(m_save_contrast));
+
if (m_indirect_colors.size() > 0)
- {
- device().save_item(NAME(m_indirect_colors));
- device().save_item(NAME(m_indirect_pens));
- }
+ container.reg(NAME(m_indirect_colors))
+ .reg(NAME(m_indirect_pens));
}
diff --git a/src/emu/dipalette.h b/src/emu/dipalette.h
index 1e84b2848e8..0e70e367ea8 100644
--- a/src/emu/dipalette.h
+++ b/src/emu/dipalette.h
@@ -90,6 +90,7 @@ protected:
virtual void interface_pre_save() override;
virtual void interface_post_load() override;
virtual void interface_post_stop() override;
+ virtual void interface_register_save(save_registrar &save) override;
// configuration-related overrides
virtual u32 palette_entries() const = 0;
diff --git a/src/emu/dirom.h b/src/emu/dirom.h
index 8243400c547..8d5d64442a3 100644
--- a/src/emu/dirom.h
+++ b/src/emu/dirom.h
@@ -48,7 +48,7 @@ private:
virtual void interface_validity_check(validity_checker &valid) const override;
virtual void interface_pre_start() override;
virtual void interface_post_start() override;
- virtual void interface_post_load() override;
+ virtual void interface_register_save(save_registrar &save) override;
};
#include "dirom.ipp"
diff --git a/src/emu/dirom.ipp b/src/emu/dirom.ipp
index 24697a0fbba..f6460e84d33 100644
--- a/src/emu/dirom.ipp
+++ b/src/emu/dirom.ipp
@@ -132,12 +132,13 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::interface_pr
}
template<int AddrWidth, int DataWidth, int AddrShift, endianness_t Endian>
-void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::interface_post_start()
+void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::interface_register_save(save_registrar &save)
{
- device_memory_interface::interface_post_start();
+ device_memory_interface::interface_register_save(save);
- device().save_item(NAME(m_cur_bank));
- device().save_item(NAME(m_bank_count));
+ save_registrar(save, "rom")
+ .reg(NAME(m_cur_bank))
+ .reg(NAME(m_bank_count));
}
#endif // MAME_EMU_DIROM_IPP
diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp
index 21da108c045..a4731150862 100644
--- a/src/emu/diserial.cpp
+++ b/src/emu/diserial.cpp
@@ -75,28 +75,29 @@ void device_serial_interface::interface_pre_start()
m_tra_clock_state = false;
}
-void device_serial_interface::interface_post_start()
+void device_serial_interface::interface_register_save(save_registrar &save)
{
- device().save_item(NAME(m_df_start_bit_count));
- device().save_item(NAME(m_df_word_length));
- device().save_item(NAME(m_df_parity));
- device().save_item(NAME(m_df_stop_bit_count));
- device().save_item(NAME(m_rcv_register_data));
- device().save_item(NAME(m_rcv_flags));
- device().save_item(NAME(m_rcv_bit_count_received));
- device().save_item(NAME(m_rcv_bit_count));
- device().save_item(NAME(m_rcv_byte_received));
- device().save_item(NAME(m_rcv_framing_error));
- device().save_item(NAME(m_rcv_parity_error));
- device().save_item(NAME(m_tra_register_data));
- device().save_item(NAME(m_tra_flags));
- device().save_item(NAME(m_tra_bit_count_transmitted));
- device().save_item(NAME(m_tra_bit_count));
- device().save_item(NAME(m_rcv_rate));
- device().save_item(NAME(m_tra_rate));
- device().save_item(NAME(m_rcv_line));
- device().save_item(NAME(m_tra_clock_state));
- device().save_item(NAME(m_rcv_clock_state));
+ save_registrar(save, "serial")
+ .reg(NAME(m_df_start_bit_count))
+ .reg(NAME(m_df_word_length))
+ .reg(NAME(m_df_parity))
+ .reg(NAME(m_df_stop_bit_count))
+ .reg(NAME(m_rcv_register_data))
+ .reg(NAME(m_rcv_flags))
+ .reg(NAME(m_rcv_bit_count_received))
+ .reg(NAME(m_rcv_bit_count))
+ .reg(NAME(m_rcv_byte_received))
+ .reg(NAME(m_rcv_framing_error))
+ .reg(NAME(m_rcv_parity_error))
+ .reg(NAME(m_tra_register_data))
+ .reg(NAME(m_tra_flags))
+ .reg(NAME(m_tra_bit_count_transmitted))
+ .reg(NAME(m_tra_bit_count))
+ .reg(NAME(m_rcv_rate))
+ .reg(NAME(m_tra_rate))
+ .reg(NAME(m_rcv_line))
+ .reg(NAME(m_tra_clock_state))
+ .reg(NAME(m_rcv_clock_state));
}
void device_serial_interface::set_rcv_rate(const attotime &rate)
diff --git a/src/emu/diserial.h b/src/emu/diserial.h
index 62b13c028a1..b21eb064d03 100644
--- a/src/emu/diserial.h
+++ b/src/emu/diserial.h
@@ -121,7 +121,7 @@ protected:
// interface-level overrides
virtual void interface_pre_start() override;
- virtual void interface_post_start() override;
+ virtual void interface_register_save(save_registrar &save) override;
bool m_start_bit_hack_for_external_clocks;
@@ -188,14 +188,15 @@ class device_buffered_serial_interface : public device_serial_interface
protected:
using device_serial_interface::device_serial_interface;
- void interface_post_start() override
+ void interface_register_save(save_registrar &save) override
{
- device_serial_interface::interface_post_start();
+ device_serial_interface::interface_register_save(save);
- device().save_item(NAME(m_fifo));
- device().save_item(NAME(m_head));
- device().save_item(NAME(m_tail));
- device().save_item(NAME(m_empty));
+ save_registrar(save, "buffered_serial")
+ .reg(NAME(m_fifo))
+ .reg(NAME(m_head))
+ .reg(NAME(m_tail))
+ .reg(NAME(m_empty));
}
virtual void tra_complete() override
diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp
index a09abd5300a..df880676927 100644
--- a/src/emu/divtlb.cpp
+++ b/src/emu/divtlb.cpp
@@ -112,13 +112,15 @@ void device_vtlb_interface::interface_pre_start()
// actually starting a device
//-------------------------------------------------
-void device_vtlb_interface::interface_post_start()
+void device_vtlb_interface::interface_register_save(save_registrar &save)
{
- device().save_item(NAME(m_live));
- device().save_item(NAME(m_table));
- device().save_item(NAME(m_refcnt));
+ save_registrar container(save, "vtlb");
+
+ container.reg(NAME(m_live))
+ .reg(NAME(m_table))
+ .reg(NAME(m_refcnt));
if (m_fixed > 0)
- device().save_item(NAME(m_fixedpages));
+ container.reg(NAME(m_fixedpages));
}
diff --git a/src/emu/divtlb.h b/src/emu/divtlb.h
index c64bca0a21c..c5070c277fe 100644
--- a/src/emu/divtlb.h
+++ b/src/emu/divtlb.h
@@ -69,8 +69,8 @@ protected:
// interface-level overrides
virtual void interface_validity_check(validity_checker &valid) const override;
virtual void interface_pre_start() override;
- virtual void interface_post_start() override;
virtual void interface_pre_reset() override;
+ virtual void interface_register_save(save_registrar &save) override;
private:
// private state
diff --git a/src/emu/driver.cpp b/src/emu/driver.cpp
index 04c6489aae3..b8b22be27ab 100644
--- a/src/emu/driver.cpp
+++ b/src/emu/driver.cpp
@@ -235,10 +235,6 @@ void driver_device::device_start()
m_callbacks[CB_VIDEO_START]();
else
video_start();
-
- // save generic states
- save_item(NAME(m_flip_screen_x));
- save_item(NAME(m_flip_screen_y));
}
diff --git a/src/emu/driver.h b/src/emu/driver.h
index 43697f2d109..a077dae6036 100644
--- a/src/emu/driver.h
+++ b/src/emu/driver.h
@@ -158,6 +158,11 @@ protected:
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
virtual void device_reset_after_children() override;
+ virtual void device_register_save(save_registrar &save) override
+ {
+ save.reg(NAME(m_flip_screen_x))
+ .reg(NAME(m_flip_screen_y));
+ }
// generic video
void flip_screen_set(u32 on);
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index a487af49b21..d33bd637927 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -209,6 +209,9 @@ class rom_entry;
// declared in romload.h
class rom_load_manager;
+// declared in save.h
+class save_registrar;
+
// declared in schedule.h
class device_scheduler;
class emu_timer;
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index aecaf26ed15..488c3519409 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -238,9 +238,6 @@ void running_machine::start()
m_rom_load = std::make_unique<rom_load_manager>(*this);
m_memory.initialize();
- // save the random seed or save states might be broken in drivers that use the rand() method
- save().save_item(NAME(m_rand_seed));
-
// initialize image devices
m_image = std::make_unique<image_manager>(*this);
m_tilemap = std::make_unique<tilemap_manager>(*this);
@@ -263,13 +260,18 @@ void running_machine::start()
// register callbacks for the devices, then start them
add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&running_machine::reset_all_devices, this));
add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&running_machine::stop_all_devices, this));
+ save_registrar device_registrar(m_save.root_registrar(), "devices");
save().register_presave(save_prepost_delegate(FUNC(running_machine::presave_all_devices), this));
start_all_devices();
+ for (device_t &device : device_enumerator(root_device()))
+ device_registrar.reg(device, device.tag());
save().register_postload(save_prepost_delegate(FUNC(running_machine::postload_all_devices), this));
// save outputs created before start time
output().register_save();
+ m_save.root_registrar().reg(*this, "machine");
+
m_render->resolve_tags();
// load cheat files
@@ -294,6 +296,8 @@ void running_machine::start()
schedule_load("auto");
manager().update_machine();
+
+ m_save.test_dump();
}
@@ -1131,6 +1135,20 @@ void running_machine::postload_all_devices()
}
+//-------------------------------------------------
+// register_save - register items for save states
+//-------------------------------------------------
+
+void running_machine::register_save(save_registrar &save)
+{
+ save.reg(NAME(m_rand_seed))
+ .reg(NAME(m_output))
+ .reg(NAME(m_sound))
+ .reg(NAME(m_tilemap))
+ .reg(NAME(m_bookkeeping));
+}
+
+
/***************************************************************************
NVRAM MANAGEMENT
***************************************************************************/
diff --git a/src/emu/machine.h b/src/emu/machine.h
index 37a5702c72e..8be9badb181 100644
--- a/src/emu/machine.h
+++ b/src/emu/machine.h
@@ -270,6 +270,9 @@ public:
// used by debug_console to take ownership of the debug.log file
std::unique_ptr<emu_file> steal_debuglogfile() { return std::move(m_debuglogfile); }
+ // state saving
+ void register_save(save_registrar &save);
+
private:
class side_effects_disabler {
running_machine *m_machine;
diff --git a/src/emu/output.cpp b/src/emu/output.cpp
index 3fe5d7629a4..65378d2e525 100644
--- a/src/emu/output.cpp
+++ b/src/emu/output.cpp
@@ -94,12 +94,11 @@ output_manager::output_manager(running_machine &machine)
void output_manager::register_save()
{
assert(m_save_order.empty());
- assert(!m_save_data);
// make space for the data
m_save_order.clear();
m_save_order.reserve(m_itemtable.size());
- m_save_data = std::make_unique<s32 []>(m_itemtable.size());
+ m_save_data.resize(m_itemtable.size());
// sort existing outputs by name and register for save
for (auto &item : m_itemtable)
@@ -107,7 +106,7 @@ void output_manager::register_save()
std::sort(m_save_order.begin(), m_save_order.end(), [] (auto const &l, auto const &r) { return l.get().name() < r.get().name(); });
// register the reserved space for saving
- machine().save().save_pointer(nullptr, "output", nullptr, 0, NAME(m_save_data), m_itemtable.size());
+ machine().save().save_pointer(nullptr, "output", nullptr, 0, NAME(&m_save_data[0]), m_itemtable.size());
if (OUTPUT_VERBOSE)
osd_printf_verbose("Registered %u outputs for save states\n", m_itemtable.size());
@@ -135,7 +134,7 @@ output_manager::output_item *output_manager::find_item(std::string_view string)
output_manager::output_item &output_manager::create_new_item(std::string_view outname, s32 value)
{
if (OUTPUT_VERBOSE)
- osd_printf_verbose("Creating output %s = %d%s\n", outname, value, m_save_data ? " (will not be saved)" : "");
+ osd_printf_verbose("Creating output %s = %d%s\n", outname, value, m_machine.save().registration_allowed() ? "" : " (will not be saved)");
auto const ins(m_itemtable.emplace(
std::piecewise_construct,
diff --git a/src/emu/output.h b/src/emu/output.h
index 3571cc1f24b..e13b9b07697 100644
--- a/src/emu/output.h
+++ b/src/emu/output.h
@@ -193,6 +193,9 @@ public:
// map a unique ID back to a name
const char *id_to_name(u32 id);
+ // state saving
+ void register_save(save_registrar &save) { save.reg(NAME(m_save_data)); }
+
private:
output_item *find_item(std::string_view string);
output_item &create_new_item(std::string_view outname, s32 value);
@@ -209,7 +212,7 @@ private:
std::unordered_map<std::string, output_item> m_itemtable;
notify_vector m_global_notifylist;
std::vector<std::reference_wrapper<output_item> > m_save_order;
- std::unique_ptr<s32 []> m_save_data;
+ std::vector<s32> m_save_data;
u32 m_uniqueid;
};
diff --git a/src/emu/save.cpp b/src/emu/save.cpp
index 96fb3429a1c..e0e51bea359 100644
--- a/src/emu/save.cpp
+++ b/src/emu/save.cpp
@@ -26,6 +26,8 @@
#include "emuopts.h"
#include "coreutil.h"
+#include <iomanip>
+
//**************************************************************************
// DEBUGGING
@@ -64,6 +66,8 @@ save_manager::save_manager(running_machine &machine)
: m_machine(machine)
, m_reg_allowed(true)
, m_illegal_regs(0)
+ , m_root_registrar(m_root_item)
+ , m_legacy_registrar(m_root_registrar, "legacy")
{
m_rewind = std::make_unique<rewinder>(*this);
}
@@ -1015,3 +1019,335 @@ void save_manager::state_entry::flip_data()
}
}
}
+
+
+//**************************************************************************
+// INITIALIZATION
+//**************************************************************************
+
+//-------------------------------------------------
+// save_registered_item - constructor
+//-------------------------------------------------
+
+save_registered_item::save_registered_item() :
+ m_ptr_offset(0),
+ m_type(TYPE_STRUCT),
+ m_native_size(0)
+{
+}
+
+// constructor for a new item
+save_registered_item::save_registered_item(uintptr_t ptr_offset, save_type type, uint32_t native_size, char const *name) :
+ m_ptr_offset(ptr_offset),
+ m_type(type),
+ m_native_size(native_size),
+ m_name(name)
+{
+ if (m_name[0] == 'm' && m_name[1] == '_')
+ m_name.erase(0, 2);
+}
+
+
+//-------------------------------------------------
+// append - append a new item to the current one
+//-------------------------------------------------
+
+save_registered_item &save_registered_item::append(uintptr_t ptr_offset, save_type type, uint32_t native_size, char const *name)
+{
+ m_items.emplace_back(ptr_offset, type, native_size, name);
+ return m_items.back();
+}
+
+
+//-------------------------------------------------
+// save_binary - save this item and all owned
+// items into a binary form
+//-------------------------------------------------
+
+uint64_t save_registered_item::save_binary(uint8_t *ptr, uint64_t length, uintptr_t objbase)
+{
+ // update the base pointer with our local base/offset
+ objbase += m_ptr_offset;
+
+ // switch off the type
+ uint64_t offset = 0;
+ switch (m_type)
+ {
+ // boolean types save as a single byte
+ case TYPE_BOOL:
+ if (offset + 1 <= length)
+ ptr[offset] = *reinterpret_cast<bool const *>(objbase) ? 1 : 0;
+ offset++;
+ break;
+
+ // integral/float types save as their native size
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_FLOAT:
+ if (offset + m_native_size <= length)
+ memcpy(&ptr[offset], reinterpret_cast<void const *>(objbase), m_native_size);
+ offset += m_native_size;
+ break;
+
+ // structs and containers iterate over owned items
+ case TYPE_CONTAINER:
+ objbase = 0;
+ case TYPE_STRUCT:
+ for (auto &item : m_items)
+ offset += item.save_binary(&ptr[offset], (offset < length) ? length - offset : 0, objbase);
+ break;
+
+ // arrays are multiples of a single item
+ default:
+ if (m_type < TYPE_ARRAY)
+ {
+ auto &item = m_items.front();
+ for (uint32_t rep = 0; rep < m_type; rep++)
+ offset += item.save_binary(&ptr[offset], (offset < length) ? length - offset : 0, objbase + rep * m_native_size);
+ }
+ break;
+ }
+ return offset;
+}
+
+
+//-------------------------------------------------
+// restore_binary - restore this item and all
+// owned items from binary form
+//-------------------------------------------------
+
+uint64_t save_registered_item::restore_binary(uint8_t const *ptr, uint64_t length, uintptr_t objbase)
+{
+ // update the base pointer with our local base/offset
+ objbase += m_ptr_offset;
+
+ // switch off the type
+ uint64_t offset = 0;
+ switch (m_type)
+ {
+ // boolean types save as a single byte
+ case TYPE_BOOL:
+ if (offset + 1 <= length)
+ *reinterpret_cast<bool *>(objbase) = (ptr[offset] != 0);
+ offset++;
+ break;
+
+ // integral/float types save as their native size
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_FLOAT:
+ if (offset + m_native_size <= length)
+ memcpy(reinterpret_cast<void *>(objbase), &ptr[offset], m_native_size);
+ offset += m_native_size;
+ break;
+
+ // structs and containers iterate over owned items
+ case TYPE_CONTAINER:
+ objbase = 0;
+ case TYPE_STRUCT:
+ for (auto &item : m_items)
+ offset += item.restore_binary(&ptr[offset], (offset < length) ? length - offset : 0, objbase);
+ break;
+
+ // arrays are multiples of a single item
+ default:
+ if (m_type < TYPE_ARRAY)
+ {
+ auto &item = m_items.front();
+ for (uint32_t rep = 0; rep < m_type; rep++)
+ offset += item.restore_binary(&ptr[offset], (offset < length) ? length - offset : 0, objbase + rep * m_native_size);
+ }
+ break;
+ }
+ return offset;
+}
+
+
+//-------------------------------------------------
+// save_json - save this item into a JSON stream
+//-------------------------------------------------
+
+void save_registered_item::save_json(std::ostringstream &output, int indent, bool inline_form, uintptr_t objbase)
+{
+ // update the base pointer with our local base/offset
+ objbase += m_ptr_offset;
+
+ // output the name if present
+ if (m_name.length() > 0)
+ output << "\"" << m_name << "\": ";
+
+ // switch off the type
+ switch (m_type)
+ {
+ // boolean types
+ case TYPE_BOOL:
+ output << (*reinterpret_cast<bool const *>(objbase) ? "true" : "false");
+ break;
+
+ // signed integral types
+ case TYPE_INT:
+ {
+ int64_t value = read_int_signed(objbase, m_native_size);
+ char const *quote = (value == int64_t(double(value))) ? "" : "\"";
+ output << quote << value << quote;
+ break;
+ }
+
+ // unsigned integral types
+ case TYPE_UINT:
+ {
+ uint64_t value = read_int_unsigned(objbase, m_native_size);
+ char const *quote = (value == uint64_t(double(value))) ? "" : "\"";
+ output << quote << "0x" << std::setw(m_native_size * 2) << std::setfill('0') << std::hex << value << quote;
+ output << std::setw(0) << std::setfill(' ') << std::dec;
+ break;
+ }
+
+ // float types
+ case TYPE_FLOAT:
+ {
+ double value = (m_native_size == 4) ? *reinterpret_cast<float const *>(objbase) : *reinterpret_cast<double const *>(objbase);
+ output << value;
+ break;
+ }
+
+ // structs and containers iterate over owned items
+ case TYPE_CONTAINER:
+ objbase = 0;
+ case TYPE_STRUCT:
+ if (inline_form || compute_binary_size() <= 16)
+ {
+ // inline form outputs everything on a single line
+ output << "{ ";
+ for (auto &item : m_items)
+ {
+ item.save_json(output, indent, true, objbase);
+ if (&item != &m_items.back())
+ output << ", ";
+ }
+ output << " }";
+ }
+ else
+ {
+ // normal form outputs each item on its own line, indented
+ output << "{" << std::endl;
+ for (auto &item : m_items)
+ {
+ output << std::setw(indent + 1) << std::setfill('\t') << "" << std::setw(0);
+ item.save_json(output, indent + 1, false, objbase);
+ if (&item != &m_items.back())
+ output << ",";
+ output << std::endl;
+ }
+ output << std::setw(indent) << std::setfill('\t') << "" << std::setw(0)
+ << "}";
+ }
+ break;
+
+ // arrays are multiples of a single item
+ default:
+ if (m_type < TYPE_ARRAY)
+ {
+ auto &item = m_items.front();
+ uint32_t item_size = item.compute_binary_size();
+ if (inline_form || m_type * item_size <= 16)
+ {
+ // strictly inline form outputs everything on a single line
+ output << "[ ";
+ for (uint32_t rep = 0; rep < m_type; rep++)
+ {
+ item.save_json(output, 0, true, objbase + rep * m_native_size);
+ if (rep != m_type - 1)
+ output << ",";
+ }
+ output << " ]";
+ }
+ else
+ {
+ // normal form outputs a certain number of items per row
+ output << "[" << std::endl;
+ uint32_t items_per_row = 0;
+ if (item.m_type == TYPE_INT || item.m_type == TYPE_UINT || item.m_type == TYPE_FLOAT)
+ items_per_row = 32 / item_size;
+ if (items_per_row == 0)
+ items_per_row = 1;
+
+ // iterate over the items
+ for (uint32_t rep = 0; rep < m_type; rep++)
+ {
+ if (rep % items_per_row == 0)
+ output << std::setw(indent + 1) << std::setfill('\t') << "" << std::setw(0);
+ item.save_json(output, indent + 1, false, objbase + rep * m_native_size);
+ if (rep != m_type - 1)
+ output << ",";
+ if (rep % items_per_row == items_per_row - 1)
+ output << std::endl;
+ }
+ if (m_type % items_per_row != 0)
+ output << std::endl;
+ output << std::setw(indent) << std::setfill('\t') << "" << std::setw(0)
+ << "]";
+ }
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// read_int_unsigned - read an unsigned integer
+// of the given size
+//-------------------------------------------------
+
+uint64_t save_registered_item::read_int_unsigned(uintptr_t objbase, int size)
+{
+ switch (size)
+ {
+ case 1: return *reinterpret_cast<uint8_t const *>(objbase);
+ case 2: return *reinterpret_cast<uint16_t const *>(objbase);
+ case 4: return *reinterpret_cast<uint32_t const *>(objbase);
+ case 8: return *reinterpret_cast<uint64_t const *>(objbase);
+ }
+ return 0;
+}
+
+
+//-------------------------------------------------
+// read_int_signed - read a signed integer of the
+// given size
+//-------------------------------------------------
+
+int64_t save_registered_item::read_int_signed(uintptr_t objbase, int size)
+{
+ switch (size)
+ {
+ case 1: return *reinterpret_cast<int8_t const *>(objbase);
+ case 2: return *reinterpret_cast<int16_t const *>(objbase);
+ case 4: return *reinterpret_cast<int32_t const *>(objbase);
+ case 8: return *reinterpret_cast<int64_t const *>(objbase);
+ }
+ return 0;
+}
+
+
+//-------------------------------------------------
+// write_int - write an integer of the given size
+//-------------------------------------------------
+
+void save_registered_item::write_int(uintptr_t objbase, int size, uint64_t data)
+{
+ switch (size)
+ {
+ case 1: *reinterpret_cast<uint8_t *>(objbase) = uint8_t(data); break;
+ case 2: *reinterpret_cast<uint16_t *>(objbase) = uint16_t(data); break;
+ case 4: *reinterpret_cast<uint32_t *>(objbase) = uint32_t(data); break;
+ case 8: *reinterpret_cast<uint64_t *>(objbase) = uint64_t(data); break;
+ }
+}
+
+void save_manager::test_dump()
+{
+ std::ostringstream json;
+ m_root_item.save_json(json);
+ printf("%s\n", json.str().c_str());
+}
diff --git a/src/emu/save.h b/src/emu/save.h
index 32ba0526486..694f9fbcee4 100644
--- a/src/emu/save.h
+++ b/src/emu/save.h
@@ -47,6 +47,23 @@ enum save_error
// MACROS
//**************************************************************************
+/*
+TEST:
+#define REGISTER_SAVE_1(a) .reg(a, #a)
+#define REGISTER_SAVE_2(a,b) REGISTER_SAVE_1(a) REGISTER_SAVE_1(b)
+#define REGISTER_SAVE_3(a,b,c) REGISTER_SAVE_1(a) REGISTER_SAVE_2(b,c)
+#define REGISTER_SAVE_4(a,b,c,d) REGISTER_SAVE_1(a) REGISTER_SAVE_3(b,c,d)
+#define REGISTER_SAVE_5(a,b,c,d,e) REGISTER_SAVE_1(a) REGISTER_SAVE_4(b,c,d,e)
+#define REGISTER_SAVE_6(a,b,c,d,e,f) REGISTER_SAVE_1(a) REGISTER_SAVE_5(b,c,d,e,f)
+#define REGISTER_SAVE_7(a,b,c,d,e,f,g) REGISTER_SAVE_1(a) REGISTER_SAVE_6(b,c,d,e,f,g)
+#define REGISTER_SAVE_8(a,b,c,d,e,f,g,h) REGISTER_SAVE_1(a) REGISTER_SAVE_7(b,c,d,e,f,g,h)
+#define REGISTER_SAVE_9(a,b,c,d,e,f,g,h,i) REGISTER_SAVE_1(a) REGISTER_SAVE_8(b,c,d,e,f,g,h,i)
+
+#define GET_SAVE_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME
+#define REGISTER_SAVE(...) GET_SAVE_N(__VA_ARGS__, REGISTER_SAVE_9, REGISTER_SAVE_8, REGISTER_SAVE_7, REGISTER_SAVE_6, REGISTER_SAVE_5, REGISTER_SAVE_4, REGISTER_SAVE_3, REGISTER_SAVE_2, REGISTER_SAVE_1)(__VA_ARGS__)
+*/
+
+
// callback delegate for presave/postload
typedef named_delegate<void ()> save_prepost_delegate;
@@ -70,6 +87,193 @@ typedef named_delegate<void ()> save_prepost_delegate;
// TYPE DEFINITIONS
//**************************************************************************
+class save_registered_item
+{
+public:
+ enum save_type : uint32_t
+ {
+ TYPE_ARRAY = 0xffff0000,
+ TYPE_CONTAINER,
+ TYPE_STRUCT,
+ TYPE_BOOL,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_FLOAT
+ };
+
+ // root constructor
+ save_registered_item();
+
+ // constructor for a new item
+ save_registered_item(uintptr_t ptr_offset, save_type type, uint32_t native_size, char const *name);
+
+ // append a new item to the current one
+ save_registered_item &append(uintptr_t ptr_offset, save_type type, uint32_t native_size, char const *name);
+
+ // compute the binary size by just saving with a null
+ uint64_t compute_binary_size() { return save_binary(nullptr, 0); }
+
+ // save this item and all owned items into a binary form
+ uint64_t save_binary(uint8_t *ptr, uint64_t length, uintptr_t objbase = 0);
+
+ // restore this item and all owned items from binary form
+ uint64_t restore_binary(uint8_t const *ptr, uint64_t length, uintptr_t objbase = 0);
+
+ // save this item into a JSON stream
+ void save_json(std::ostringstream &output, int indent = 0, bool inline_form = false, uintptr_t objbase = 0);
+
+ // restore this item from a JSON stream
+ void restore_json(std::istringstream &input, uintptr_t objbase = 0);
+
+private:
+ // internal helpers
+ uint64_t read_int_unsigned(uintptr_t objbase, int size);
+ int64_t read_int_signed(uintptr_t objbase, int size);
+ void write_int(uintptr_t objbase, int size, uint64_t data);
+
+ // internal state
+ std::list<save_registered_item> m_items; // list of embedded items
+ uintptr_t m_ptr_offset; // pointer or offset
+ save_type m_type; // type of native
+ uint32_t m_native_size; // native size of item
+ std::string m_name; // name of item
+};
+
+class save_registrar
+{
+ friend class save_manager;
+
+public:
+ // construct a container within parent
+ save_registrar(save_registrar &parent, char const *name) :
+ m_parent(parent.parent_item().append(0, save_registered_item::TYPE_CONTAINER, 0, name)),
+ m_baseptr(0)
+ {
+ }
+
+ // return a reference to the parent item
+ save_registered_item &parent_item() const { return m_parent; }
+
+ // enum types
+ template<typename T, std::enable_if_t<std::is_enum<T>::value, bool> = true>
+ save_registrar &reg(T &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_INT, sizeof(data), name); }
+
+ // signed integral types
+ template<typename T, std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, bool> = true>
+ save_registrar &reg(T &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_INT, sizeof(data), name); }
+
+ // unsigned integral types
+ template<typename T, std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, bool> = true>
+ save_registrar &reg(T &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); }
+
+ // floating-point types
+ template<typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
+ save_registrar &reg(T &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_FLOAT, sizeof(data), name); }
+
+ // unique_ptrs
+ template<typename T>
+ save_registrar &reg(std::unique_ptr<T> &dataptr, char const *name)
+ {
+ if (dataptr.get() == nullptr)
+ throw emu_fatalerror("Passed null pointer to save state registration.");
+ reg(*dataptr.get(), name);
+ return *this;
+ }
+
+ // arrays
+ template<typename T, std::size_t N>
+ save_registrar &reg(T (&data)[N], char const *name)
+ {
+ auto &item = m_parent.append(uintptr_t(&data[0]) - m_baseptr, save_registered_item::save_type(N), sizeof(data[0]), name);
+ save_registrar sub(item, &data[0]);
+ sub.reg(data[0], "");
+ return *this;
+ }
+
+ // vectors
+ template<typename T>
+ save_registrar &reg(std::vector<T> &data, char const *name)
+ {
+ auto &item = m_parent.append(uintptr_t(&data[0]) - m_baseptr, save_registered_item::save_type(data.size()), sizeof(data[0]), name);
+ save_registrar sub(item, &data[0]);
+ sub.reg(data[0], "");
+ return *this;
+ }
+
+ // unique_ptrs with arrays
+ template<typename T>
+ save_registrar &reg(std::unique_ptr<T[]> &dataptr, char const *name, std::size_t count)
+ {
+ if (dataptr.get() == nullptr)
+ throw emu_fatalerror("Passed null pointer to save state registration.");
+ reg(dataptr.get(), name, count);
+ return *this;
+ }
+
+ // pointers
+ template<typename T>
+ save_registrar &reg(T *dataptr, char const *name, std::size_t count)
+ {
+ if (dataptr == nullptr)
+ throw emu_fatalerror("Passed null pointer to save state registration.");
+ auto &item = m_parent.append(uintptr_t(dataptr) - m_baseptr, save_registered_item::save_type(sizeof(*dataptr) * count), sizeof(*dataptr), name);
+ save_registrar sub(item, dataptr);
+ sub.reg(dataptr[0], "");
+ return *this;
+ }
+
+ // structures (must have a _save method)
+ template<typename T, std::enable_if_t<std::is_class<T>::value, bool> = true>
+ save_registrar &reg(T &data, char const *name)
+ {
+ auto &item = m_parent.append(uintptr_t(&data) - m_baseptr, save_registered_item::TYPE_STRUCT, sizeof(data), name);
+ save_registrar sub(item, &data);
+ data.register_save(sub);
+ return *this;
+ }
+
+ // bool as a special case
+ save_registrar &reg(bool &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_BOOL, sizeof(data), name); }
+
+ // rgb_t as a special case
+ save_registrar &reg(rgb_t &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); }
+
+ // PAIR/PAIR64 as a special case
+ save_registrar &reg(PAIR &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); }
+ save_registrar &reg(PAIR64 &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); }
+
+ // rectangle as a special case
+ save_registrar &reg(rectangle &data, char const *name)
+ {
+ auto &item = m_parent.append(uintptr_t(&data) - m_baseptr, save_registered_item::TYPE_STRUCT, sizeof(data), name);
+ save_registrar sub(item, &data);
+ sub.reg(data.min_x, "min_x").reg(data.max_x, "max_x").reg(data.min_y, "min_y").reg(data.max_y, "max_y");
+ return *this;
+ }
+
+private:
+ // internal constructor
+ save_registrar(save_registered_item &parent, void *baseptr = nullptr) :
+ m_parent(parent),
+ m_baseptr(uintptr_t(baseptr))
+ {
+ }
+
+ // internal registration
+ save_registrar &register_internal(void *memptr, save_registered_item::save_type type, std::size_t itemsize, char const *itemname)
+ {
+ m_parent.append(uintptr_t(memptr) - m_baseptr, type, itemsize, itemname);
+ return *this;
+ }
+
+ // internal state
+ save_registered_item &m_parent;
+ uintptr_t m_baseptr;
+};
+
+
+
+
class ram_state;
class rewinder;
@@ -292,6 +496,10 @@ public:
save_error write_buffer(void *buf, size_t size);
save_error read_buffer(const void *buf, size_t size);
+ save_registrar &root_registrar() { return m_root_registrar; }
+ save_registrar &legacy_registrar() { return m_legacy_registrar; }
+ void test_dump();
+
private:
// state callback item
class state_callback
@@ -318,6 +526,10 @@ private:
bool m_reg_allowed; // are registrations allowed?
s32 m_illegal_regs; // number of illegal registrations
+ save_registered_item m_root_item;
+ save_registrar m_root_registrar;
+ save_registrar m_legacy_registrar;
+
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
std::vector<std::unique_ptr<state_callback>> m_presave_list; // list of pre-save functions
@@ -396,4 +608,13 @@ ALLOW_SAVE_TYPE_AND_VECTOR(endianness_t)
ALLOW_SAVE_TYPE_AND_VECTOR(rgb_t)
+
+
+
+
+
+
+
+
+
#endif // MAME_EMU_SAVE_H
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index 1a1c5dee8ad..a297e4ffef2 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -870,22 +870,6 @@ void screen_device::device_start()
if (overname != nullptr && strcmp(overname, "none") != 0)
load_effect_overlay(overname);
- // register items for saving
- save_item(NAME(m_width));
- save_item(NAME(m_height));
- save_item(NAME(m_visarea.min_x));
- save_item(NAME(m_visarea.min_y));
- save_item(NAME(m_visarea.max_x));
- save_item(NAME(m_visarea.max_y));
- save_item(NAME(m_last_partial_scan));
- save_item(NAME(m_frame_period));
- save_item(NAME(m_brightness));
- save_item(NAME(m_scantime));
- save_item(NAME(m_pixeltime));
- save_item(NAME(m_vblank_period));
- save_item(NAME(m_vblank_start_time));
- 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());
diff --git a/src/emu/screen.h b/src/emu/screen.h
index d3f4ce418b1..128dcf6106b 100644
--- a/src/emu/screen.h
+++ b/src/emu/screen.h
@@ -447,6 +447,22 @@ private:
virtual void device_post_load() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void device_register_save(save_registrar &save) override
+ {
+ save.reg(NAME(m_width));
+ save.reg(NAME(m_height));
+ save.reg(NAME(m_visarea));
+ save.reg(NAME(m_last_partial_scan));
+ save.reg(NAME(m_frame_period));
+ save.reg(NAME(m_brightness));
+ save.reg(NAME(m_scantime));
+ save.reg(NAME(m_pixeltime));
+ save.reg(NAME(m_vblank_period));
+ save.reg(NAME(m_vblank_start_time));
+ save.reg(NAME(m_vblank_end_time));
+ save.reg(NAME(m_frame_number));
+ }
+
// internal helpers
void set_container(render_container &container) { m_container = &container; }
void realloc_screen_bitmaps();
diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp
index 7ee663aba69..9fd1df11b9c 100644
--- a/src/emu/sound.cpp
+++ b/src/emu/sound.cpp
@@ -364,16 +364,12 @@ sound_stream_output::sound_stream_output() :
// init - initialization
//-------------------------------------------------
-void sound_stream_output::init(sound_stream &stream, u32 index, char const *tag)
+void sound_stream_output::init(sound_stream &stream, u32 index)
{
// set the passed-in data
m_stream = &stream;
m_index = index;
- // save our state
- auto &save = stream.device().machine().save();
- save.save_item(&stream.device(), "stream.output", tag, index, NAME(m_gain));
-
#if (LOG_OUTPUT_WAV)
std::string filename = stream.device().machine().basename();
filename += stream.device().tag();
@@ -452,17 +448,12 @@ sound_stream_input::sound_stream_input() :
// init - initialization
//-------------------------------------------------
-void sound_stream_input::init(sound_stream &stream, u32 index, char const *tag, sound_stream_output *resampler)
+void sound_stream_input::init(sound_stream &stream, u32 index, sound_stream_output *resampler)
{
// set the passed-in values
m_owner = &stream;
m_index = index;
m_resampler_source = resampler;
-
- // save our state
- auto &save = stream.device().machine().save();
- save.save_item(&stream.device(), "stream.input", tag, index, NAME(m_gain));
- save.save_item(&stream.device(), "stream.input", tag, index, NAME(m_user_gain));
}
@@ -576,10 +567,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
m_name += "'";
// 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.register_postload(save_prepost_delegate(FUNC(sound_stream::postload), this));
+ device.machine().save().register_postload(save_prepost_delegate(FUNC(sound_stream::postload), this));
// initialize all inputs
for (unsigned int inputnum = 0; inputnum < m_input.size(); inputnum++)
@@ -593,12 +581,12 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
}
// add the new input
- m_input[inputnum].init(*this, inputnum, state_tag.c_str(), resampler);
+ m_input[inputnum].init(*this, inputnum, resampler);
}
// initialize all outputs
for (unsigned int outputnum = 0; outputnum < m_output.size(); outputnum++)
- m_output[outputnum].init(*this, outputnum, state_tag.c_str());
+ m_output[outputnum].init(*this, outputnum);
// create an update timer for synchronous streams
if (synchronous())
@@ -1096,9 +1084,6 @@ sound_manager::sound_manager(running_machine &machine) :
machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&sound_manager::reset, this));
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&sound_manager::stop_recording, this));
- // register global states
- machine.save().save_item(NAME(m_last_update));
-
// set the starting attenuation
set_attenuation(machine.options().volume());
diff --git a/src/emu/sound.h b/src/emu/sound.h
index 3aefc4bef3f..ff00c3f7f67 100644
--- a/src/emu/sound.h
+++ b/src/emu/sound.h
@@ -476,7 +476,7 @@ public:
sound_stream_output();
// initialization
- void init(sound_stream &stream, u32 index, char const *tag_base);
+ void init(sound_stream &stream, u32 index);
// no copying allowed
sound_stream_output(sound_stream_output const &src) = delete;
@@ -507,6 +507,12 @@ public:
// attempt to optimize resamplers by reusing them where possible
sound_stream_output &optimize_resampler(sound_stream_output *input_resampler);
+ // register for save states
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_gain));
+ }
+
private:
// internal state
sound_stream *m_stream; // owning stream
@@ -530,7 +536,7 @@ public:
sound_stream_input();
// initialization
- void init(sound_stream &stream, u32 index, char const *tag_base, sound_stream_output *resampler);
+ void init(sound_stream &stream, u32 index, sound_stream_output *resampler);
// no copying allowed
sound_stream_input(sound_stream_input const &src) = delete;
@@ -560,6 +566,13 @@ public:
// tell inputs to apply sample rate changes
void apply_sample_rate_changes(u32 updatenum, u32 downstream_rate);
+ // register for save states
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_gain))
+ .reg(NAME(m_user_gain));
+ }
+
private:
// internal state
sound_stream *m_owner; // pointer to the owning stream
@@ -646,6 +659,14 @@ public:
// apply any pending sample rate changes; should only be called by the sound manager
void apply_sample_rate_changes(u32 updatenum, u32 downstream_rate);
+ // register for saves
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_sample_rate))
+ .reg(NAME(m_input))
+ .reg(NAME(m_output));
+ }
+
#if (SOUND_DEBUG)
// print one level of the sound graph and recursively tell our inputs to do the same
void print_graph_recursive(int indent, int index);
@@ -786,6 +807,16 @@ public:
// fill the given buffer with 16-bit stereo audio samples
void samples(s16 *buffer);
+ // register for saves
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_last_update));
+
+ save_registrar streams(save, "streams");
+ for (auto &stream : m_stream_list)
+ streams.reg(stream, string_format("%s:%d", stream->device().tag(), stream->output_base()).c_str());
+ }
+
private:
// set/reset the mute state for the given reason
void mute(bool mute, u8 reason);
diff --git a/src/emu/tilemap.cpp b/src/emu/tilemap.cpp
index 5757f35341f..1981e4a461e 100644
--- a/src/emu/tilemap.cpp
+++ b/src/emu/tilemap.cpp
@@ -361,7 +361,7 @@ void tilemap_t::init_common(
m_manager = &manager;
m_device = dynamic_cast<device_t *>(this);
m_palette = &decoder.palette();
- m_next = nullptr;
+// m_next = nullptr;
m_user_data = nullptr;
// populate tilemap metrics
@@ -416,20 +416,6 @@ void tilemap_t::init_common(
for (int group = 0; group < TILEMAP_NUM_GROUPS; group++)
map_pens_to_layer(group, 0, 0, TILEMAP_PIXEL_LAYER0);
- // save relevant state
- int instance = manager.alloc_instance();
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_enable));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_attributes));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_palette_offset));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_scrollrows));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_scrollcols));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_rowscroll));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_colscroll));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_dx));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_dx_flipped));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_dy));
- machine().save().save_item(m_device, "tilemap", nullptr, instance, NAME(m_dy_flipped));
-
// reset everything after a load
machine().save().register_postload(save_prepost_delegate(FUNC(tilemap_t::postload), this));
}
@@ -1587,19 +1573,6 @@ tilemap_manager::tilemap_manager(running_machine &machine)
tilemap_manager::~tilemap_manager()
{
- // detach all device tilemaps since they will be destroyed as subdevices elsewhere
- bool found = true;
- while (found)
- {
- found = false;
- for (tilemap_t &tmap : m_tilemap_list)
- if (tmap.m_device)
- {
- found = true;
- m_tilemap_list.detach(tmap);
- break;
- }
- }
}
@@ -1610,16 +1583,26 @@ tilemap_manager::~tilemap_manager()
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)
{
- if (!allocated)
- allocated = new tilemap_t(machine().root_device());
- return m_tilemap_list.append(allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows));
+ if (allocated != nullptr)
+ m_device_tilemap_list.push_back(allocated);
+ else
+ {
+ m_tilemap_list.push_back(std::make_unique<tilemap_t>(machine().root_device()));
+ allocated = m_tilemap_list.back().get();
+ }
+ return allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows);
}
tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_standard_mapper mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated)
{
- if (!allocated)
- allocated = new tilemap_t(machine().root_device());
- return m_tilemap_list.append(allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows));
+ if (allocated != nullptr)
+ m_device_tilemap_list.push_back(allocated);
+ else
+ {
+ m_tilemap_list.push_back(std::make_unique<tilemap_t>(machine().root_device()));
+ allocated = m_tilemap_list.back().get();
+ }
+ return allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows);
}
@@ -1630,8 +1613,10 @@ tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_in
void tilemap_manager::set_flip_all(u32 attributes)
{
- for (tilemap_t &tmap : m_tilemap_list)
- tmap.set_flip(attributes);
+ for (auto &tmap : m_tilemap_list)
+ tmap->set_flip(attributes);
+ for (auto &tmap : m_device_tilemap_list)
+ tmap->set_flip(attributes);
}
@@ -1642,8 +1627,10 @@ void tilemap_manager::set_flip_all(u32 attributes)
void tilemap_manager::mark_all_dirty()
{
- for (tilemap_t &tmap : m_tilemap_list)
- tmap.mark_all_dirty();
+ for (auto &tmap : m_tilemap_list)
+ tmap->mark_all_dirty();
+ for (auto &tmap : m_device_tilemap_list)
+ tmap->mark_all_dirty();
}
diff --git a/src/emu/tilemap.h b/src/emu/tilemap.h
index 504cbfea04a..31f817bd42d 100644
--- a/src/emu/tilemap.h
+++ b/src/emu/tilemap.h
@@ -409,7 +409,7 @@ class tilemap_t
friend class tilemap_device;
friend class tilemap_manager;
- friend class simple_list<tilemap_t>;
+ friend class std::unique_ptr<tilemap_t>;
friend resource_pool_object<tilemap_t>::~resource_pool_object();
// logical index
@@ -427,20 +427,21 @@ class tilemap_t
void init_common(tilemap_manager &manager, device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, u16 tilewidth, u16 tileheight, u32 cols, u32 rows);
protected:
- // tilemap_manager controls our allocations
- tilemap_t(device_t &owner);
- virtual ~tilemap_t();
tilemap_t &init(tilemap_manager &manager, 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 &init(tilemap_manager &manager, device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_standard_mapper mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows);
public:
+ // tilemap_manager controls our allocations
+ tilemap_t(device_t &owner);
+ virtual ~tilemap_t();
+
// getters
running_machine &machine() const;
device_palette_interface &palette() const { return *m_palette; }
device_gfx_interface &decoder() const { return *m_tileinfo.decoder; }
- tilemap_t *next() const { return m_next; }
+// tilemap_t *next() const { return m_next; }
void *user_data() const { return m_user_data; }
u32 rows() const { return m_rows; }
u32 cols() const { return m_cols; }
@@ -507,6 +508,22 @@ public:
tilemap_memory_index scan_cols_flip_y(u32 col, u32 row, u32 num_cols, u32 num_rows);
tilemap_memory_index scan_cols_flip_xy(u32 col, u32 row, u32 num_cols, u32 num_rows);
+ // register for saves
+ void register_save(save_registrar &save)
+ {
+ save.reg(NAME(m_enable))
+ .reg(NAME(m_attributes))
+ .reg(NAME(m_palette_offset))
+ .reg(NAME(m_scrollrows))
+ .reg(NAME(m_scrollcols))
+ .reg(NAME(m_rowscroll))
+ .reg(NAME(m_colscroll))
+ .reg(NAME(m_dx))
+ .reg(NAME(m_dx_flipped))
+ .reg(NAME(m_dy))
+ .reg(NAME(m_dy_flipped));
+ }
+
private:
// internal set of transparency states for rendering
enum trans_t
@@ -563,7 +580,7 @@ private:
tilemap_manager * m_manager; // reference to the owning manager
device_t * m_device; // pointer to our owning device
device_palette_interface * m_palette; // palette used for drawing
- tilemap_t * m_next; // pointer to next tilemap
+// tilemap_t * m_next; // pointer to next tilemap
void * m_user_data; // user data value
// basic tilemap metrics
@@ -636,13 +653,21 @@ public:
{ return create(decoder, std::forward<T>(tile_get_info), std::forward<U>(mapper), tilewidth, tileheight, cols, rows, &static_cast<tilemap_t &>(allocated)); }
// tilemap list information
- tilemap_t *find(int index) { return m_tilemap_list.find(index); }
- int count() const { return m_tilemap_list.count(); }
+ tilemap_t *find(int index) { return (index < m_tilemap_list.size()) ? m_tilemap_list[index].get() : m_device_tilemap_list[index - m_tilemap_list.size()]; }
+ int count() const { return m_tilemap_list.size() + m_device_tilemap_list.size(); }
// global operations on all tilemaps
void mark_all_dirty();
void set_flip_all(u32 attributes);
+ // register for saves
+ void register_save(save_registrar &save)
+ {
+ int index = 0;
+ for (auto &tmap : m_tilemap_list)
+ save.reg(tmap, string_format("%d", index++).c_str());
+ }
+
private:
// tilemap creation
tilemap_t &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);
@@ -653,7 +678,8 @@ private:
// internal state
running_machine & m_machine;
- simple_list<tilemap_t> m_tilemap_list;
+ std::vector<std::unique_ptr<tilemap_t>> m_tilemap_list;
+ std::vector<tilemap_t *> m_device_tilemap_list;
int m_instance;
};
@@ -757,6 +783,12 @@ protected:
// device-level overrides
virtual void device_start() override;
+ // register for save states
+ void device_register_save(save_registrar &save) override
+ {
+ save.reg(*static_cast<tilemap_t *>(this), "tilemap");
+ }
+
private:
// devices
required_device<gfxdecode_device> m_gfxdecode;