diff options
author | 2019-12-09 00:35:38 +1100 | |
---|---|---|
committer | 2019-12-09 00:35:38 +1100 | |
commit | e6b4cdb3527bf7a799eb6b6b9f7df57aea8971ec (patch) | |
tree | 49f373544238a8e2458cc1de05039468a066a016 | |
parent | d3a70dc3460ef0b9c97fe16efb70db83bf012848 (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.cpp | 2 | ||||
-rw-r--r-- | src/devices/sound/qsoundhle.cpp | 92 | ||||
-rw-r--r-- | src/emu/debug/debugcmd.cpp | 8 | ||||
-rw-r--r-- | src/emu/debug/dvmemory.cpp | 30 | ||||
-rw-r--r-- | src/emu/debug/dvmemory.h | 16 | ||||
-rw-r--r-- | src/emu/device.h | 18 | ||||
-rw-r--r-- | src/emu/save.cpp | 93 | ||||
-rw-r--r-- | src/emu/save.h | 136 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 64 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.h | 3 | ||||
-rw-r--r-- | src/mame/includes/orion.h | 1 | ||||
-rw-r--r-- | src/mame/machine/osborne1.cpp | 2 | ||||
-rw-r--r-- | src/mame/video/orion.cpp | 7 |
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 ®ion); - 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; |