diff --git a/source/emuInstance.hpp b/source/emuInstance.hpp index 028978e..8f62f37 100644 --- a/source/emuInstance.hpp +++ b/source/emuInstance.hpp @@ -64,38 +64,14 @@ class EmuInstance std::string moveString = "|..|........|"; #endif - if (move & 0b00010000) - moveString += 'U'; - else - moveString += '.'; - if (move & 0b00100000) - moveString += 'D'; - else - moveString += '.'; - if (move & 0b01000000) - moveString += 'L'; - else - moveString += '.'; - if (move & 0b10000000) - moveString += 'R'; - else - moveString += '.'; - if (move & 0b00001000) - moveString += 'S'; - else - moveString += '.'; - if (move & 0b00000100) - moveString += 's'; - else - moveString += '.'; - if (move & 0b00000010) - moveString += 'B'; - else - moveString += '.'; - if (move & 0b00000001) - moveString += 'A'; - else - moveString += '.'; + if (move & 0b00010000) moveString += 'U'; else moveString += '.'; + if (move & 0b00100000) moveString += 'D'; else moveString += '.'; + if (move & 0b01000000) moveString += 'L'; else moveString += '.'; + if (move & 0b10000000) moveString += 'R'; else moveString += '.'; + if (move & 0b00001000) moveString += 'S'; else moveString += '.'; + if (move & 0b00000100) moveString += 's'; else moveString += '.'; + if (move & 0b00000010) moveString += 'B'; else moveString += '.'; + if (move & 0b00000001) moveString += 'A'; else moveString += '.'; moveString += "|"; return moveString; @@ -108,8 +84,6 @@ class EmuInstance advanceStateImpl(moveStringToCode(move), 0); } - inline size_t getStateSize() const { return _stateSize; } - inline size_t getLiteStateSize() const { return _liteStateSize; } inline std::string getRomSHA1() const { return _romSHA1String; } inline hash_t getStateHash() const @@ -134,14 +108,14 @@ class EmuInstance std::string stateData; bool status = loadStringFromFile(stateData, stateFilePath); if (status == false) EXIT_WITH_ERROR("Could not find/read state file: %s\n", stateFilePath.c_str()); - deserializeState((uint8_t *)stateData.data()); + deserializeFullState((uint8_t *)stateData.data()); } inline void saveStateFile(const std::string &stateFilePath) const { std::string stateData; - stateData.resize(_stateSize); - serializeState((uint8_t *)stateData.data()); + stateData.resize(_fullStateSize); + serializeFullState((uint8_t *)stateData.data()); saveStringToFile(stateData, stateFilePath.c_str()); } @@ -159,10 +133,10 @@ class EmuInstance if (status == false) EXIT_WITH_ERROR("Could not process ROM file: %s\n", romFilePath.c_str()); // Detecting full state size - _stateSize = getStateSizeImpl(); + _fullStateSize = getFullStateSize(); // Detecting lite state size - _liteStateSize = getLiteStateSizeImpl(); + _liteStateSize = getLiteStateSize(); } // Virtual functions @@ -174,10 +148,12 @@ class EmuInstance virtual uint8_t *getHighMem() const = 0; virtual const uint8_t *getChrMem() const = 0; virtual size_t getChrMemSize() const = 0; - virtual void serializeState(uint8_t *state) const = 0; - virtual void deserializeState(const uint8_t *state) = 0; - virtual size_t getStateSizeImpl() const = 0; - virtual size_t getLiteStateSizeImpl() const { return getStateSizeImpl(); }; + virtual void serializeFullState(uint8_t *state) const = 0; + virtual void deserializeFullState(const uint8_t *state) = 0; + virtual void serializeLiteState(uint8_t *state) const = 0; + virtual void deserializeLiteState(const uint8_t *state) = 0; + virtual size_t getFullStateSize() const = 0; + virtual size_t getLiteStateSize() const = 0; virtual void doSoftReset() = 0; virtual void doHardReset() = 0; virtual std::string getCoreName() const = 0; @@ -190,7 +166,7 @@ class EmuInstance size_t _liteStateSize; // Storage for the full state size - size_t _stateSize; + size_t _fullStateSize; // Flag to determine whether to enable/disable rendering bool _doRendering = true; diff --git a/source/playbackInstance.hpp b/source/playbackInstance.hpp index 3f26f9b..db8ab38 100644 --- a/source/playbackInstance.hpp +++ b/source/playbackInstance.hpp @@ -29,13 +29,16 @@ struct stepData_t class PlaybackInstance { + static const uint16_t image_width = 256; + static const uint16_t image_height = 240; + public: void addStep(const std::string &input) { stepData_t step; step.input = input; - step.stateData = (uint8_t *)malloc(_emu->getStateSize()); - _emu->serializeState(step.stateData); + step.stateData = (uint8_t *)malloc(_emu->getFullStateSize()); + _emu->serializeFullState(step.stateData); step.hash = _emu->getStateHash(); // Adding the step into the sequence @@ -50,8 +53,8 @@ class PlaybackInstance // Loading Emulator instance HQN _hqnState.setEmulatorPointer(_emu->getInternalEmulatorPointer()); - static uint8_t video_buffer[emulator_t::image_width * emulator_t::image_height]; - _hqnState.m_emu->set_pixels(video_buffer, emulator_t::image_width + 8); + static uint8_t video_buffer[image_width * image_height]; + _hqnState.m_emu->set_pixels(video_buffer, image_width + 8); // Building sequence information for (const auto &input : sequence) @@ -166,7 +169,7 @@ class PlaybackInstance if (stepId > 0) { const auto stateData = getStateData(stepId - 1); - _emu->deserializeState(stateData); + _emu->deserializeFullState(stateData); _emu->advanceState(getStateInput(stepId - 1)); } diff --git a/source/player.cpp b/source/player.cpp index 6ddae77..66de329 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) auto p = PlaybackInstance(&e, sequence); // Getting state size - auto stateSize = e.getStateSize(); + auto stateSize = e.getFullStateSize(); // Flag to continue running playback bool continueRunning = true; diff --git a/source/quickNES/quickNESInstance.hpp b/source/quickNES/quickNESInstance.hpp index 46d5c30..1cb5b83 100644 --- a/source/quickNES/quickNESInstance.hpp +++ b/source/quickNES/quickNESInstance.hpp @@ -45,20 +45,34 @@ class QuickNESInstance : public EmuInstance const uint8_t *getChrMem() const override { return _nes->chr_mem(); }; size_t getChrMemSize() const override { return _nes->chr_size(); }; - void serializeState(uint8_t *state) const override + void serializeLiteState(uint8_t *state) const override { serializeFullState(state); } + void deserializeLiteState(const uint8_t *state) override { deserializeFullState(state); } + inline size_t getLiteStateSize() const override { return getFullStateSize(); } + + void serializeFullState(uint8_t *state) const override { - Mem_Writer w(state, _stateSize, 0); + Mem_Writer w(state, _fullStateSize, 0); Auto_File_Writer a(w); _nes->save_state(a); } - void deserializeState(const uint8_t *state) override + void deserializeFullState(const uint8_t *state) override { - Mem_File_Reader r(state, _stateSize); + Mem_File_Reader r(state, _fullStateSize); Auto_File_Reader a(r); _nes->load_state(a); } + inline size_t getFullStateSize() const override + { + uint8_t *data = (uint8_t *)malloc(_DUMMY_SIZE); + Mem_Writer w(data, _DUMMY_SIZE); + Auto_File_Writer a(w); + _nes->save_state(a); + free(data); + return w.size(); + } + void advanceStateImpl(const inputType controller1, const inputType controller2) override { if (_doRendering == true) _nes->emulate_frame(controller1, controller2); @@ -72,15 +86,6 @@ class QuickNESInstance : public EmuInstance void *getInternalEmulatorPointer() const override { return _nes; } private: - inline size_t getStateSizeImpl() const override - { - uint8_t *data = (uint8_t *)malloc(_DUMMY_SIZE); - Mem_Writer w(data, _DUMMY_SIZE); - Auto_File_Writer a(w); - _nes->save_state(a); - free(data); - return w.size(); - } // Video buffer uint8_t *video_buffer; diff --git a/source/quickerNES/apu/Blip_Buffer.cpp b/source/quickerNES/apu/blipBuffer.cpp similarity index 98% rename from source/quickerNES/apu/Blip_Buffer.cpp rename to source/quickerNES/apu/blipBuffer.cpp index 7252d7b..568db77 100644 --- a/source/quickerNES/apu/Blip_Buffer.cpp +++ b/source/quickerNES/apu/blipBuffer.cpp @@ -1,11 +1,11 @@ // Blip_Buffer 0.4.0. http://www.slack.net/~ant/ -#include "Blip_Buffer.hpp" -#include -#include -#include -#include +#include +#include +#include +#include +#include "blipBuffer.hpp" /* Copyright (C) 2003-2006 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser diff --git a/source/quickerNES/apu/Blip_Buffer.hpp b/source/quickerNES/apu/blipBuffer.hpp similarity index 100% rename from source/quickerNES/apu/Blip_Buffer.hpp rename to source/quickerNES/apu/blipBuffer.hpp diff --git a/source/quickerNES/apu/buffer.hpp b/source/quickerNES/apu/buffer.hpp index d368dd5..c55642a 100644 --- a/source/quickerNES/apu/buffer.hpp +++ b/source/quickerNES/apu/buffer.hpp @@ -3,8 +3,8 @@ // NES non-linear audio buffer // Emu 0.7.0 -#include "Multi_Buffer.hpp" #include +#include "multiBuffer.hpp" namespace quickerNES { diff --git a/source/quickerNES/apu/effectsBuffer.hpp b/source/quickerNES/apu/effectsBuffer.hpp index b5ae33c..6878c58 100644 --- a/source/quickerNES/apu/effectsBuffer.hpp +++ b/source/quickerNES/apu/effectsBuffer.hpp @@ -3,8 +3,8 @@ // Multi-channel effects buffer with panning, echo and reverb // Game_Music_Emu 0.3.0 -#include "Multi_Buffer.hpp" #include +#include "multiBuffer.hpp" namespace quickerNES { diff --git a/source/quickerNES/apu/fme7/apu.hpp b/source/quickerNES/apu/fme7/apu.hpp index 503b1d9..b7397ff 100644 --- a/source/quickerNES/apu/fme7/apu.hpp +++ b/source/quickerNES/apu/fme7/apu.hpp @@ -4,7 +4,7 @@ // Emu 0.7.0 #include -#include "apu/Blip_Buffer.hpp" +#include "apu/blipBuffer.hpp" namespace quickerNES { diff --git a/source/quickerNES/apu/Multi_Buffer.cpp b/source/quickerNES/apu/multiBuffer.cpp similarity index 99% rename from source/quickerNES/apu/Multi_Buffer.cpp rename to source/quickerNES/apu/multiBuffer.cpp index e9a2353..5583c94 100644 --- a/source/quickerNES/apu/Multi_Buffer.cpp +++ b/source/quickerNES/apu/multiBuffer.cpp @@ -1,8 +1,8 @@ // Blip_Buffer 0.4.0. http://www.slack.net/~ant/ -#include "Multi_Buffer.hpp" #include +#include "multiBuffer.hpp" /* Copyright (C) 2003-2006 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser diff --git a/source/quickerNES/apu/Multi_Buffer.hpp b/source/quickerNES/apu/multiBuffer.hpp similarity index 99% rename from source/quickerNES/apu/Multi_Buffer.hpp rename to source/quickerNES/apu/multiBuffer.hpp index 20a1ff3..461af0f 100644 --- a/source/quickerNES/apu/Multi_Buffer.hpp +++ b/source/quickerNES/apu/multiBuffer.hpp @@ -4,7 +4,7 @@ // Multi-channel sound buffer interface, and basic mono and stereo buffers // Blip_Buffer 0.4.0 -#include "Blip_Buffer.hpp" +#include "blipBuffer.hpp" namespace quickerNES { diff --git a/source/quickerNES/apu/namco/apu.cpp b/source/quickerNES/apu/namco/apu.cpp index b6064a4..5cc6831 100644 --- a/source/quickerNES/apu/namco/apu.cpp +++ b/source/quickerNES/apu/namco/apu.cpp @@ -2,7 +2,7 @@ // Snd_Emu 0.1.7. http://www.slack.net/~ant/ #include "apu/namco/apu.hpp" -#include "apu/Blip_Buffer.hpp" +#include "apu/blipBuffer.hpp" /* Copyright (C) 2003-2006 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser diff --git a/source/quickerNES/apu/oscs.hpp b/source/quickerNES/apu/oscs.hpp index 88e8b24..302f0dd 100644 --- a/source/quickerNES/apu/oscs.hpp +++ b/source/quickerNES/apu/oscs.hpp @@ -4,7 +4,7 @@ // Private oscillators used by Apu // Snd_Emu 0.1.7 -#include "Blip_Buffer.hpp" +#include "blipBuffer.hpp" namespace quickerNES { diff --git a/source/quickerNES/apu/vrc6/apu.hpp b/source/quickerNES/apu/vrc6/apu.hpp index 6e3dcec..e25e057 100644 --- a/source/quickerNES/apu/vrc6/apu.hpp +++ b/source/quickerNES/apu/vrc6/apu.hpp @@ -5,7 +5,7 @@ // Snd_Emu 0.1.7 #include -#include "apu/Blip_Buffer.hpp" +#include "apu/blipBuffer.hpp" #include "apu/apu.hpp" namespace quickerNES diff --git a/source/quickerNES/apu/vrc7/apu.hpp b/source/quickerNES/apu/vrc7/apu.hpp index c48949f..dae5e37 100644 --- a/source/quickerNES/apu/vrc7/apu.hpp +++ b/source/quickerNES/apu/vrc7/apu.hpp @@ -5,7 +5,7 @@ // Snd_Emu 0.1.7. Copyright (C) 2003-2005 Shay Green. GNU LGPL license. #include -#include "apu/Blip_Buffer.hpp" +#include "apu/blipBuffer.hpp" #include "apu/vrc7/emu2413_state.hpp" namespace quickerNES diff --git a/source/quickerNES/core.hpp b/source/quickerNES/core.hpp index f0f3b62..172be2b 100644 --- a/source/quickerNES/core.hpp +++ b/source/quickerNES/core.hpp @@ -129,93 +129,7 @@ class Core : private Cpu reset(true, true); } - size_t getLiteStateSize() const - { - size_t size = 0; - - size += sizeof(nes_state_t); - size += sizeof(registers_t); - size += sizeof(ppu_state_t); - size += sizeof(Apu::apu_state_t); - size += sizeof(joypad_state_t); - size += mapper->state_size; - size += low_ram_size; - size += Ppu::spr_ram_size; - size_t nametable_size = 0x800; - if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000; - size += nametable_size; - if (ppu.chr_is_writable) size += ppu.chr_size; - if (sram_present) size += impl->sram_size; - - return size; - } - - size_t getStateSize() const - { - size_t size = 0; - - size += sizeof(char[4]); // NESS Block - size += sizeof(uint32_t); // Block Size - - size += sizeof(char[4]); // TIME Block - size += sizeof(uint32_t); // Block Size - size += sizeof(nes_state_t); - - size += sizeof(char[4]); // CPUR Block - size += sizeof(uint32_t); // Block Size - size += sizeof(registers_t); - - size += sizeof(char[4]); // PPUR Block - size += sizeof(uint32_t); // Block Size - size += sizeof(ppu_state_t); - - size += sizeof(char[4]); // APUR Block - size += sizeof(uint32_t); // Block Size - size += sizeof(Apu::apu_state_t); - - size += sizeof(char[4]); // CTRL Block - size += sizeof(uint32_t); // Block Size - size += sizeof(joypad_state_t); - - size += sizeof(char[4]); // MAPR Block - size += sizeof(uint32_t); // Block Size - size += mapper->state_size; - - size += sizeof(char[4]); // LRAM Block - size += sizeof(uint32_t); // Block Size - size += low_ram_size; - - size += sizeof(char[4]); // SPRT Block - size += sizeof(uint32_t); // Block Size - size += Ppu::spr_ram_size; - - size += sizeof(char[4]); // NTAB Block - size += sizeof(uint32_t); // Block Size - size_t nametable_size = 0x800; - if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000; - size += nametable_size; - - if (ppu.chr_is_writable) - { - size += sizeof(char[4]); // CHRR Block - size += sizeof(uint32_t); // Block Size - size += ppu.chr_size; - } - - if (sram_present) - { - size += sizeof(char[4]); // SRAM Block - size += sizeof(uint32_t); // Block Size - size += impl->sram_size; - } - - size += sizeof(char[4]); // gend Block - size += sizeof(uint32_t); // Block Size - - return size; - } - - size_t serializeState(uint8_t *buffer) const + size_t serializeFullState(uint8_t *buffer) const { size_t pos = 0; std::string headerCode; @@ -225,9 +139,9 @@ class Core : private Cpu headerCode = "NESS"; // NESS Block blockSize = 0xFFFFFFFF; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; headerCode = "TIME"; // TIME Block @@ -235,11 +149,11 @@ class Core : private Cpu state.timestamp *= 5; blockSize = sizeof(nes_state_t); dataSource = (void *)&state; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "CPUR"; // CPUR Block @@ -253,72 +167,72 @@ class Core : private Cpu s.p = r.status; blockSize = sizeof(cpu_state_t); dataSource = (void *)&s; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "PPUR"; // PPUR Block blockSize = sizeof(ppu_state_t); dataSource = (void *)&ppu; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "APUR"; // APUR Block Apu::apu_state_t apuState; impl->apu.save_state(&apuState); blockSize = sizeof(Apu::apu_state_t); - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], &apuState, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], &apuState, blockSize); pos += blockSize; headerCode = "CTRL"; // CTRL Block blockSize = sizeof(joypad_state_t); dataSource = (void *)&joypad; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "MAPR"; // MAPR Block blockSize = mapper->state_size; dataSource = (void *)mapper->state; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "LRAM"; // LRAM Block blockSize = low_ram_size; dataSource = (void *)low_mem; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "SPRT"; // SPRT Block blockSize = Ppu::spr_ram_size; dataSource = (void *)ppu.spr_ram; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; headerCode = "NTAB"; // NTAB Block @@ -326,11 +240,11 @@ class Core : private Cpu if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000; blockSize = nametable_size; dataSource = (void *)ppu.impl->nt_ram; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; if (ppu.chr_is_writable) @@ -338,11 +252,11 @@ class Core : private Cpu headerCode = "CHRR"; // CHRR Block blockSize = ppu.chr_size; dataSource = (void *)ppu.impl->chr_ram; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; } @@ -351,25 +265,301 @@ class Core : private Cpu headerCode = "SRAM"; // SRAM Block blockSize = impl->sram_size; dataSource = (void *)impl->sram; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; - memcpy(&buffer[pos], dataSource, blockSize); + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; } headerCode = "gend"; // gend Block blockSize = 0; - memcpy(&buffer[pos], headerCode.data(), headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; - memcpy(&buffer[pos], &blockSize, headerSize); + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; return pos; // Bytes written } - size_t deserializeState(const uint8_t *buffer) + size_t deserializeFullState(const uint8_t *buffer) + { + disable_rendering(); + error_count = 0; + ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over + + size_t pos = 0; + const uint32_t headerSize = sizeof(char) * 4; + uint32_t blockSize = 0; + + // NESS Block + pos += headerSize; + pos += headerSize; + + // TIME Block + nes_state_t nesState; + pos += headerSize; + pos += headerSize; + blockSize = sizeof(nes_state_t); + memcpy(&nesState, &buffer[pos], blockSize); + pos += blockSize; + nes = nesState; + nes.timestamp /= 5; + + // CPUR Block + cpu_state_t s; + blockSize = sizeof(cpu_state_t); + pos += headerSize; + pos += headerSize; + memcpy((void *)&s, &buffer[pos], blockSize); + pos += blockSize; + r.pc = s.pc; + r.sp = s.s; + r.a = s.a; + r.x = s.x; + r.y = s.y; + r.status = s.p; + + // PPUR Block + blockSize = sizeof(ppu_state_t); + pos += headerSize; + pos += headerSize; + memcpy((void *)&ppu, &buffer[pos], blockSize); + pos += blockSize; + + // APUR Block + Apu::apu_state_t apuState; + blockSize = sizeof(Apu::apu_state_t); + pos += headerSize; + pos += headerSize; + memcpy(&apuState, &buffer[pos], blockSize); + pos += blockSize; + impl->apu.load_state(apuState); + impl->apu.end_frame(-(int)nes.timestamp / ppu_overclock); + + // CTRL Block + blockSize = sizeof(joypad_state_t); + pos += headerSize; + pos += headerSize; + memcpy((void *)&joypad, &buffer[pos], blockSize); + pos += blockSize; + + // MAPR Block + mapper->default_reset_state(); + blockSize = mapper->state_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)mapper->state, &buffer[pos], blockSize); + pos += blockSize; + mapper->apply_mapping(); + + // LRAM Block + blockSize = low_ram_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)low_mem, &buffer[pos], blockSize); + pos += blockSize; + + // SPRT Block + blockSize = Ppu::spr_ram_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)ppu.spr_ram, &buffer[pos], blockSize); + pos += blockSize; + + // NTAB Block + size_t nametable_size = 0x800; + if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000; + blockSize = nametable_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)ppu.impl->nt_ram, &buffer[pos], blockSize); + pos += blockSize; + + if (ppu.chr_is_writable) + { + // CHRR Block + blockSize = ppu.chr_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)ppu.impl->chr_ram, &buffer[pos], blockSize); + pos += blockSize; + } + + if (sram_present) + { + // SRAM Block + blockSize = impl->sram_size; + pos += headerSize; + pos += headerSize; + memcpy((void *)impl->sram, &buffer[pos], blockSize); + pos += blockSize; + enable_sram(true); + } + + // headerCode = "gend"; // gend Block + pos += headerSize; + pos += headerSize; + + return pos; // Bytes read + } + +size_t serializeLiteState(uint8_t *buffer) const + { + size_t pos = 0; + std::string headerCode; + const uint32_t headerSize = sizeof(char) * 4; + uint32_t blockSize = 0; + void *dataSource; + + headerCode = "NESS"; // NESS Block + blockSize = 0xFFFFFFFF; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + + headerCode = "TIME"; // TIME Block + nes_state_t state = nes; + state.timestamp *= 5; + blockSize = sizeof(nes_state_t); + dataSource = (void *)&state; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "CPUR"; // CPUR Block + cpu_state_t s; + memset(&s, 0, sizeof s); + s.pc = r.pc; + s.s = r.sp; + s.a = r.a; + s.x = r.x; + s.y = r.y; + s.p = r.status; + blockSize = sizeof(cpu_state_t); + dataSource = (void *)&s; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "PPUR"; // PPUR Block + blockSize = sizeof(ppu_state_t); + dataSource = (void *)&ppu; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "APUR"; // APUR Block + Apu::apu_state_t apuState; + impl->apu.save_state(&apuState); + blockSize = sizeof(Apu::apu_state_t); + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &apuState, blockSize); + pos += blockSize; + + headerCode = "CTRL"; // CTRL Block + blockSize = sizeof(joypad_state_t); + dataSource = (void *)&joypad; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "MAPR"; // MAPR Block + blockSize = mapper->state_size; + dataSource = (void *)mapper->state; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "LRAM"; // LRAM Block + blockSize = low_ram_size; + dataSource = (void *)low_mem; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "SPRT"; // SPRT Block + blockSize = Ppu::spr_ram_size; + dataSource = (void *)ppu.spr_ram; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + headerCode = "NTAB"; // NTAB Block + size_t nametable_size = 0x800; + if (ppu.nt_banks[3] >= &ppu.impl->nt_ram[0xC00]) nametable_size = 0x1000; + blockSize = nametable_size; + dataSource = (void *)ppu.impl->nt_ram; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + + if (ppu.chr_is_writable) + { + headerCode = "CHRR"; // CHRR Block + blockSize = ppu.chr_size; + dataSource = (void *)ppu.impl->chr_ram; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + } + + if (sram_present) + { + headerCode = "SRAM"; // SRAM Block + blockSize = impl->sram_size; + dataSource = (void *)impl->sram; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], dataSource, blockSize); + pos += blockSize; + } + + headerCode = "gend"; // gend Block + blockSize = 0; + if (buffer != nullptr) memcpy(&buffer[pos], headerCode.data(), headerSize); + pos += headerSize; + if (buffer != nullptr) memcpy(&buffer[pos], &blockSize, headerSize); + pos += headerSize; + + return pos; // Bytes written + } + + size_t deserializeLiteState(const uint8_t *buffer) { disable_rendering(); error_count = 0; diff --git a/source/quickerNES/emu.hpp b/source/quickerNES/emu.hpp index 7fb74d4..9183eb2 100644 --- a/source/quickerNES/emu.hpp +++ b/source/quickerNES/emu.hpp @@ -6,7 +6,7 @@ #include "cart.hpp" #include "core.hpp" -#include "apu/Multi_Buffer.hpp" +#include "apu/multiBuffer.hpp" namespace quickerNES { @@ -44,8 +44,15 @@ class Emu const uint8_t *getHostPixels() const { return emu.ppu.host_pixels; } - size_t getLiteStateSize() const { return emu.getLiteStateSize(); } - size_t getStateSize() const { return emu.getStateSize(); } +// Save emulator state variants + size_t serializeFullState(uint8_t *buffer) const { return emu.serializeFullState(buffer); } + size_t serializeLiteState(uint8_t *buffer) const { return emu.serializeLiteState(buffer); } + + size_t deserializeFullState(const uint8_t *buffer) { return emu.deserializeFullState(buffer); } + size_t deserializeLiteState(const uint8_t *buffer) { return emu.deserializeLiteState(buffer); } + + size_t getLiteStateSize() const { return emu.serializeLiteState(nullptr); } + size_t getFullStateSize() const { return emu.serializeFullState(nullptr); } // Basic emulation @@ -141,10 +148,6 @@ class Emu // File save/load - // Save emulator state - size_t serializeState(uint8_t *buffer) const { return emu.serializeState(buffer); } - size_t deserializeState(const uint8_t *buffer) { return emu.deserializeState(buffer); } - // True if current cartridge claims it uses battery-backed memory bool has_battery_ram() const { return cart()->has_battery_ram(); } diff --git a/source/quickerNES/meson.build b/source/quickerNES/meson.build index 8e44de1..bbda328 100644 --- a/source/quickerNES/meson.build +++ b/source/quickerNES/meson.build @@ -4,10 +4,10 @@ quickerNESAPUSrc = [ 'apu/apu.cpp', 'apu/oscs.cpp', 'apu/buffer.cpp', - 'apu/Blip_Buffer.cpp', + 'apu/blipBuffer.cpp', 'apu/NESEffectsBuffer.cpp', 'apu/effectsBuffer.cpp', - 'apu/Multi_Buffer.cpp', + 'apu/multiBuffer.cpp', 'apu/namco/apu.cpp', 'apu/vrc6/apu.cpp', 'apu/vrc7/emu2413.cpp', diff --git a/source/quickerNES/quickerNESInstance.hpp b/source/quickerNES/quickerNESInstance.hpp index e395ad1..a7ec138 100644 --- a/source/quickerNES/quickerNESInstance.hpp +++ b/source/quickerNES/quickerNESInstance.hpp @@ -36,15 +36,14 @@ class QuickerNESInstance : public EmuInstance const uint8_t *getChrMem() const override { return _nes->chr_mem(); }; size_t getChrMemSize() const override { return _nes->chr_size(); }; - void serializeState(uint8_t *state) const override - { - _nes->serializeState(state); - } + void serializeFullState(uint8_t *state) const override { _nes->serializeFullState(state); } + void deserializeFullState(const uint8_t *state) override { _nes->deserializeFullState(state); } - void deserializeState(const uint8_t *state) override - { - _nes->deserializeState(state); - } + void serializeLiteState(uint8_t *state) const override { _nes->serializeLiteState(state); } + void deserializeLiteState(const uint8_t *state) override { _nes->deserializeLiteState(state); } + + size_t getFullStateSize() const override { return _nes->getFullStateSize(); } + size_t getLiteStateSize() const override { return _nes->getLiteStateSize(); } void advanceStateImpl(const inputType controller1, const inputType controller2) override { @@ -58,17 +57,6 @@ class QuickerNESInstance : public EmuInstance void *getInternalEmulatorPointer() const override { return _nes; } - private: - inline size_t getStateSizeImpl() const override - { - return _nes->getStateSize(); - } - - inline size_t getLiteStateSizeImpl() const override - { - return _nes->getLiteStateSize(); - } - // Video buffer uint8_t *video_buffer; diff --git a/source/tester.cpp b/source/tester.cpp index b0c31dc..b8380df 100644 --- a/source/tester.cpp +++ b/source/tester.cpp @@ -76,14 +76,14 @@ int main(int argc, char *argv[]) if (scriptJson["Expected ROM SHA1"].is_string() == false) EXIT_WITH_ERROR("Script file 'Expected ROM SHA1' entry is not a string\n"); std::string expectedROMSHA1 = scriptJson["Expected ROM SHA1"].get(); -// Creating emulator instance -#ifdef _USE_QUICKNES + // Creating emulator instance + #ifdef _USE_QUICKNES auto e = QuickNESInstance(); -#endif + #endif -#ifdef _USE_QUICKERNES + #ifdef _USE_QUICKERNES auto e = quickerNES::QuickerNESInstance(); -#endif + #endif // Loading ROM File e.loadROMFile(romFilePath); @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) auto initialHash = e.getStateHash(); // Getting full state size - const auto stateSize = e.getStateSize(); + const auto fullStateSize = e.getFullStateSize(); // Getting lite state size const auto liteStateSize = e.getLiteStateSize(); @@ -132,15 +132,15 @@ int main(int argc, char *argv[]) printf("[] Sequence File: '%s'\n", sequenceFilePath.c_str()); printf("[] Sequence Length: %lu\n", sequenceLength); printf("[] Initial State Hash: 0x%lX%lX\n", initialHash.first, initialHash.second); - printf("[] Full State Size: %lu bytes\n", stateSize); + printf("[] Full State Size: %lu bytes\n", fullStateSize); printf("[] Lite State Size: %lu bytes\n", liteStateSize); printf("[] ********** Running Test **********\n"); fflush(stdout); // Serializing initial state - uint8_t *currentState = (uint8_t *)malloc(stateSize); - e.serializeState(currentState); + uint8_t *currentState = (uint8_t *)malloc(liteStateSize); + e.serializeLiteState(currentState); // Check whether to perform each action bool doPreAdvance = cycleType == "Full"; @@ -152,9 +152,9 @@ int main(int argc, char *argv[]) for (const std::string &input : sequence) { if (doPreAdvance == true) e.advanceState(input); - if (doDeserialize == true) e.deserializeState(currentState); + if (doDeserialize == true) e.deserializeLiteState(currentState); e.advanceState(input); - if (doSerialize == true) e.serializeState(currentState); + if (doSerialize == true) e.serializeLiteState(currentState); } auto tf = std::chrono::high_resolution_clock::now();