From 4530713b01c28cd1933cc71e67af1bf02ca1db0e Mon Sep 17 00:00:00 2001 From: Sergio Martin Date: Thu, 18 Jan 2024 19:56:30 +0100 Subject: [PATCH] Created new functions for serialization and deserialization --- README.md | 17 +- source/emuInstance.hpp | 17 +- source/quickerNES/Nes_Core.h | 384 ++++++++++++++++++++--- source/quickerNES/Nes_Emu.h | 5 +- source/quickerNES/Nes_Mapper.h | 15 +- source/quickerNES/Nes_Ppu_Impl.cpp | 1 + source/quickerNES/Nes_Ppu_Impl.h | 15 +- source/quickerNES/Nes_State.cpp | 2 +- source/quickerNES/quickerNESInstance.hpp | 24 +- source/tester.cpp | 8 +- 10 files changed, 404 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 93399c2..1e10e56 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,33 @@ quickerNES -============ +----------- -quickerNES is an attempt to modernizing and improving the performance of quickNES, the fastest NES emulator in the interwebs (as far as I know). The goals for this project are, in order of importance: +quickerNES is an attempt to modernizing and improving the performance of [quickNES](https://github.com/kode54/QuickNES). The goals for this project are, in order of importance: -- Improve overall emulation performance even more +- Improve overall emulation performance for modern (x86) CPUs - Modernize the code base with best programming practices, including CI tests, benchmarks, and coverage analysis - Add support for more mappers, controllers, and features supported by other emulators - Improve accuracy, if possible -The main aim is to improve the performance of skip (non-rendering, no-audio) frame advances for brute force botting. (See: [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus)). However, if this work might help with homebrew emulation and other people having more fun, then much better! +The main aim is to improve the performance of headless re-recording for TASing and botting (See: [JaffarPlus](https://github.com/SergioMartin86/jaffarPlus)) purposes. However, if this work can help regular play emulation, then much better. Changes -========= +-------- - Optimizations made in the CPU emulation core, including: + Forced alignment at the start of a page to prevent crossing cache line boundaries - + Simplifying instruction decode + + Simplifying the 6502 CPU instruction fetching and decoding - Minimize compiled code size to reduce pressure on L1i cache - Reduce heap allocations +- General code reorganization (make it header only to help compiler optimizations) Credits -========= +--------- - quickNES was originally by Shay Green (a.k.a. [Blaarg](http://www.slack.net/~ant/)) under the GNU GPLv2 license. The source code is still located [here](https://github.com/kode54/QuickNES) - The code was later improved and maintained by Christopher Snowhill (a.k.a. [kode54](https://kode54.net/)) - I could trace further contributions (e.g., new mappers) by retrowertz, CaH4e3, some adaptations from the [FCEUX emulator](https://github.com/TASEmulators/fceux) (see mapper021) - The latest version of the code is maintained by Libretro's community [here](https://github.com/libretro/QuickNES_Core) -- For the interactive player, this project uses a modified version of [HeadlessQuickNES (HQN)](https://github.com/Bindernews/HeadlessQuickNes) by Drew (Binder News) +- For the interactive player, this project drew some code from [HeadlessQuickNES (HQN)](https://github.com/Bindernews/HeadlessQuickNes) by Drew (Binder News) - We use some of the [NES test rom set](https://github.com/christopherpow/nes-test-roms) made by multiple authors and gathered by Christopher Pow et al. - We also use some movies from the [TASVideos](tasvideos.org) website for testing. These movies are copied into this repository with authorization under the Creative Commons Attribution 2.0 license. diff --git a/source/emuInstance.hpp b/source/emuInstance.hpp index 4da378b..28b4efd 100644 --- a/source/emuInstance.hpp +++ b/source/emuInstance.hpp @@ -86,15 +86,13 @@ class EmuInstance } 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 { MetroHash128 hash; - uint8_t stateData[_stateSize]; - serializeState(stateData); - hash.Update(getLowMem(), _LOW_MEM_SIZE); hash.Update(getHighMem(), _HIGH_MEM_SIZE); hash.Update(getNametableMem(), _NAMETABLES_MEM_SIZE); @@ -137,8 +135,11 @@ inline void loadROMFile(const std::string& romFilePath) status = loadROMFileImpl(_romData); if (status == false) EXIT_WITH_ERROR("Could not process ROM file: %s\n", romFilePath.c_str()); - // Detecting state size + // Detecting full state size _stateSize = getStateSizeImpl(); + + // Detecting lite state size + _liteStateSize = getLiteStateSizeImpl(); } // Virtual functions @@ -153,16 +154,20 @@ inline void loadROMFile(const std::string& romFilePath) 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 doSoftReset() = 0; virtual void doHardReset() = 0; virtual std::string getCoreName() const = 0; virtual void* getInternalEmulatorPointer() const = 0; - + protected: EmuInstance() = default; - // Storage for the state + // Storage for the light state size + size_t _liteStateSize; + + // Storage for the full state size size_t _stateSize; // Flag to determine whether to enable/disable rendering diff --git a/source/quickerNES/Nes_Core.h b/source/quickerNES/Nes_Core.h index 775304a..3370797 100644 --- a/source/quickerNES/Nes_Core.h +++ b/source/quickerNES/Nes_Core.h @@ -16,13 +16,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Nes_Emu 0.7.0 +#include +#include #include "blargg_common.h" #include "Nes_Apu.h" #include "Nes_Cpu.h" #include "Nes_Ppu.h" #include "Nes_Mapper.h" #include "Nes_State.h" -#include /* New mapping distribution by Sergio Martin (eien86) @@ -216,12 +217,321 @@ public: return 0; } - size_t getLightweightStateSize() + size_t getLiteStateSize() const { size_t size = 0; + + size += sizeof(nes_state_t); + size += sizeof(registers_t); + size += sizeof(ppu_state_t); + size += sizeof(Nes_Apu::apu_state_t); + size += sizeof(joypad_state_t); + size += mapper->state_size; + size += low_ram_size; + size += Nes_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(Nes_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 += Nes_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 pos = 0; + std::string headerCode; + const uint32_t headerSize = sizeof(char) * 4; + uint32_t blockSize = 0; + void* dataSource; + + headerCode = "NESS"; // NESS Block + blockSize = 0xFFFFFFFF; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + 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; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; + + headerCode = "APUR"; // APUR Block + Nes_Apu::apu_state_t apuState; + impl->apu.save_state(&apuState); + blockSize = sizeof(Nes_Apu::apu_state_t); + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; + + headerCode = "SPRT"; // SPRT Block + blockSize = Nes_Ppu::spr_ram_size; + dataSource = (void*) ppu.spr_ram; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + 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; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; + } + + if ( sram_present ) + { + headerCode = "SRAM"; // SRAM Block + blockSize = impl->sram_size; + dataSource = (void*) impl->sram; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + memcpy(&buffer[pos], dataSource, blockSize); pos += blockSize; + } + + headerCode = "gend"; // gend Block + blockSize = 0; + memcpy(&buffer[pos], headerCode.data(), headerSize); pos += headerSize; + memcpy(&buffer[pos], &blockSize, headerSize); pos += headerSize; + + return pos; // Bytes written + } + + size_t deserializeState(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 + Nes_Apu::apu_state_t apuState; + blockSize = sizeof(Nes_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 = Nes_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 + } + void reset( bool full_reset, bool erase_battery_ram ) { if ( full_reset ) @@ -347,50 +657,50 @@ public: void load_state( Nes_State_ const& in ) { - disable_rendering(); - error_count = 0; + // disable_rendering(); + // error_count = 0; - if ( in.nes_valid ) - nes = in.nes; + // if ( in.nes_valid ) + // nes = in.nes; - // always use frame count - ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over - nes.frame_count = in.nes.frame_count; - if ( (frame_count_t) nes.frame_count == invalid_frame_count ) - nes.frame_count = 0; + // // always use frame count + // ppu.burst_phase = 0; // avoids shimmer when seeking to same time over and over + // nes.frame_count = in.nes.frame_count; + // if ( (frame_count_t) nes.frame_count == invalid_frame_count ) + // nes.frame_count = 0; - if ( in.cpu_valid ) - cpu::r = *in.cpu; + // if ( in.cpu_valid ) + // cpu::r = *in.cpu; - if ( in.joypad_valid ) - joypad = *in.joypad; + // if ( in.joypad_valid ) + // joypad = *in.joypad; - if ( in.apu_valid ) - { - impl->apu.load_state( *in.apu ); - // prevent apu from running extra at beginning of frame - impl->apu.end_frame( -(int) nes.timestamp / ppu_overclock ); - } - else - { - impl->apu.reset(); - } + // if ( in.apu_valid ) + // { + // impl->apu.load_state( *in.apu ); + // // prevent apu from running extra at beginning of frame + // impl->apu.end_frame( -(int) nes.timestamp / ppu_overclock ); + // } + // else + // { + // impl->apu.reset(); + // } - ppu.load_state( in ); + // ppu.load_state( in ); - if ( in.ram_valid ) - memcpy( cpu::low_mem, in.ram, in.ram_size ); + // if ( in.ram_valid ) + // memcpy( cpu::low_mem, in.ram, in.ram_size ); - sram_present = false; - if ( in.sram_size ) - { - sram_present = true; - memcpy( impl->sram, in.sram, min( (int) in.sram_size, (int) sizeof impl->sram ) ); - enable_sram( true ); // mapper can override (read-only, unmapped, etc.) - } + // sram_present = false; + // if ( in.sram_size ) + // { + // sram_present = true; + // // memcpy( impl->sram, in.sram, min( (int) in.sram_size, (int) sizeof impl->sram ) ); + // enable_sram( true ); // mapper can override (read-only, unmapped, etc.) + // } - if ( in.mapper_valid ) // restore last since it might reconfigure things - mapper->load_state( *in.mapper ); + // if ( in.mapper_valid ) // restore last since it might reconfigure things + // mapper->load_state( *in.mapper ); } void irq_changed() diff --git a/source/quickerNES/Nes_Emu.h b/source/quickerNES/Nes_Emu.h index 870345e..cb3740f 100644 --- a/source/quickerNES/Nes_Emu.h +++ b/source/quickerNES/Nes_Emu.h @@ -42,7 +42,8 @@ public: const uint8_t* getHostPixels () const { return emu.ppu.host_pixels; } - size_t getLightweightStateSize() { return emu.getLightweightStateSize(); } + size_t getLiteStateSize() const { return emu.getLiteStateSize(); } + size_t getStateSize() const { return emu.getStateSize(); } // Basic emulation @@ -140,6 +141,8 @@ public: // Save emulator state void save_state( Nes_State* s ) const { emu.save_state( s ); } const char * save_state( Auto_File_Writer ) const; + size_t serializeState (uint8_t* buffer) const { return emu.serializeState(buffer); } + size_t deserializeState (const uint8_t* buffer) { return emu.deserializeState(buffer); } // Load state into emulator void load_state( Nes_State const& ); diff --git a/source/quickerNES/Nes_Mapper.h b/source/quickerNES/Nes_Mapper.h index 9739ea0..a9b58a1 100644 --- a/source/quickerNES/Nes_Mapper.h +++ b/source/quickerNES/Nes_Mapper.h @@ -68,6 +68,9 @@ public: // $2006 and $2007 accesses (but not due to PPU scanline rendering). virtual void a12_clocked(); + void* state; + unsigned state_size; + protected: // Services provided for derived mapper classes Nes_Mapper(); @@ -147,9 +150,7 @@ protected: // apply_mapping(). virtual void read_state( mapper_state_t const& ); - // Apply current mapping state to hardware. Called after reading mapper state - // from a snapshot. - virtual void apply_mapping() = 0; + // Called by default reset() before apply_mapping() is called. virtual void reset_state() { } @@ -161,11 +162,9 @@ protected: Nes_Cart const* cart_; Nes_Core* emu_; -private: - - void* state; - unsigned state_size; - + // Apply current mapping state to hardware. Called after reading mapper state + // from a snapshot. + virtual void apply_mapping() = 0; void default_reset_state(); }; diff --git a/source/quickerNES/Nes_Ppu_Impl.cpp b/source/quickerNES/Nes_Ppu_Impl.cpp index a356294..7288a11 100644 --- a/source/quickerNES/Nes_Ppu_Impl.cpp +++ b/source/quickerNES/Nes_Ppu_Impl.cpp @@ -3,6 +3,7 @@ #include "Nes_Ppu_Impl.h" +#include #include #include "blargg_endian.h" #include "Nes_State.h" diff --git a/source/quickerNES/Nes_Ppu_Impl.h b/source/quickerNES/Nes_Ppu_Impl.h index cefb34a..756a5f3 100644 --- a/source/quickerNES/Nes_Ppu_Impl.h +++ b/source/quickerNES/Nes_Ppu_Impl.h @@ -30,6 +30,10 @@ public: static const uint16_t buffer_height = image_height; enum { spr_ram_size = 0x100 }; + uint8_t* nt_banks [4]; + bool chr_is_writable; + long chr_size; + int write_2007( int ); // Host palette @@ -67,9 +71,10 @@ public: uint8_t* getSpriteRAM () { return spr_ram; } uint16_t getSpriteRAMSize () { return spr_ram_size; } - -protected: uint8_t spr_ram [spr_ram_size]; + void all_tiles_modified(); +protected: + void begin_frame(); void run_hblank( int ); int sprite_height() const { return (w2000 >> 2 & 8) + 8; } @@ -90,7 +95,6 @@ protected: //friend class Nes_Ppu_Rendering; private: void capture_palette(); bool any_tiles_modified; - bool chr_is_writable; void update_tiles( int first_tile ); typedef uint32_t cache_t; @@ -128,7 +132,7 @@ private: return ret; } - uint8_t* nt_banks [4]; + bool mmc24_enabled; uint8_t mmc24_latched [2]; @@ -136,7 +140,6 @@ private: // CHR data uint8_t const* chr_data; // points to chr ram when there is no read-only data uint8_t* chr_ram; // always points to impl->chr_ram; makes write_2007() faster - long chr_size; uint8_t const* map_chr( int addr ) { return &chr_data [map_chr_addr( addr )]; } // CHR cache @@ -147,7 +150,7 @@ private: uint8_t modified_tiles [chr_tile_count / 8]; uint32_t align_; }; - void all_tiles_modified(); + void update_tile( int index ); }; diff --git a/source/quickerNES/Nes_State.cpp b/source/quickerNES/Nes_State.cpp index 079c413..d991c72 100644 --- a/source/quickerNES/Nes_State.cpp +++ b/source/quickerNES/Nes_State.cpp @@ -113,7 +113,7 @@ const char * Nes_State_::write_blocks( Nes_File_Writer& out ) const s.p = cpu->status; RETURN_ERR( write_nes_state( out, s ) ); } - + if ( ppu_valid ) { ppu_state_t s = *ppu; diff --git a/source/quickerNES/quickerNESInstance.hpp b/source/quickerNES/quickerNESInstance.hpp index 98bf6bb..0b43228 100644 --- a/source/quickerNES/quickerNESInstance.hpp +++ b/source/quickerNES/quickerNESInstance.hpp @@ -26,9 +26,6 @@ class QuickerNESInstance : public EmuInstance { // Loading rom data auto result = _nes->load_ines((uint8_t*)romData.data()); - - // printf("Lightweight size: %lu vs Full Size: %lu\n", _nes->getLightweightStateSize(), getStateSizeImpl()); - // exit(0); return result == 0; } @@ -40,16 +37,12 @@ class QuickerNESInstance : public EmuInstance void serializeState(uint8_t* state) const { - Mem_Writer w(state, _stateSize, 0); - Auto_File_Writer a(w); - _nes->save_state(a); + _nes->serializeState(state); } void deserializeState(const uint8_t* state) { - Mem_File_Reader r(state, _stateSize); - Auto_File_Reader a(r); - _nes->load_state(a); + _nes->deserializeState(state); } void advanceStateImpl(const inputType controller1, const inputType controller2) override @@ -66,13 +59,14 @@ class QuickerNESInstance : public EmuInstance private: - inline size_t getStateSizeImpl() const + inline size_t getStateSizeImpl() const override { - // Using dry writer to just obtain the state size - Dry_Writer w; - Auto_File_Writer a(w); - _nes->save_state(a); - return w.size(); + return _nes->getStateSize(); + } + + inline size_t getLiteStateSizeImpl() const override + { + return _nes->getLiteStateSize(); } // Video buffer diff --git a/source/tester.cpp b/source/tester.cpp index 6a57e5f..4237ba4 100644 --- a/source/tester.cpp +++ b/source/tester.cpp @@ -92,9 +92,12 @@ int main(int argc, char *argv[]) // Getting initial hash auto initialHash = e.getStateHash(); - // Getting state size + // Getting full state size const auto stateSize = e.getStateSize(); + // Getting lite state size + const auto liteStateSize = e.getLiteStateSize(); + // Getting actual ROM SHA1 auto romSHA1 = e.getRomSHA1(); @@ -124,7 +127,8 @@ 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("[] State Size: %lu bytes\n", stateSize); + printf("[] Full State Size: %lu bytes\n", stateSize); + printf("[] Lite State Size: %lu bytes\n", liteStateSize); printf("[] ********** Running Test **********\n"); fflush(stdout);