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