summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2019-12-09 00:35:38 +1100
committer Vas Crabb <vas@vastheman.com>2019-12-09 00:35:38 +1100
commite6b4cdb3527bf7a799eb6b6b9f7df57aea8971ec (patch)
tree49f373544238a8e2458cc1de05039468a066a016
parentd3a70dc3460ef0b9c97fe16efb70db83bf012848 (diff)
Allow saving members of structures in n-dimensional arrays, even if the members themselves are n-dimensional arrays - see qsoundhle.cpp for an example of loops disappearing. This can greatly reduce the number of save state registrations in some cases. Obviously I want to know if save states are broken in something by this.
-rw-r--r--src/devices/cpu/tms9900/tms9995.cpp2
-rw-r--r--src/devices/sound/qsoundhle.cpp92
-rw-r--r--src/emu/debug/debugcmd.cpp8
-rw-r--r--src/emu/debug/dvmemory.cpp30
-rw-r--r--src/emu/debug/dvmemory.h16
-rw-r--r--src/emu/device.h18
-rw-r--r--src/emu/save.cpp93
-rw-r--r--src/emu/save.h136
-rw-r--r--src/frontend/mame/luaengine.cpp64
-rw-r--r--src/frontend/mame/luaengine.h3
-rw-r--r--src/mame/includes/orion.h1
-rw-r--r--src/mame/machine/osborne1.cpp2
-rw-r--r--src/mame/video/orion.cpp7
13 files changed, 282 insertions, 190 deletions
diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp
index 7bc077d1dd4..696b04fb870 100644
--- a/src/devices/cpu/tms9900/tms9995.cpp
+++ b/src/devices/cpu/tms9900/tms9995.cpp
@@ -1836,7 +1836,7 @@ void tms9995_device::mem_read()
// An on-chip memory access is also visible to the outside world ([1], 2.3.1.2)
// but only on word boundary, as only full words are read.
if (m_setaddr)
- m_setaddr->write_byte(m_address & 0xfffe, (TMS99xx_BUS_DBIN | (m_iaq? TMS99xx_BUS_IAQ : 0)));
+ m_setaddr->write_byte(m_address & 0xfffe, (TMS99xx_BUS_DBIN | (m_iaq? TMS99xx_BUS_IAQ : 0)));
// Always read a word from internal memory
m_current_value = (m_onchip_memory[intaddr] << 8) | m_onchip_memory[intaddr + 1];
diff --git a/src/devices/sound/qsoundhle.cpp b/src/devices/sound/qsoundhle.cpp
index 7cfe01391f4..a917728ed1f 100644
--- a/src/devices/sound/qsoundhle.cpp
+++ b/src/devices/sound/qsoundhle.cpp
@@ -70,29 +70,25 @@ void qsound_hle_device::device_start()
// state save
// PCM registers
- for (int j = 0; j < 16; j++) // PCM voices
- {
- save_item(NAME(m_voice[j].m_bank), j);
- save_item(NAME(m_voice[j].m_addr), j);
- save_item(NAME(m_voice[j].m_phase), j);
- save_item(NAME(m_voice[j].m_rate), j);
- save_item(NAME(m_voice[j].m_loop_len), j);
- save_item(NAME(m_voice[j].m_end_addr), j);
- save_item(NAME(m_voice[j].m_volume), j);
- save_item(NAME(m_voice[j].m_echo), j);
- }
-
- for (int j = 0; j < 3; j++) // ADPCM voices
- {
- save_item(NAME(m_adpcm[j].m_start_addr), j);
- save_item(NAME(m_adpcm[j].m_end_addr), j);
- save_item(NAME(m_adpcm[j].m_bank), j);
- save_item(NAME(m_adpcm[j].m_volume), j);
- save_item(NAME(m_adpcm[j].m_flag), j);
- save_item(NAME(m_adpcm[j].m_cur_vol), j);
- save_item(NAME(m_adpcm[j].m_step_size), j);
- save_item(NAME(m_adpcm[j].m_cur_addr), j);
- }
+ // PCM voices
+ save_item(STRUCT_MEMBER(m_voice, m_bank));
+ save_item(STRUCT_MEMBER(m_voice, m_addr));
+ save_item(STRUCT_MEMBER(m_voice, m_phase));
+ save_item(STRUCT_MEMBER(m_voice, m_rate));
+ save_item(STRUCT_MEMBER(m_voice, m_loop_len));
+ save_item(STRUCT_MEMBER(m_voice, m_end_addr));
+ save_item(STRUCT_MEMBER(m_voice, m_volume));
+ save_item(STRUCT_MEMBER(m_voice, m_echo));
+
+ // ADPCM voices
+ save_item(STRUCT_MEMBER(m_adpcm, m_start_addr));
+ save_item(STRUCT_MEMBER(m_adpcm, m_end_addr));
+ save_item(STRUCT_MEMBER(m_adpcm, m_bank));
+ save_item(STRUCT_MEMBER(m_adpcm, m_volume));
+ save_item(STRUCT_MEMBER(m_adpcm, m_flag));
+ save_item(STRUCT_MEMBER(m_adpcm, m_cur_vol));
+ save_item(STRUCT_MEMBER(m_adpcm, m_step_size));
+ save_item(STRUCT_MEMBER(m_adpcm, m_cur_addr));
// PCM voices
save_item(NAME(m_voice_pan));
@@ -105,32 +101,30 @@ void qsound_hle_device::device_start()
save_item(NAME(m_echo.m_delay_line));
save_item(NAME(m_echo.m_delay_pos));
- for (int j = 0; j < 2; j++) // left, right
- {
- save_item(NAME(m_filter[j].m_tap_count), j);
- save_item(NAME(m_filter[j].m_delay_pos), j);
- save_item(NAME(m_filter[j].m_table_pos), j);
- save_item(NAME(m_filter[j].m_taps), j);
- save_item(NAME(m_filter[j].m_delay_line), j);
-
- save_item(NAME(m_alt_filter[j].m_tap_count), j);
- save_item(NAME(m_alt_filter[j].m_delay_pos), j);
- save_item(NAME(m_alt_filter[j].m_table_pos), j);
- save_item(NAME(m_alt_filter[j].m_taps), j);
- save_item(NAME(m_alt_filter[j].m_delay_line), j);
-
- save_item(NAME(m_wet[j].m_delay), j);
- save_item(NAME(m_wet[j].m_volume), j);
- save_item(NAME(m_wet[j].m_write_pos), j);
- save_item(NAME(m_wet[j].m_read_pos), j);
- save_item(NAME(m_wet[j].m_delay_line), j);
-
- save_item(NAME(m_dry[j].m_delay), j);
- save_item(NAME(m_dry[j].m_volume), j);
- save_item(NAME(m_dry[j].m_write_pos), j);
- save_item(NAME(m_dry[j].m_read_pos), j);
- save_item(NAME(m_dry[j].m_delay_line), j);
- }
+ // left, right
+ save_item(STRUCT_MEMBER(m_filter, m_tap_count));
+ save_item(STRUCT_MEMBER(m_filter, m_delay_pos));
+ save_item(STRUCT_MEMBER(m_filter, m_table_pos));
+ save_item(STRUCT_MEMBER(m_filter, m_taps));
+ save_item(STRUCT_MEMBER(m_filter, m_delay_line));
+
+ save_item(STRUCT_MEMBER(m_alt_filter, m_tap_count));
+ save_item(STRUCT_MEMBER(m_alt_filter, m_delay_pos));
+ save_item(STRUCT_MEMBER(m_alt_filter, m_table_pos));
+ save_item(STRUCT_MEMBER(m_alt_filter, m_taps));
+ save_item(STRUCT_MEMBER(m_alt_filter, m_delay_line));
+
+ save_item(STRUCT_MEMBER(m_wet, m_delay));
+ save_item(STRUCT_MEMBER(m_wet, m_volume));
+ save_item(STRUCT_MEMBER(m_wet, m_write_pos));
+ save_item(STRUCT_MEMBER(m_wet, m_read_pos));
+ save_item(STRUCT_MEMBER(m_wet, m_delay_line));
+
+ save_item(STRUCT_MEMBER(m_dry, m_delay));
+ save_item(STRUCT_MEMBER(m_dry, m_volume));
+ save_item(STRUCT_MEMBER(m_dry, m_write_pos));
+ save_item(STRUCT_MEMBER(m_dry, m_read_pos));
+ save_item(STRUCT_MEMBER(m_dry, m_delay_line));
save_item(NAME(m_state));
save_item(NAME(m_next_state));
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index fa877cafd34..fa65b327d6c 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -114,16 +114,16 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
/* add all single-entry save state globals */
for (int itemnum = 0; itemnum < MAX_GLOBALS; itemnum++)
{
- u32 valsize, valcount;
void *base;
+ u32 valsize, valcount, blockcount, stride;
/* stop when we run out of items */
- const char* name = m_machine.save().indexed_item(itemnum, base, valsize, valcount);
- if (name == nullptr)
+ const char* name = m_machine.save().indexed_item(itemnum, base, valsize, valcount, blockcount, stride);
+ if (!name)
break;
/* if this is a single-entry global, add it */
- if (valcount == 1 && strstr(name, "/globals/"))
+ if ((valcount == 1) && (blockcount == 1) && strstr(name, "/globals/"))
{
char symname[100];
sprintf(symname, ".%s", strrchr(name, '/') + 1);
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index 95fb412ba89..11932d6bab0 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -54,7 +54,9 @@ debug_view_memory_source::debug_view_memory_source(std::string &&name, address_s
, m_space(&space)
, m_memintf(dynamic_cast<device_memory_interface *>(&space.device()))
, m_base(nullptr)
- , m_length(0)
+ , m_blocklength(0)
+ , m_numblocks(0)
+ , m_blockstride(0)
, m_offsetxor(0)
, m_endianness(space.endianness())
, m_prefsize(space.data_width() / 8)
@@ -66,19 +68,23 @@ debug_view_memory_source::debug_view_memory_source(std::string &&name, memory_re
, m_space(nullptr)
, m_memintf(nullptr)
, m_base(region.base())
- , m_length(region.bytes())
+ , m_blocklength(region.bytes())
+ , m_numblocks(1)
+ , m_blockstride(0)
, m_offsetxor(ENDIAN_VALUE_NE_NNE(region.endianness(), 0, region.bytewidth() - 1))
, m_endianness(region.endianness())
, m_prefsize(std::min<u8>(region.bytewidth(), 8))
{
}
-debug_view_memory_source::debug_view_memory_source(std::string &&name, void *base, int element_size, int num_elements)
+debug_view_memory_source::debug_view_memory_source(std::string &&name, void *base, int element_size, int num_elements, int num_blocks, int block_stride)
: debug_view_source(std::move(name))
, m_space(nullptr)
, m_memintf(nullptr)
, m_base(base)
- , m_length(element_size * num_elements)
+ , m_blocklength(element_size * num_elements)
+ , m_numblocks(num_blocks)
+ , m_blockstride(element_size * block_stride)
, m_offsetxor(0)
, m_endianness(ENDIANNESS_NATIVE)
, m_prefsize(std::min(element_size, 8))
@@ -168,14 +174,14 @@ void debug_view_memory::enumerate_sources()
std::size_t const firstsave = m_source_list.size();
for (int itemnum = 0; itemnum < machine().save().registration_count(); itemnum++)
{
- u32 valsize, valcount;
+ u32 valsize, valcount, blockcount, stride;
void *base;
- name = machine().save().indexed_item(itemnum, base, valsize, valcount);
+ name = machine().save().indexed_item(itemnum, base, valsize, valcount, blockcount, stride);
// add pretty much anything that's not a timer (we may wish to cull other items later)
// also, don't trim the front of the name, it's important to know which VIA6522 we're looking at, e.g.
if (strncmp(name.c_str(), "timer/", 6))
- m_source_list.emplace_back(std::make_unique<debug_view_memory_source>(std::move(name), base, valsize, valcount));
+ m_source_list.emplace_back(std::make_unique<debug_view_memory_source>(std::move(name), base, valsize, valcount, blockcount, stride));
}
std::sort(
std::next(m_source_list.begin(), firstsave),
@@ -562,7 +568,7 @@ void debug_view_memory::recompute()
}
else
{
- maxbyte = m_maxaddr = source.m_length - 1;
+ maxbyte = m_maxaddr = (source.m_blocklength * source.m_numblocks) - 1;
addrchars = string_format("%X", m_maxaddr).size();
}
@@ -808,9 +814,9 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data)
// all 0xff if out of bounds
offs ^= source.m_offsetxor;
- if (offs >= source.m_length)
+ if (offs >= (source.m_blocklength * source.m_numblocks))
return false;
- data = *((u8 *)source.m_base + offs);
+ data = *(reinterpret_cast<const u8 *>(source.m_base) + (offs / source.m_blocklength * source.m_blockstride) + (offs % source.m_blocklength));
return true;
}
@@ -907,9 +913,9 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data)
// ignore if out of bounds
offs ^= source.m_offsetxor;
- if (offs >= source.m_length)
+ if (offs >= (source.m_blocklength * source.m_numblocks))
return;
- *((u8 *)source.m_base + offs) = data;
+ *(reinterpret_cast<u8 *>(source.m_base) + (offs / source.m_blocklength * source.m_blockstride) + (offs % source.m_blocklength)) = data;
// hack for FD1094 editing
#ifdef FD1094_HACK
diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h
index de7cf8b5af5..05138c2ba0c 100644
--- a/src/emu/debug/dvmemory.h
+++ b/src/emu/debug/dvmemory.h
@@ -30,18 +30,20 @@ class debug_view_memory_source : public debug_view_source
public:
debug_view_memory_source(std::string &&name, address_space &space);
debug_view_memory_source(std::string &&name, memory_region &region);
- debug_view_memory_source(std::string &&name, void *base, int element_size, int num_elements);
+ debug_view_memory_source(std::string &&name, void *base, int element_size, int num_elements, int num_blocks, int block_stride);
address_space *space() const { return m_space; }
private:
- address_space *m_space; // address space we reference (if any)
+ address_space *m_space; // address space we reference (if any)
device_memory_interface *m_memintf; // pointer to the memory interface of the device
- void * m_base; // pointer to memory base
- offs_t m_length; // length of memory
- offs_t m_offsetxor; // XOR to apply to offsets
- endianness_t m_endianness; // endianness of memory
- u8 m_prefsize; // preferred bytes per chunk
+ void * m_base; // pointer to memory base
+ offs_t m_blocklength; // length of each block of memory
+ offs_t m_numblocks; // number of blocks of memory
+ offs_t m_blockstride; // stride between blocks of memory
+ offs_t m_offsetxor; // XOR to apply to offsets
+ endianness_t m_endianness; // endianness of memory
+ u8 m_prefsize; // preferred bytes per chunk
};
diff --git a/src/emu/device.h b/src/emu/device.h
index 6e729402989..11798068259 100644
--- a/src/emu/device.h
+++ b/src/emu/device.h
@@ -610,9 +610,23 @@ public:
// state saving interfaces
template<typename ItemType>
- void ATTR_COLD save_item(ItemType &&value, const char *valname, int index = 0) { assert(m_save != nullptr); m_save->save_item(this, name(), tag(), index, std::forward<ItemType>(value), valname); }
+ void ATTR_COLD save_item(ItemType &&value, const char *valname, int index = 0)
+ {
+ assert(m_save);
+ m_save->save_item(this, name(), tag(), index, std::forward<ItemType>(value), valname);
+ }
+ template<typename ItemType, typename ElementType>
+ void ATTR_COLD save_item(ItemType &&value, ElementType save_manager::array_unwrap<std::remove_reference_t<ItemType> >::underlying_type::*element, const char *valname, int index = 0)
+ {
+ assert(m_save);
+ m_save->save_item(this, name(), tag(), index, std::forward<ItemType>(value), element, valname);
+ }
template<typename ItemType>
- void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0) { assert(m_save != nullptr); m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count); }
+ void ATTR_COLD save_pointer(ItemType &&value, const char *valname, u32 count, int index = 0)
+ {
+ assert(m_save);
+ m_save->save_pointer(this, name(), tag(), index, std::forward<ItemType>(value), valname, count);
+ }
// debugging
device_debug *debug() const { return m_debug.get(); }
diff --git a/src/emu/save.cpp b/src/emu/save.cpp
index 035235e673d..72a164345f2 100644
--- a/src/emu/save.cpp
+++ b/src/emu/save.cpp
@@ -82,12 +82,12 @@ void save_manager::allow_registration(bool allowed)
{
// look for duplicates
std::sort(m_entry_list.begin(), m_entry_list.end(),
- [](std::unique_ptr<state_entry> const& a, std::unique_ptr<state_entry> const& b) { return a->m_name < b->m_name; });
+ [] (std::unique_ptr<state_entry> const& a, std::unique_ptr<state_entry> const& b) { return a->m_name < b->m_name; });
int dupes_found = 0;
- for (int i = 0; i < m_entry_list.size() - 1; i++)
+ for (int i = 1; i < m_entry_list.size(); i++)
{
- if (m_entry_list[i]->m_name == m_entry_list[i + 1]->m_name)
+ if (m_entry_list[i - 1]->m_name == m_entry_list[i]->m_name)
{
osd_printf_error("Duplicate save state registration entry (%s)\n", m_entry_list[i]->m_name);
dupes_found++;
@@ -110,7 +110,7 @@ void save_manager::allow_registration(bool allowed)
// index
//-------------------------------------------------
-const char *save_manager::indexed_item(int index, void *&base, u32 &valsize, u32 &valcount) const
+const char *save_manager::indexed_item(int index, void *&base, u32 &valsize, u32 &valcount, u32 &blockcount, u32 &stride) const
{
if (index >= m_entry_list.size() || index < 0)
return nullptr;
@@ -119,6 +119,8 @@ const char *save_manager::indexed_item(int index, void *&base, u32 &valsize, u32
base = entry->m_data;
valsize = entry->m_typesize;
valcount = entry->m_typecount;
+ blockcount = entry->m_blockcount;
+ stride = entry->m_stride;
return entry->m_name.c_str();
}
@@ -171,9 +173,10 @@ void save_manager::register_postload(save_prepost_delegate func)
// memory
//-------------------------------------------------
-void save_manager::save_memory(device_t *device, const char *module, const char *tag, u32 index, const char *name, void *val, u32 valsize, u32 valcount)
+void save_manager::save_memory(device_t *device, const char *module, const char *tag, u32 index, const char *name, void *val, u32 valsize, u32 valcount, u32 blockcount, u32 stride)
{
assert(valsize == 1 || valsize == 2 || valsize == 4 || valsize == 8);
+ assert(((blockcount <= 1) && (stride == 0)) || (stride >= valcount));
// check for invalid timing
if (!m_reg_allowed)
@@ -193,7 +196,7 @@ void save_manager::save_memory(device_t *device, const char *module, const char
totalname = string_format("%s/%X/%s", module, index, name);
// insert us into the list
- m_entry_list.emplace_back(std::make_unique<state_entry>(val, totalname.c_str(), device, module, tag ? tag : "", index, valsize, valcount));
+ m_entry_list.emplace_back(std::make_unique<state_entry>(val, totalname.c_str(), device, module, tag ? tag : "", index, valsize, valcount, blockcount, stride));
}
@@ -265,9 +268,11 @@ save_error save_manager::read_file(emu_file &file)
// read all the data, flipping if necessary
for (auto &entry : m_entry_list)
{
- u32 totalsize = entry->m_typesize * entry->m_typecount;
- if (file.read(entry->m_data, totalsize) != totalsize)
- return STATERR_READ_ERROR;
+ const u32 blocksize = entry->m_typesize * entry->m_typecount;
+ u8 *data = reinterpret_cast<u8 *>(entry->m_data);
+ for (u32 b = 0; entry->m_blockcount > b; ++b, data += (entry->m_typesize * entry->m_stride))
+ if (file.read(data, blocksize) != blocksize)
+ return STATERR_READ_ERROR;
// handle flipping
if (flip)
@@ -325,9 +330,11 @@ save_error save_manager::write_file(emu_file &file)
// then write all the data
for (auto &entry : m_entry_list)
{
- u32 totalsize = entry->m_typesize * entry->m_typecount;
- if (file.write(entry->m_data, totalsize) != totalsize)
- return STATERR_WRITE_ERROR;
+ const u32 blocksize = entry->m_typesize * entry->m_typecount;
+ const u8 *data = reinterpret_cast<const u8 *>(entry->m_data);
+ for (u32 b = 0; entry->m_blockcount > b; ++b, data += (entry->m_typesize * entry->m_stride))
+ if (file.write(data, blocksize) != blocksize)
+ return STATERR_WRITE_ERROR;
}
return STATERR_NONE;
}
@@ -348,9 +355,11 @@ u32 save_manager::signature() const
crc = core_crc32(crc, (u8 *)entry->m_name.c_str(), entry->m_name.length());
// add the type and size to the CRC
- u32 temp[2];
- temp[0] = little_endianize_int32(entry->m_typecount);
- temp[1] = little_endianize_int32(entry->m_typesize);
+ u32 temp[4];
+ temp[0] = little_endianize_int32(entry->m_typesize);
+ temp[1] = little_endianize_int32(entry->m_typecount);
+ temp[2] = little_endianize_int32(entry->m_blockcount);
+ temp[3] = little_endianize_int32(entry->m_stride);
crc = core_crc32(crc, (u8 *)&temp[0], sizeof(temp));
}
return crc;
@@ -365,7 +374,7 @@ u32 save_manager::signature() const
void save_manager::dump_registry() const
{
for (auto &entry : m_entry_list)
- LOG(("%s: %d x %d\n", entry->m_name.c_str(), entry->m_typesize, entry->m_typecount));
+ LOG(("%s: %u x %u x %u (%u)\n", entry->m_name.c_str(), entry->m_typesize, entry->m_typecount, entry->m_blockcount, entry->m_stride));
}
@@ -454,9 +463,7 @@ size_t ram_state::get_size(save_manager &save)
size_t totalsize = 0;
for (auto &entry : save.m_entry_list)
- {
- totalsize += entry->m_typesize * entry->m_typecount;
- }
+ totalsize += entry->m_typesize * entry->m_typecount * entry->m_blockcount;
return totalsize + HEADER_SIZE;
}
@@ -499,8 +506,10 @@ save_error ram_state::save()
// write all the data
for (auto &entry : m_save.m_entry_list)
{
- u32 totalsize = entry->m_typesize * entry->m_typecount;
- m_data.write((char *)entry->m_data, totalsize);
+ const u32 blocksize = entry->m_typesize * entry->m_typecount;
+ const char *data = reinterpret_cast<const char *>(entry->m_data);
+ for (u32 b = 0; entry->m_blockcount > b; ++b, data += (entry->m_typesize * entry->m_stride))
+ m_data.write(data, blocksize);
// check for any errors
if (!m_data)
@@ -548,8 +557,10 @@ save_error ram_state::load()
// read all the data, flipping if necessary
for (auto &entry : m_save.m_entry_list)
{
- u32 totalsize = entry->m_typesize * entry->m_typecount;
- m_data.read((char *)entry->m_data, totalsize);
+ const u32 blocksize = entry->m_typesize * entry->m_typecount;
+ char *data = reinterpret_cast<char *>(entry->m_data);
+ for (u32 b = 0; entry->m_blockcount > b; ++b, data += (entry->m_typesize * entry->m_stride))
+ m_data.read(data, blocksize);
// check for any errors
if (!m_data)
@@ -880,7 +891,7 @@ void rewinder::report_error(save_error error, rewind_operation operation)
// state_entry - constructor
//-------------------------------------------------
-state_entry::state_entry(void *data, const char *name, device_t *device, const char *module, const char *tag, int index, u8 size, u32 count)
+save_manager::state_entry::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)
: m_data(data)
, m_name(name)
, m_device(device)
@@ -888,8 +899,9 @@ state_entry::state_entry(void *data, const char *name, device_t *device, const c
, m_tag(tag)
, m_index(index)
, m_typesize(size)
- , m_typecount(count)
- , m_offset(0)
+ , m_typecount(valcount)
+ , m_blockcount(blockcount)
+ , m_stride(stride)
{
}
@@ -899,31 +911,34 @@ state_entry::state_entry(void *data, const char *name, device_t *device, const c
// block of data
//-------------------------------------------------
-void state_entry::flip_data()
+void save_manager::state_entry::flip_data()
{
- u16 *data16;
- u32 *data32;
- u64 *data64;
- int count;
-
- switch (m_typesize)
+ u8 *data = reinterpret_cast<u8 *>(m_data);
+ for (u32 b = 0; m_blockcount > b; ++b, data += (m_typesize * m_stride))
{
+ u16 *data16;
+ u32 *data32;
+ u64 *data64;
+
+ switch (m_typesize)
+ {
case 2:
- data16 = (u16 *)m_data;
- for (count = 0; count < m_typecount; count++)
+ data16 = reinterpret_cast<u16 *>(data);
+ for (u32 count = 0; count < m_typecount; count++)
data16[count] = swapendian_int16(data16[count]);
break;
case 4:
- data32 = (u32 *)m_data;
- for (count = 0; count < m_typecount; count++)
+ data32 = reinterpret_cast<u32 *>(data);
+ for (u32 count = 0; count < m_typecount; count++)
data32[count] = swapendian_int32(data32[count]);
break;
case 8:
- data64 = (u64 *)m_data;
- for (count = 0; count < m_typecount; count++)
+ data64 = reinterpret_cast<u64 *>(data);
+ for (u32 count = 0; count < m_typecount; count++)
data64[count] = swapendian_int64(data64[count]);
break;
+ }
}
}
diff --git a/src/emu/save.h b/src/emu/save.h
index a5ae5437414..5fe6c143c4b 100644
--- a/src/emu/save.h
+++ b/src/emu/save.h
@@ -18,6 +18,8 @@
#define MAME_EMU_SAVE_H
#include <array>
+#include <cassert>
+#include <type_traits>
@@ -50,44 +52,56 @@ typedef named_delegate<void ()> save_prepost_delegate;
// 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; }
+ template <> struct save_manager::type_checker<TYPE> { static constexpr bool is_atom = true; static constexpr bool is_pointer = false; }
// use this as above, but also to declare that std::vector<TYPE> is safe as well
#define ALLOW_SAVE_TYPE_AND_ARRAY(TYPE) \
ALLOW_SAVE_TYPE(TYPE); \
- template<> inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, std::vector<TYPE> &value, const char *name) { save_memory(device, module, tag, index, name, &value[0], sizeof(TYPE), value.size()); }
+ template <> inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, std::vector<TYPE> &value, const char *name) { save_memory(device, module, tag, index, name, &value[0], sizeof(TYPE), value.size()); }
+
+// use this for saving members of structures in arrays
+#define STRUCT_MEMBER(s, m) s, &save_manager::array_unwrap<std::remove_reference_t<decltype(s)> >::underlying_type::m, #s "." #m
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-class state_entry
-{
-public:
- // construction/destruction
- state_entry(void *data, const char *name, device_t *device, const char *module, const char *tag, int index, u8 size, u32 count);
-
- // helpers
- void flip_data();
-
- // state
- void * m_data; // pointer to the memory to save/restore
- std::string m_name; // full name
- device_t * m_device; // associated device, nullptr if none
- std::string m_module; // module name
- std::string m_tag; // tag name
- int m_index; // index
- u8 m_typesize; // size of the raw data type
- u32 m_typecount; // number of items
- u32 m_offset; // offset within the final structure
-};
-
class ram_state;
class rewinder;
class save_manager
{
+ // type_checker is a set of templates to identify valid save types
+ template <typename ItemType> struct type_checker { static constexpr bool is_atom = false; static constexpr bool is_pointer = false; };
+ template <typename ItemType> struct type_checker<ItemType*> { static constexpr bool is_atom = false; static constexpr bool is_pointer = true; };
+
+ class state_entry
+ {
+ public:
+ // construction/destruction
+ 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);
+
+ // helpers
+ void flip_data();
+
+ // state
+ void * m_data; // pointer to the memory to save/restore
+ std::string m_name; // full name
+ device_t * m_device; // associated device, nullptr if none
+ std::string m_module; // module name
+ std::string m_tag; // tag name
+ int m_index; // index
+ u8 m_typesize; // size of the raw data type
+ u32 m_typecount; // number of items in each block
+ u32 m_blockcount; // number of blocks of items
+ u32 m_stride; // stride between blocks of items in units of item size
+ };
+
+ friend class ram_state;
+ friend class rewinder;
+
+public:
// stuff for working with arrays
template <typename T> struct array_unwrap
{
@@ -111,14 +125,6 @@ class save_manager
static underlying_type *ptr(std::array<T, N> &value) { return array_unwrap<T>::ptr(value[0]); }
};
- // 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; };
-
- friend class ram_state;
- friend class rewinder;
-
-public:
// construction/destruction
save_manager(running_machine &machine);
@@ -130,7 +136,7 @@ public:
// registration control
void allow_registration(bool allowed = true);
- const char *indexed_item(int index, void *&base, u32 &valsize, u32 &valcount) const;
+ const char *indexed_item(int index, void *&base, u32 &valsize, u32 &valcount, u32 &blockcount, u32 &stride) const;
// function registration
void register_presave(save_prepost_delegate func);
@@ -141,41 +147,65 @@ public:
void dispatch_postload();
// generic memory registration
- void save_memory(device_t *device, const char *module, const char *tag, u32 index, const char *name, void *val, u32 valsize, u32 valcount = 1);
+ 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);
// templatized wrapper for general objects and arrays
- template<typename ItemType>
+ template <typename ItemType>
void save_item(device_t *device, 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<typename array_unwrap<ItemType>::underlying_type>::is_atom)
- throw emu_fatalerror("Called save_item on a non-fundamental type, name %s!", valname);
+ static_assert(!type_checker<ItemType>::is_pointer, "Called save_item on a pointer with no count!");
+ static_assert(type_checker<typename array_unwrap<ItemType>::underlying_type>::is_atom, "Called save_item on a non-fundamental type!");
save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT);
}
+ // templatized wrapper for structure members
+ template <typename ItemType, typename ElementType>
+ void save_item(device_t *device, const char *module, const char *tag, int index, ItemType &value, ElementType array_unwrap<ItemType>::underlying_type::*element, const char *valname)
+ {
+ static_assert(!(sizeof(typename array_unwrap<ItemType>::underlying_type) % sizeof(typename array_unwrap<ElementType>::underlying_type)), "Called save_item on an unaligned struct member!");
+ static_assert(!type_checker<ElementType>::is_pointer, "Called save_item on a struct member pointer!");
+ static_assert(type_checker<typename array_unwrap<ElementType>::underlying_type>::is_atom, "Called save_item on a non-fundamental type!");
+ 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) / sizeof(typename array_unwrap<ElementType>::underlying_type));
+ }
+
// templatized wrapper for pointers
- template<typename ItemType>
+ template <typename ItemType>
void save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, const char *valname, u32 count)
{
- if (!type_checker<typename array_unwrap<ItemType>::underlying_type>::is_atom)
- throw emu_fatalerror("Called save_item on a non-fundamental type, name %s!", valname);
+ static_assert(type_checker<typename array_unwrap<ItemType>::underlying_type>::is_atom, "Called save_pointer on a non-fundamental type!");
save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value[0]), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT * count);
}
+ template <typename ItemType, typename ElementType>
+ void save_pointer(device_t *device, const char *module, const char *tag, int index, ItemType *value, ElementType array_unwrap<ItemType>::underlying_type::*element, const char *valname, u32 count)
+ {
+ static_assert(!(sizeof(typename array_unwrap<ItemType>::underlying_type) % sizeof(typename array_unwrap<ElementType>::underlying_type)), "Called save_pointer on an unaligned struct member!");
+ static_assert(!type_checker<ElementType>::is_pointer, "Called save_pointer on a struct member pointer!");
+ static_assert(type_checker<typename array_unwrap<ElementType>::underlying_type>::is_atom, "Called save_pointer on a non-fundamental type!");
+ 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) / sizeof(typename array_unwrap<ElementType>::underlying_type));
+ }
+
// templatized wrapper for std::unique_ptr
- template<typename ItemType>
- void save_pointer(device_t *device, const char *module, const char *tag, int index, std::unique_ptr<ItemType[]> &value, const char *valname, u32 count)
+ template <typename ItemType>
+ void save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, const char *valname, u32 count)
{
- if (!type_checker<typename array_unwrap<ItemType>::underlying_type>::is_atom)
- throw emu_fatalerror("Called save_item on a non-fundamental type, name %s!", valname);
+ static_assert(type_checker<typename array_unwrap<ItemType>::underlying_type>::is_atom, "Called save_pointer on a non-fundamental type!");
save_memory(device, module, tag, index, valname, array_unwrap<ItemType>::ptr(value[0]), array_unwrap<ItemType>::SIZE, array_unwrap<ItemType>::SAVE_COUNT * count);
}
+ template <typename ItemType, typename ElementType>
+ void save_pointer(device_t *device, const char *module, const char *tag, int index, const std::unique_ptr<ItemType []> &value, ElementType array_unwrap<ItemType>::underlying_type::*element, const char *valname, u32 count)
+ {
+ static_assert(!(sizeof(typename array_unwrap<ItemType>::underlying_type) % sizeof(typename array_unwrap<ElementType>::underlying_type)), "Called save_pointer on an unaligned struct member!");
+ static_assert(!type_checker<ElementType>::is_pointer, "Called save_pointer on a struct member pointer!");
+ static_assert(type_checker<typename array_unwrap<ElementType>::underlying_type>::is_atom, "Called save_pointer on a non-fundamental type!");
+ 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) / sizeof(typename array_unwrap<ElementType>::underlying_type));
+ }
+
// global memory registration
- template<typename ItemType>
+ template <typename ItemType>
void save_item(ItemType &value, const char *valname, int index = 0) { save_item(nullptr, "global", nullptr, index, value, valname); }
- template<typename ItemType>
+ template <typename ItemType>
void save_pointer(ItemType *value, const char *valname, u32 count, int index = 0) { save_pointer(nullptr, "global", nullptr, index, value, valname, count); }
// file processing
@@ -292,25 +322,25 @@ ALLOW_SAVE_TYPE_AND_ARRAY(rgb_t)
// save_item - specialized save_item for bitmaps
//-------------------------------------------------
-template<>
+template <>
inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind8 &value, const char *name)
{
save_memory(device, module, tag, index, name, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height());
}
-template<>
+template <>
inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind16 &value, const char *name)
{
save_memory(device, module, tag, index, name, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height());
}
-template<>
+template <>
inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, bitmap_ind32 &value, const char *name)
{
save_memory(device, module, tag, index, name, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height());
}
-template<>
+template <>
inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, bitmap_rgb32 &value, const char *name)
{
save_memory(device, module, tag, index, name, &value.pix(0), value.bpp() / 8, value.rowpixels() * value.height());
@@ -321,7 +351,7 @@ inline void save_manager::save_item(device_t *device, const char *module, const
// save_item - specialized save_item for attotimes
//-------------------------------------------------
-template<>
+template <>
inline void save_manager::save_item(device_t *device, const char *module, const char *tag, int index, attotime &value, const char *name)
{
std::string tempstr = std::string(name).append(".attoseconds");
@@ -331,4 +361,4 @@ inline void save_manager::save_item(device_t *device, const char *module, const
}
-#endif /* MAME_EMU_SAVE_H */
+#endif // MAME_EMU_SAVE_H
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 35fae5c436a..2e1273bfcc1 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -8,7 +8,6 @@
***************************************************************************/
-#include <thread>
#include <lua.hpp>
#include "emu.h"
#include "mame.h"
@@ -27,6 +26,10 @@
#include "softlist.h"
#include "inputdev.h"
+#include <cstring>
+#include <thread>
+
+
#ifdef __clang__
#pragma clang diagnostic ignored "-Wshift-count-overflow"
#endif
@@ -1072,61 +1075,88 @@ void lua_engine::initialize()
*/
auto item_type = emu.create_simple_usertype<save_item>(sol::call_constructor, sol::initializers([this](save_item &item, int index) {
- if(!machine().save().indexed_item(index, item.base, item.size, item.count))
+ if(machine().save().indexed_item(index, item.base, item.size, item.valcount, item.blockcount, item.stride))
+ {
+ item.count = item.valcount * item.blockcount;
+ }
+ else
{
item.base = nullptr;
item.size = 0;
- item.count= 0;
+ item.count = 0;
+ item.valcount = 0;
+ item.blockcount = 0;
+ item.stride = 0;
}
}));
item_type.set("size", sol::readonly(&save_item::size));
item_type.set("count", sol::readonly(&save_item::count));
item_type.set("read", [this](save_item &item, int offset) -> sol::object {
- uint64_t ret = 0;
- if(!item.base || (offset > item.count))
+ if(!item.base || (offset >= item.count))
return sol::make_object(sol(), sol::nil);
+ const void *const data = reinterpret_cast<const uint8_t *>(item.base) + (item.size * item.stride * (offset / item.valcount));
+ uint64_t ret = 0;
switch(item.size)
{
case 1:
default:
- ret = ((uint8_t *)item.base)[offset];
+ ret = reinterpret_cast<const uint8_t *>(data)[offset % item.valcount];
break;
case 2:
- ret = ((uint16_t *)item.base)[offset];
+ ret = reinterpret_cast<const uint16_t *>(data)[offset % item.valcount];
break;
case 4:
- ret = ((uint32_t *)item.base)[offset];
+ ret = reinterpret_cast<const uint32_t *>(data)[offset % item.valcount];
break;
case 8:
- ret = ((uint64_t *)item.base)[offset];
+ ret = reinterpret_cast<const uint64_t *>(data)[offset % item.valcount];
break;
}
return sol::make_object(sol(), ret);
});
item_type.set("read_block", [](save_item &item, int offset, sol::buffer *buff) {
if(!item.base || ((offset + buff->get_len()) > (item.size * item.count)))
+ {
buff->set_len(0);
+ }
else
- memcpy(buff->get_ptr(), (uint8_t *)item.base + offset, buff->get_len());
+ {
+ const uint32_t blocksize = item.size * item.valcount;
+ const uint32_t bytestride = item.size * item.stride;
+ uint32_t remaining = buff->get_len();
+ uint8_t *dest = reinterpret_cast<uint8_t *>(buff->get_ptr());
+ while(remaining)
+ {
+ const uint32_t blockno = offset / blocksize;
+ const uint32_t available = blocksize - (offset % blocksize);
+ const uint32_t chunk = (available < remaining) ? available : remaining;
+ const void *const source = reinterpret_cast<const uint8_t *>(item.base) + (blockno * bytestride) + (offset % blocksize);
+ std::memcpy(dest, source, chunk);
+ offset += chunk;
+ remaining -= chunk;
+ dest += chunk;
+ }
+ }
return buff;
});
item_type.set("write", [](save_item &item, int offset, uint64_t value) {
- if(!item.base || (offset > item.count))
+ if(!item.base || (offset >= item.count))
return;
+ void *const data = reinterpret_cast<uint8_t *>(item.base) + (item.size * item.stride * (offset / item.valcount));
switch(item.size)
{
case 1:
default:
- ((uint8_t *)item.base)[offset] = (uint8_t)value;
+ reinterpret_cast<uint8_t *>(data)[offset % item.valcount] = uint8_t(value);
break;
case 2:
- ((uint16_t *)item.base)[offset] = (uint16_t)value;
+ reinterpret_cast<uint16_t *>(data)[offset % item.valcount] = uint16_t(value);
break;
case 4:
- ((uint32_t *)item.base)[offset] = (uint32_t)value;
+ reinterpret_cast<uint32_t *>(data)[offset % item.valcount] = uint32_t(value);
break;
case 8:
- ((uint64_t *)item.base)[offset] = (uint64_t)value;
+ reinterpret_cast<uint64_t *>(data)[offset % item.valcount] = uint64_t(value);
break;
}
});
@@ -1611,9 +1641,9 @@ void lua_engine::initialize()
{
std::string name;
const char *item;
- unsigned int size, count;
void *base;
- item = dev.machine().save().indexed_item(i, base, size, count);
+ uint32_t size, valcount, blockcount, stride;
+ item = dev.machine().save().indexed_item(i, base, size, valcount, blockcount, stride);
if(!item)
break;
name = &(strchr(item, '/')[1]);
diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h
index 869b875d178..28bf3b60ca2 100644
--- a/src/frontend/mame/luaengine.h
+++ b/src/frontend/mame/luaengine.h
@@ -157,6 +157,9 @@ private:
void *base;
unsigned int size;
unsigned int count;
+ unsigned int valcount;
+ unsigned int blockcount;
+ unsigned int stride;
};
void close();
diff --git a/src/mame/includes/orion.h b/src/mame/includes/orion.h
index 0ec84fa7513..bde29a8b601 100644
--- a/src/mame/includes/orion.h
+++ b/src/mame/includes/orion.h
@@ -79,7 +79,6 @@ protected:
DECLARE_READ8_MEMBER(orionpro_io_r);
DECLARE_WRITE8_MEMBER(orionpro_io_w);
DECLARE_MACHINE_START(orion128);
- DECLARE_MACHINE_RESET(orion128);
void orion128_palette(palette_device &palette) const;
uint32_t screen_update_orion128(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(orionz80_interrupt);
diff --git a/src/mame/machine/osborne1.cpp b/src/mame/machine/osborne1.cpp
index 3429c6fab10..807ba5229f5 100644
--- a/src/mame/machine/osborne1.cpp
+++ b/src/mame/machine/osborne1.cpp
@@ -466,7 +466,7 @@ TIMER_CALLBACK_MEMBER(osborne1_state::video_callback)
m_beep_state = (ra & 0x04) ? 1 : 0;
m_speaker->level_w((m_beep_state && BIT(m_pia1->b_output(), 5)) ? 1 : 0);
- int const next((10 * (y / 10)) + ((ra < 4) ? 4 : (ra < 8) ? 8 : 14));
+ int const next((y - ra) + ((ra < 4) ? 4 : (ra < 8) ? 8 : 14));
m_video_timer->adjust(m_screen->time_until_pos((m_screen->height() > next) ? next : 0, 0));
}
diff --git a/src/mame/video/orion.cpp b/src/mame/video/orion.cpp
index eeb3a2e7a3a..b806f87b150 100644
--- a/src/mame/video/orion.cpp
+++ b/src/mame/video/orion.cpp
@@ -16,16 +16,15 @@
uint32_t orion_state::screen_update_orion128(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
uint8_t code1,code2,code3,code4,color,val;
- int y, x,b;
int orionproshift = (m_orion128_video_mode & 0x10) ? 1 : 0;
int part1addr = (3-((m_orion128_video_page & 3) | orionproshift)) * 0x4000;
int part2addr = part1addr + 0x10000;
int video_mode = m_orion128_video_mode & m_video_mode_mask;
uint8_t *ram = m_ram->pointer();
- for (x = 0; x < m_orion128_video_width; x++)
+ for (int x = 0; x < m_orion128_video_width; x++)
{
- for (y = 0; y < 256; y++)
+ for (int y = 0; y < 256; y++)
{
code1 = ram[part1addr + y + x*256];
code2 = ram[part2addr + y + x*256];
@@ -35,7 +34,7 @@ uint32_t orion_state::screen_update_orion128(screen_device &screen, bitmap_ind16
code2 = m_orionpro_pseudo_color;
}
color = 0;
- for (b = 7; b >= 0; b--)
+ for (int b = 7; b >= 0; b--)
{
switch(m_orion128_video_mode & m_video_mode_mask) {
case 0 : color = ((code1 >> b) & 0x01) ? 10 : 0; break;