summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/save.h
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/save.h')
-rw-r--r--trunk/src/emu/save.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/trunk/src/emu/save.h b/trunk/src/emu/save.h
new file mode 100644
index 00000000000..4af38458080
--- /dev/null
+++ b/trunk/src/emu/save.h
@@ -0,0 +1,293 @@
+/***************************************************************************
+
+ save.h
+
+ Save state management functions.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __EMU_H__
+#error Dont include this file directly; include emu.h instead.
+#endif
+
+#ifndef __SAVE_H__
+#define __SAVE_H__
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+enum save_error
+{
+ STATERR_NONE,
+ STATERR_ILLEGAL_REGISTRATIONS,
+ STATERR_INVALID_HEADER,
+ STATERR_READ_ERROR,
+ STATERR_WRITE_ERROR
+};
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// callback delegate for presave/postload
+typedef delegate<void ()> save_prepost_delegate;
+
+
+// use this to declare a given type is a simple, non-pointer type that can be
+// saved; in general, this is intended only to be used for specific enum types
+// defined by your device
+#define ALLOW_SAVE_TYPE(TYPE) template<> struct save_manager::type_checker<TYPE> { static const bool is_atom = true; static const bool is_pointer = false; }
+
+
+
+// register items with explicit tags
+#define state_save_register_item(_mach, _mod, _tag, _index, _val) \
+ (_mach).save().save_item(_mod, _tag, _index, _val, #_val)
+
+#define state_save_register_item_pointer(_mach, _mod, _tag, _index, _val, _count) \
+ (_mach).save().save_pointer(_mod, _tag, _index, _val, #_val, _count)
+
+#define state_save_register_item_array(_mach, _mod, _tag, _index, _val) \
+ (_mach).save().save_item(_mod, _tag, _index, _val, #_val)
+
+#define state_save_register_item_2d_array(_mach, _mod, _tag, _index, _val) \
+ (_mach).save().save_item(_mod, _tag, _index, _val, #_val)
+
+#define state_save_register_item_bitmap(_mach, _mod, _tag, _index, _val) \
+ (_mach).save().save_item(_mod, _tag, _index, *(_val), #_val)
+
+
+
+// register global items
+#define state_save_register_global(_mach, _val) \
+ (_mach).save().save_item(_val, #_val)
+
+#define state_save_register_global_pointer(_mach, _val, _count) \
+ (_mach).save().save_pointer(_val, #_val, _count)
+
+#define state_save_register_global_array(_mach, _val) \
+ (_mach).save().save_item(_val, #_val)
+
+#define state_save_register_global_2d_array(_mach, _val) \
+ (_mach).save().save_item(_val, #_val)
+
+#define state_save_register_global_bitmap(_mach, _val) \
+ (_mach).save().save_item(*(_val), #_val)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class save_manager
+{
+ // type_checker is a set of templates to identify valid save types
+ template<typename _ItemType> struct type_checker { static const bool is_atom = false; static const bool is_pointer = false; };
+ template<typename _ItemType> struct type_checker<_ItemType*> { static const bool is_atom = false; static const bool is_pointer = true; };
+
+public:
+ // construction/destruction
+ save_manager(running_machine &machine);
+
+ // getters
+ running_machine &machine() const { return m_machine; }
+ int registration_count() const { return m_entry_list.count(); }
+ bool registration_allowed() const { return m_reg_allowed; }
+
+ // registration control
+ void allow_registration(bool allowed = true);
+ const char *indexed_item(int index, void *&base, UINT32 &valsize, UINT32 &valcount) const;
+
+ // function registration
+ void register_presave(save_prepost_delegate func);
+ void register_postload(save_prepost_delegate func);
+
+ // generic memory registration
+ void save_memory(const char *module, const char *tag, UINT32 index, const char *name, void *val, UINT32 valsize, UINT32 valcount = 1);
+
+ // templatized wrapper for general objects
+ template<typename _ItemType>
+ void save_item(const char *module, const char *tag, int index, _ItemType &value, const char *valname)
+ {
+ if (type_checker<_ItemType>::is_pointer) throw emu_fatalerror("Called save_item on a pointer with no count!");
+ if (!type_checker<_ItemType>::is_atom) throw emu_fatalerror("Called save_item on a non-fundamental type!");
+ save_memory(module, tag, index, valname, &value, sizeof(value));
+ }
+
+ // templatized wrapper for 1-dimensional arrays
+ template<typename _ItemType, std::size_t N>
+ void save_item(const char *module, const char *tag, int index, _ItemType (&value)[N], const char *valname)
+ {
+ if (!type_checker<_ItemType>::is_atom) throw emu_fatalerror("Called save_item on a non-fundamental type!");
+ save_memory(module, tag, index, valname, &value[0], sizeof(value[0]), N);
+ }
+
+ // templatized wrapper for 2-dimensional arrays
+ template<typename _ItemType, std::size_t M, std::size_t N>
+ void save_item(const char *module, const char *tag, int index, _ItemType (&value)[M][N], const char *valname)
+ {
+ if (!type_checker<_ItemType>::is_atom) throw emu_fatalerror("Called save_item on a non-fundamental type!");
+ save_memory(module, tag, index, valname, &value[0][0], sizeof(value[0][0]), M * N);
+ }
+
+ // templatized wrapper for pointers
+ template<typename _ItemType>
+ void save_pointer(const char *module, const char *tag, int index, _ItemType *value, const char *valname, UINT32 count)
+ {
+ if (!type_checker<_ItemType>::is_atom) throw emu_fatalerror("Called save_item on a non-fundamental type!");
+ save_memory(module, tag, index, valname, value, sizeof(*value), count);
+ }
+
+ // global memory registration
+ template<typename _ItemType>
+ void save_item(_ItemType &value, const char *valname, int index = 0) { save_item("global", NULL, index, value, valname); }
+ template<typename _ItemType>
+ void save_pointer(_ItemType *value, const char *valname, UINT32 count, int index = 0) { save_pointer("global", NULL, index, value, valname, count); }
+
+ // file processing
+ static save_error check_file(running_machine &machine, emu_file &file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
+ save_error write_file(emu_file &file);
+ save_error read_file(emu_file &file);
+
+private:
+ // internal helpers
+ UINT32 signature() const;
+ void dump_registry() const;
+ static save_error validate_header(const UINT8 *header, const char *gamename, UINT32 signature, void (CLIB_DECL *errormsg)(const char *fmt, ...), const char *error_prefix);
+
+ // state callback item
+ class state_callback
+ {
+ public:
+ // construction/destruction
+ state_callback(save_prepost_delegate callback);
+
+ // getters
+ state_callback *next() const { return m_next; }
+
+ // state
+ state_callback * m_next; // pointer to next entry
+ save_prepost_delegate m_func; // delegate
+ };
+
+ class state_entry
+ {
+ public:
+ // construction/destruction
+ state_entry(void *data, const char *name, UINT8 size, UINT32 count);
+
+ // getters
+ state_entry *next() const { return m_next; }
+
+ // helpers
+ void flip_data();
+
+ // state
+ state_entry * m_next; // pointer to next entry
+ void * m_data; // pointer to the memory to save/restore
+ astring m_name; // full name
+ UINT8 m_typesize; // size of the raw data type
+ UINT32 m_typecount; // number of items
+ UINT32 m_offset; // offset within the final structure
+ };
+
+ // internal state
+ running_machine & m_machine; // reference to our machine
+ bool m_reg_allowed; // are registrations allowed?
+ int m_illegal_regs; // number of illegal registrations
+
+ simple_list<state_entry> m_entry_list; // list of reigstered entries
+ simple_list<state_callback> m_presave_list; // list of pre-save functions
+ simple_list<state_callback> m_postload_list; // list of post-load functions
+
+ static const char s_magic_num[8]; // magic number for header
+};
+
+
+// template specializations to enumerate the fundamental atomic types you are allowed to save
+ALLOW_SAVE_TYPE(bool);
+ALLOW_SAVE_TYPE(INT8);
+ALLOW_SAVE_TYPE(UINT8);
+ALLOW_SAVE_TYPE(INT16);
+ALLOW_SAVE_TYPE(UINT16);
+ALLOW_SAVE_TYPE(INT32);
+ALLOW_SAVE_TYPE(UINT32);
+ALLOW_SAVE_TYPE(INT64);
+ALLOW_SAVE_TYPE(UINT64);
+ALLOW_SAVE_TYPE(PAIR);
+ALLOW_SAVE_TYPE(PAIR64);
+ALLOW_SAVE_TYPE(float);
+ALLOW_SAVE_TYPE(double);
+ALLOW_SAVE_TYPE(endianness_t);
+
+
+
+//**************************************************************************
+// INLINE FUNCTIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// save_item - specialized save_item for bitmaps
+//-------------------------------------------------
+
+template<>
+inline void save_manager::save_item(const char *module, const char *tag, int index, bitmap_t &value, const char *name)
+{
+ save_memory(module, tag, index, name, value.base, value.bpp / 8, value.rowpixels * value.height);
+}
+
+
+//-------------------------------------------------
+// save_item - specialized save_item for attotimes
+//-------------------------------------------------
+
+template<>
+inline void save_manager::save_item(const char *module, const char *tag, int index, attotime &value, const char *name)
+{
+ astring tempstr(name, ".attoseconds");
+ save_memory(module, tag, index, tempstr, &value.attoseconds, sizeof(value.attoseconds));
+ tempstr.cpy(name).cat(".seconds");
+ save_memory(module, tag, index, tempstr, &value.seconds, sizeof(value.seconds));
+}
+
+
+#endif /* __SAVE_H__ */
adice); TILE_GET_INFO_MEMBER(get_tile_info); virtual void machine_start(); virtual void machine_reset(); virtual void video_start(); virtual void palette_init(); }; WRITE8_MEMBER(dynadice_state::dynadice_videoram_w) { m_videoram[offset] = data; m_bg_tilemap->mark_tile_dirty(offset); m_top_tilemap->mark_all_dirty(); } WRITE8_MEMBER(dynadice_state::sound_data_w) { m_ay_data = data; } WRITE8_MEMBER(dynadice_state::sound_control_w) { device_t *device = machine().device("aysnd"); /* AY 3-8910 : D0 - BC1 D1 - BC2 D2 - BDIR D3 - /Reset */ if ((data & 7) == 7) ay8910_address_w(device, space, 0, m_ay_data); if ((data & 7) == 6) ay8910_data_w(device, space, 0, m_ay_data); } static ADDRESS_MAP_START( dynadice_map, AS_PROGRAM, 8, dynadice_state ) AM_RANGE(0x0000, 0x1fff) AM_ROM AM_RANGE(0x2000, 0x23ff) AM_RAM_WRITE(dynadice_videoram_w) AM_SHARE("videoram") AM_RANGE(0x4000, 0x40ff) AM_RAM AM_SHARE("nvram") ADDRESS_MAP_END static ADDRESS_MAP_START( dynadice_io_map, AS_IO, 8, dynadice_state ) AM_RANGE(0x50, 0x50) AM_READ_PORT("IN0") AM_RANGE(0x51, 0x51) AM_READ_PORT("IN1") AM_RANGE(0x52, 0x52) AM_READ_PORT("DSW") AM_RANGE(0x62, 0x62) AM_WRITENOP AM_RANGE(0x63, 0x63) AM_WRITE(soundlatch_byte_w) AM_RANGE(0x70, 0x77) AM_WRITENOP ADDRESS_MAP_END static ADDRESS_MAP_START( dynadice_sound_map, AS_PROGRAM, 8, dynadice_state ) AM_RANGE(0x0000, 0x07ff) AM_ROM AM_RANGE(0x2000, 0x23ff) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START( dynadice_sound_io_map, AS_IO, 8, dynadice_state ) ADDRESS_MAP_GLOBAL_MASK(0xff) AM_RANGE(0x00, 0x00) AM_READ(soundlatch_byte_r) AM_RANGE(0x01, 0x01) AM_WRITE(soundlatch_clear_byte_w) AM_RANGE(0x02, 0x02) AM_WRITE(sound_data_w) AM_RANGE(0x03, 0x03) AM_WRITE(sound_control_w) ADDRESS_MAP_END static INPUT_PORTS_START( dynadice ) PORT_START("IN0") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_DIPNAME( 0x02, 0x02, "Initialize NVRAM" ) PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_START("IN1") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) /* increase number of coins */ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* decrease number of coins */ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 ) /* start /stop */ PORT_START("DSW") PORT_DIPNAME( 0x1c, 0x1c, DEF_STR( Coinage ) ) PORT_DIPSETTING( 0x00, DEF_STR( 5C_1C )) PORT_DIPSETTING( 0x04, DEF_STR( 4C_1C )) PORT_DIPSETTING( 0x08, DEF_STR( 3C_1C )) PORT_DIPSETTING( 0x0c, DEF_STR( 2C_1C )) PORT_DIPSETTING( 0x1c, DEF_STR( 1C_1C )) PORT_DIPSETTING( 0x18, DEF_STR( 1C_2C )) PORT_DIPSETTING( 0x14, DEF_STR( 1C_3C )) PORT_DIPSETTING( 0x10, DEF_STR( 1C_4C )) PORT_DIPNAME( 0x01, 0x01, "DSW 1-0" ) PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x02, 0x02, "DSW 1-1" ) PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x20, 0x20, "DSW 1-5" ) PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x40, 0x40, "DSW 1-6" ) PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x80, 0x80, "DSW 1-7" ) PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) INPUT_PORTS_END static const gfx_layout charlayout = { 8,8, RGN_FRAC(1,1), 1, { 0 }, { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, 8*8 }; static const gfx_layout charlayout2 = { 8,8, RGN_FRAC(1,1), 3, { 5,6,7 }, { 0, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, { 0*8*8, 1*8*8, 2*8*8, 3*8*8, 4*8*8, 5*8*8, 6*8*8, 7*8*8 }, 8*8*8 }; static GFXDECODE_START( dynadice ) GFXDECODE_ENTRY( "gfx1", 0, charlayout, 0, 1 ) /* 1bpp */ GFXDECODE_ENTRY( "gfx2", 0, charlayout2, 0, 1 ) /* 3bpp */ GFXDECODE_END TILE_GET_INFO_MEMBER(dynadice_state::get_tile_info) { int code = m_videoram[tile_index]; SET_TILE_INFO_MEMBER(1, code, 0, 0); } void dynadice_state::video_start() { /* pacman - style videoram layout */ m_bg_tilemap = &machine().tilemap().create(tilemap_get_info_delegate(FUNC(dynadice_state::get_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32); m_top_tilemap = &machine().tilemap().create(tilemap_get_info_delegate(FUNC(dynadice_state::get_tile_info),this), TILEMAP_SCAN_COLS, 8, 8, 2, 32); m_bg_tilemap->set_scrollx(0, -16); } static SCREEN_UPDATE_IND16( dynadice ) { dynadice_state *state = screen.machine().driver_data<dynadice_state>(); rectangle myclip = cliprect; myclip.max_x = 15; state->m_bg_tilemap->draw(bitmap, cliprect, 0, 0); state->m_top_tilemap->draw(bitmap, myclip, 0, 0); return 0; } void dynadice_state::palette_init() { int i; for(i = 0; i < 8; i++) palette_set_color_rgb(machine(), i, pal1bit(i >> 1), pal1bit(i >> 2), pal1bit(i >> 0)); } void dynadice_state::machine_start() { save_item(NAME(m_ay_data)); } void dynadice_state::machine_reset() { m_ay_data = 0; } static MACHINE_CONFIG_START( dynadice, dynadice_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", I8080,18432000/8) MCFG_CPU_PROGRAM_MAP(dynadice_map) MCFG_CPU_IO_MAP(dynadice_io_map) MCFG_CPU_ADD("audiocpu", Z80,18432000/6) MCFG_CPU_PROGRAM_MAP(dynadice_sound_map) MCFG_CPU_IO_MAP(dynadice_sound_io_map) MCFG_NVRAM_ADD_0FILL("nvram") /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) MCFG_SCREEN_SIZE(256+16, 256) MCFG_SCREEN_VISIBLE_AREA(0*8, 34*8-1, 3*8, 28*8-1) MCFG_SCREEN_UPDATE_STATIC(dynadice) MCFG_GFXDECODE(dynadice) MCFG_PALETTE_LENGTH(8) MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("aysnd", AY8910, 2000000) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MACHINE_CONFIG_END ROM_START( dynadice ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD( "dy_1.bin", 0x0000, 0x1000, CRC(4ad18724) SHA1(78151b02a727f4272eff72765883df9ca09606c3) ) ROM_LOAD( "dy_2.bin", 0x1000, 0x0800, CRC(82cb1873) SHA1(661f33af4a536b7929d432d755ab44f9280f82db) ) ROM_LOAD( "dy_3.bin", 0x1800, 0x0800, CRC(a8edad20) SHA1(b812141f216355c986047969326bd1e036be71e6) ) ROM_REGION( 0x10000, "audiocpu", 0 ) ROM_LOAD( "dy_6.bin", 0x0000, 0x0800, CRC(d4e6e6a3) SHA1(84c0fcfd8326a4301accbd192df6e372b98ae537) ) ROM_REGION( 0x0800, "gfx1", 0 ) ROM_LOAD( "dy_4.bin", 0x0000, 0x0800, CRC(306b851b) SHA1(bf69ed126d32b31e1711ff23c5a75b8a8bd28207) ) ROM_REGION( 0x0800*8, "gfx2", ROMREGION_ERASE00 ) /* gfx data will be rearranged here for 8x8 3bpp tiles */ ROM_REGION( 0x0800, "user1",0 ) ROM_LOAD( "dy_5.bin", 0x0000, 0x0800, CRC(e4799462) SHA1(5cd0f003572540522d72706bc5a8fa6588553031) ) ROM_END DRIVER_INIT_MEMBER(dynadice_state,dynadice) { int i, j; UINT8 *usr1 = machine().root_device().memregion("user1")->base(); UINT8 *cpu2 = machine().root_device().memregion("audiocpu")->base(); UINT8 *gfx1 = machine().root_device().memregion("gfx1")->base(); UINT8 *gfx2 = machine().root_device().memregion("gfx2")->base(); cpu2[0x0b] = 0x23; /* bug in game code Dec HL -> Inc HL*/ /* 1bpp tiles -> 3bpp tiles (dy_5.bin contains bg/fg color data for each tile line) */ for (i = 0; i < 0x800; i++) for (j = 0; j < 8; j++) gfx2[(i << 3) + j] = (gfx1[i] & (0x80 >> j)) ? (usr1[i] & 7) : (usr1[i] >> 4); } GAME( 19??, dynadice, 0, dynadice, dynadice, dynadice_state, dynadice, ROT90, "<unknown>", "Dynamic Dice", GAME_SUPPORTS_SAVE )