diff options
| author | 2021-04-09 03:04:35 -0700 | |
|---|---|---|
| committer | 2021-04-09 03:04:35 -0700 | |
| commit | b8c568b279f9ebaedac014d51eb48ed9b530566a (patch) | |
| tree | 2b7ece212eedac9271d6603bae4566b805411ccf | |
| parent | adf5af551b54e165d9d95370cc569f4bf63b54bc (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.
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 ®(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 ®(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 ®(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 ®(T &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_FLOAT, sizeof(data), name); } + + // unique_ptrs + template<typename T> + save_registrar ®(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 ®(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 ®(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 ®(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 ®(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 ®(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 ®(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 ®(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 ®(PAIR &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); } + save_registrar ®(PAIR64 &data, char const *name) { return register_internal(&data, save_registered_item::TYPE_UINT, sizeof(data), name); } + + // rectangle as a special case + save_registrar ®(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 ®ister_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; |
