1 // license:BSD-3-Clause 2 // copyright-holders:Aaron Giles 3 /*************************************************************************** 4 5 save.h 6 7 Save state management functions. 8 9 ***************************************************************************/ 10 11 #pragma once 12 13 #ifndef __EMU_H__ 14 #error Dont include this file directly; include emu.h instead. 15 #endif 16 17 #ifndef MAME_EMU_SAVE_H 18 #define MAME_EMU_SAVE_H 19 20 #include <array> 21 #include <cassert> 22 #include <memory> 23 #include <string> 24 #include <type_traits> 25 #include <vector> 26 27 28 29 //************************************************************************** 30 // CONSTANTS 31 //************************************************************************** 32 33 enum save_error 34 { 35 STATERR_NONE, 36 STATERR_NOT_FOUND, 37 STATERR_ILLEGAL_REGISTRATIONS, 38 STATERR_INVALID_HEADER, 39 STATERR_READ_ERROR, 40 STATERR_WRITE_ERROR, 41 STATERR_DISABLED 42 }; 43 44 45 46 //************************************************************************** 47 // MACROS 48 //************************************************************************** 49 50 // callback delegate for presave/postload 51 typedef named_delegate<void ()> save_prepost_delegate; 52 53 54 // use this to declare a given type is a simple, non-pointer type that can be 55 // saved; in general, this is intended only to be used for specific enum types 56 // defined by your device 57 #define ALLOW_SAVE_TYPE(TYPE) \ 58 template <> struct save_manager::is_atom<TYPE> { static constexpr bool value = true; }; 59 60 // use this as above, but also to declare that std::vector<TYPE> is safe as well 61 #define ALLOW_SAVE_TYPE_AND_VECTOR(TYPE) \ 62 ALLOW_SAVE_TYPE(TYPE) \ 63 template <> struct save_manager::is_vector_safe<TYPE> { static constexpr bool value = true; }; 64 65 // use this for saving members of structures in arrays 66 #define STRUCT_MEMBER(s, m) s, &save_manager::pointer_unwrap<decltype(s)>::underlying_type::m, #s "." #m 67 68 69 //************************************************************************** 70 // TYPE DEFINITIONS 71 //************************************************************************** 72 73 class ram_state; 74 class rewinder; 75 76 class save_manager 77 { 78 // stuff for working with arrays 79 template <typename T> struct array_unwrap 80 { 81 using underlying_type = T; 82 static constexpr std::size_t SAVE_COUNT = 1U; 83 static constexpr std::size_t SIZE = sizeof(underlying_type); ptrarray_unwrap84 static underlying_type *ptr(T &value) { return &value; } 85 }; 86 template <typename T, std::size_t N> struct array_unwrap<T [N]> 87 { 88 using underlying_type = typename array_unwrap<T>::underlying_type; 89 static constexpr std::size_t SAVE_COUNT = N * array_unwrap<T>::SAVE_COUNT; 90 static constexpr std::size_t SIZE = sizeof(underlying_type); 91 static underlying_type *ptr(T (&value)[N]) { return array_unwrap<T>::ptr(value[0]); } 92 }; 93 template <typename T, std::size_t N> struct array_unwrap<std::array<T, N> > 94 { 95 using underlying_type = typename array_unwrap<T>::underlying_type; 96 static constexpr std::size_t SAVE_COUNT = N * array_unwrap<T>::SAVE_COUNT; 97 static constexpr std::size_t SIZE = sizeof(underlying_type); 98 static underlying_type *ptr(std::array<T, N> &value) { return array_unwrap<T>::ptr(value[0]); } 99 }; 100 101 // set of templates to identify valid save types 102 template <typename ItemType> struct is_atom { static constexpr bool value = false; }; 103 template <typename ItemType> struct is_vector_safe { static constexpr bool value = false; }; 104 105 class state_entry 106 { 107 public: 108 // construction/destruction 109 state_entry(void *data, const char *name, device_t *device, const char *module, const char *tag, int index, u8 size, u32 valcount, u32 blockcount, u32 stride); 110 111 // helpers 112 void flip_data(); 113 114 // state 115 void * m_data; // pointer to the memory to save/restore 116 std::string m_name; // full name 117 device_t * m_device; // associated device, nullptr if none 118 std::string m_module; // module name 119 std::string m_tag; // tag name 120 int m_index; // index 121 u8 m_typesize; // size of the raw data type 122 u32 m_typecount; // number of items in each block 123 u32 m_blockcount; // number of blocks of items 124 u32 m_stride; // stride between blocks of items in units of item size 125 }; 126 127 friend class ram_state; 128 friend class rewinder; 129 130 public: 131 // stuff to allow STRUCT_MEMBER to work with pointers 132 template <typename T> struct pointer_unwrap { using underlying_type = typename array_unwrap<T>::underlying_type; }; 133 template <typename T> struct pointer_unwrap<T &> { using underlying_type = typename pointer_unwrap<std::remove_cv_t<T> >::underlying_type; }; 134 template <typename T> struct pointer_unwrap<T *> { using underlying_type = typename array_unwrap<T>::underlying_type; }; 135 template <typename T> struct pointer_unwrap<std::unique_ptr<T []> > { using underlying_type = typename array_unwrap<T>::underlying_type; }; 136 137 // construction/destruction 138 save_manager(running_machine &machine); 139 140 // getters 141 running_machine &machine() const { return m_machine; } 142 rewinder *rewind() { return m_rewind.get(); } 143 int registration_count() const { return m_entry_list.size(); } 144 bool registration_allowed() const { return m_reg_allowed; } 145 146 // registration control 147 void allow_registration(bool allowed = true); 148 const char *indexed_item(int index, void *&base, u32 &valsize, u32 &valcount, u32 &blockcount, u32 &stride) const; 149 150 // function registration 151 void register_presave(save_prepost_delegate func); 152 void register_postload(save_prepost_delegate func); 153 154 // callback dispatching 155 void dispatch_presave(); 156 void dispatch_postload(); 157 158 // generic memory registration 159 void save_memory(device_t *device, const char *module, const char *tag, u32 index, const char *name, void *val, u32 valsize, u32 valcount = 1, u32 blockcount = 1, u32 stride = 0); 160 161 // templatized wrapper for general objects and arrays 162 template <typename ItemType> 163 std::enable_if_t<is_atom<typename array_unwrap<ItemType>::underlying_type>::value> save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, const char *valname) 164 { 165 static_assert(!std::is_pointer<ItemType>::value, "Called save_item on a pointer with no count!"); 166 save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT); 167 } 168 169 // templatized wrapper for structure members 170 template <typename ItemType, typename StructType, typename ElementType> 171 void save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, ElementType StructType::*element, const char *valname) 172 { 173 static_assert(std::is_base_of<StructType, typename array_unwrap<ItemType>::underlying_type>::value, "Called save_item on a non-matching struct member pointer!"); 174 static_assert(!std::is_pointer<ElementType>::value, "Called save_item on a struct member pointer!"); 175 static_assert(is_atom<typename array_unwrap<ElementType>::underlying_type>::value, "Called save_item on a non-fundamental type!"); 176 save_memory(device, module, tag, index, valname, array_unwrap<ElementType>::ptr(array_unwrap<ItemType>::ptr(value)->*element), array_unwrap<ElementType>::SIZE, array_unwrap<ElementType>::SAVE_COUNT, array_unwrap<ItemType>::SAVE_COUNT, sizeof(typename array_unwrap<ItemType>::underlying_type)); 177 } 178 179 // templatized wrapper for pointers 180 template <typename ItemType> 181 std::enable_if_t<is_atom<typename array_unwrap<ItemType>::underlying_type>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, const char *valname, u32 count) 182 { 183 save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value[0]), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT * count); 184 } 185 186 template <typename ItemType, typename StructType, typename ElementType> 187 void save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, ElementType StructType::*element, const char *valname, u32 count) 188 { 189 static_assert(std::is_base_of<StructType, typename array_unwrap<ItemType>::underlying_type>::value, "Called save_pointer on a non-matching struct member pointer!"); 190 static_assert(!std::is_pointer<ElementType>::value, "Called save_pointer on a struct member pointer!"); 191 static_assert(is_atom<typename array_unwrap<ElementType>::underlying_type>::value, "Called save_pointer on a non-fundamental type!"); 192 save_memory(device, module, tag, index, valname, array_unwrap<ElementType>::ptr(array_unwrap<ItemType>::ptr(value[0])->*element), array_unwrap<ElementType>::SIZE, array_unwrap<ElementType>::SAVE_COUNT, array_unwrap<ItemType>::SAVE_COUNT * count, sizeof(typename array_unwrap<ItemType>::underlying_type)); 193 } 194 195 // templatized wrapper for std::unique_ptr 196 template <typename ItemType> 197 std::enable_if_t<is_atom<typename array_unwrap<ItemType>::underlying_type>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, const char *valname, u32 count) 198 { 199 save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value[0]), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT * count); 200 } 201 202 template <typename ItemType, typename StructType, typename ElementType> 203 void save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, ElementType StructType::*element, const char *valname, u32 count) 204 { 205 static_assert(std::is_base_of<StructType, typename array_unwrap<ItemType>::underlying_type>::value, "Called save_pointer on a non-matching struct member pointer!"); 206 static_assert(!std::is_pointer<ElementType>::value, "Called save_pointer on a struct member pointer!"); 207 static_assert(is_atom<typename array_unwrap<ElementType>::underlying_type>::value, "Called save_pointer on a non-fundamental type!"); 208 save_memory(device, module, tag, index, valname, array_unwrap<ElementType>::ptr(array_unwrap<ItemType>::ptr(value[0])->*element), array_unwrap<ElementType>::SIZE, array_unwrap<ElementType>::SAVE_COUNT, array_unwrap<ItemType>::SAVE_COUNT * count, sizeof(typename array_unwrap<ItemType>::underlying_type)); 209 } 210 211 // templatized wrapper for std::vector 212 template <typename ItemType> 213 std::enable_if_t<is_vector_safe<typename array_unwrap<ItemType>::underlying_type>::value> save_item(device_t *device, const char *module, const char *tag, int index, std::vector<ItemType> &value, const char *valname) 214 { 215 save_pointer(device, module, tag, index, &value[0], valname, value.size()); 216 } 217 218 // specializations for bitmaps 219 void save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind8 &value, const char *valname) 220 { 221 save_memory(device, module, tag, index, valname, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height()); 222 } 223 224 void save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind16 &value, const char *valname) 225 { 226 save_memory(device, module, tag, index, valname, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height()); 227 } 228 229 void save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind32 &value, const char *valname) 230 { 231 save_memory(device, module, tag, index, valname, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height()); 232 } 233 234 void save_item(device_t *device, const char *module, const char *tag, int index, bitmap_rgb32 &value, const char *valname) 235 { 236 save_memory(device, module, tag, index, valname, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height()); 237 } 238 239 // specializations for attotimes 240 template <typename ItemType> 241 std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, const char *valname) 242 { 243 std::string tempstr; 244 tempstr.assign(valname).append(".attoseconds"); 245 save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str()); 246 tempstr.assign(valname).append(".seconds"); 247 save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str()); 248 } 249 250 template <typename ItemType> 251 std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, const char *valname, u32 count) 252 { 253 std::string tempstr; 254 tempstr.assign(valname).append(".attoseconds"); 255 save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str(), count); 256 tempstr.assign(valname).append(".seconds"); 257 save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str(), count); 258 } 259 260 template <typename ItemType> 261 std::enable_if_t<std::is_same<typename save_manager::array_unwrap<ItemType>::underlying_type, attotime>::value> save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, const char *valname, u32 count) 262 { 263 std::string tempstr; 264 tempstr.assign(valname).append(".attoseconds"); 265 save_item(device, module, tag, index, value, &attotime::m_attoseconds, tempstr.c_str(), count); 266 tempstr.assign(valname).append(".seconds"); 267 save_item(device, module, tag, index, value, &attotime::m_seconds, tempstr.c_str(), count); 268 } 269 270 // global memory registration 271 template <typename ItemType> 272 void save_item(ItemType &value, const char *valname, int index = 0) 273 { save_item(nullptr, "global", nullptr, index, value, valname); } 274 template <typename ItemType, typename StructType, typename ElementType> 275 void save_item(ItemType &value, ElementType StructType::*element, const char *valname, int index = 0) 276 { save_item(nullptr, "global", nullptr, index, value, element, valname); } 277 template <typename ItemType> 278 void save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0) 279 { save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), valname, count); } 280 template <typename ItemType, typename StructType, typename ElementType> 281 void save_pointer(ItemType &&value, ElementType StructType::*element, const char *valname, u32 count, int index = 0) 282 { save_pointer(nullptr, "global", nullptr, index, std::forward<ItemType>(value), element, valname, count); } 283 284 // file processing 285 static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...)); 286 save_error write_file(emu_file &file); 287 save_error read_file(emu_file &file); 288 289 save_error write_stream(std::ostream &str); 290 save_error read_stream(std::istream &str); 291 292 save_error write_buffer(void *buf, size_t size); 293 save_error read_buffer(const void *buf, size_t size); 294 295 private: 296 // state callback item 297 class state_callback 298 { 299 public: 300 // construction/destruction 301 state_callback(save_prepost_delegate callback); 302 303 save_prepost_delegate m_func; // delegate 304 }; 305 306 // internal helpers 307 template <typename T, typename U, typename V, typename W> 308 save_error do_write(T check_space, U write_block, V start_header, W start_data); 309 template <typename T, typename U, typename V, typename W> 310 save_error do_read(T check_length, U read_block, V start_header, W start_data); 311 u32 signature() const; 312 void dump_registry() const; 313 static save_error validate_header(const u8 *header, const char *gamename, u32 signature, void (CLIB_DECL *errormsg)(const char *fmt, ...), const char *error_prefix); 314 315 // internal state 316 running_machine & m_machine; // reference to our machine 317 std::unique_ptr<rewinder> m_rewind; // rewinder 318 bool m_reg_allowed; // are registrations allowed? 319 s32 m_illegal_regs; // number of illegal registrations 320 321 std::vector<std::unique_ptr<state_entry>> m_entry_list; // list of registered entries 322 std::vector<std::unique_ptr<ram_state>> m_ramstate_list; // list of ram states 323 std::vector<std::unique_ptr<state_callback>> m_presave_list; // list of pre-save functions 324 std::vector<std::unique_ptr<state_callback>> m_postload_list; // list of post-load functions 325 }; 326 327 class ram_state 328 { 329 save_manager & m_save; // reference to save_manager 330 util::vectorstream m_data; // save data buffer 331 332 public: 333 bool m_valid; // can we load this state? 334 attotime m_time; // machine timestamp 335 336 ram_state(save_manager &save); 337 static size_t get_size(save_manager &save); 338 save_error save(); 339 save_error load(); 340 }; 341 342 class rewinder 343 { 344 save_manager & m_save; // reference to save_manager 345 bool m_enabled; // enable rewind savestates 346 size_t m_capacity; // total memory rewind states can occupy (MB, limited to 1-2048 in options) 347 s32 m_current_index; // where we are in time 348 s32 m_first_invalid_index; // all states before this one are guarateed to be valid 349 bool m_first_time_warning; // keep track of warnings we report 350 bool m_first_time_note; // keep track of notes 351 std::vector<std::unique_ptr<ram_state>> m_state_list; // rewinder's own ram states 352 353 // load/save management 354 enum class rewind_operation 355 { 356 SAVE, 357 LOAD 358 }; 359 360 enum 361 { 362 REWIND_INDEX_NONE = -1, 363 REWIND_INDEX_FIRST 364 }; 365 366 bool check_size(); 367 bool current_index_is_last() { return m_current_index == m_state_list.size() - 1; } 368 void report_error(save_error type, rewind_operation operation); 369 370 public: 371 rewinder(save_manager &save); 372 bool enabled() { return m_enabled; } 373 void clamp_capacity(); 374 void invalidate(); 375 bool capture(); 376 bool step(); 377 }; 378 379 380 // template specializations to enumerate the fundamental atomic types you are allowed to save 381 ALLOW_SAVE_TYPE_AND_VECTOR(char) 382 ALLOW_SAVE_TYPE (bool) // std::vector<bool> may be packed internally 383 ALLOW_SAVE_TYPE_AND_VECTOR(osd::s8) 384 ALLOW_SAVE_TYPE_AND_VECTOR(osd::u8) 385 ALLOW_SAVE_TYPE_AND_VECTOR(osd::s16) 386 ALLOW_SAVE_TYPE_AND_VECTOR(osd::u16) 387 ALLOW_SAVE_TYPE_AND_VECTOR(osd::s32) 388 ALLOW_SAVE_TYPE_AND_VECTOR(osd::u32) 389 ALLOW_SAVE_TYPE_AND_VECTOR(osd::s64) 390 ALLOW_SAVE_TYPE_AND_VECTOR(osd::u64) 391 ALLOW_SAVE_TYPE_AND_VECTOR(PAIR) 392 ALLOW_SAVE_TYPE_AND_VECTOR(PAIR64) 393 ALLOW_SAVE_TYPE_AND_VECTOR(float) 394 ALLOW_SAVE_TYPE_AND_VECTOR(double) 395 ALLOW_SAVE_TYPE_AND_VECTOR(endianness_t) 396 ALLOW_SAVE_TYPE_AND_VECTOR(rgb_t) 397 398 399 #endif // MAME_EMU_SAVE_H 400